pmix-6.1.1~rc2/0000775000175000017500000000000015203537001013461 5ustar alastairalastairpmix-6.1.1~rc2/VERSION0000664000175000017500000001152715203536752014553 0ustar alastairalastair# Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2008-2011 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2011 NVIDIA Corporation. All rights reserved. # Copyright (c) 2013 Mellanox Technologies, Inc. # All rights reserved. # Copyright (c) 2014-2016 Intel, Inc. All rights reserved. # Copyright (c) 2022 IBM Corporation. All rights reserved. # This is the VERSION file for PMIx, describing the precise # version of PMIx in this distribution. The various components of # the version number below are combined to form a single version # number string. # major, minor, and release are generally combined in the form # ... major=6 minor=1 release=1 # greek is used for alpha or beta release tags. If it is non-empty, # it will be appended to the version number. It does not have to be # numeric. Common examples include a1 (alpha release 1), b1 or (beta release 1). # The only requirement is that it must be entirely printable ASCII # characters and have no white space. greek=rc2 # PMIx required dependency versions. # List in x.y.z format. hwloc_min_version=2.1.0 event_min_version=2.0.21 automake_min_version=1.13.4 autoconf_min_version=2.69.0 libtool_min_version=2.4.2 flex_min_version=2.5.4 python_min_version=3.6 # PMIx Standard Compliance Level # The major and minor numbers indicate the version # of the official PMIx Standard that is supported # by this release. The extension number tracks how # far beyond that Standard this implementation has # gone. It is incremented whenever a release ADDS # something beyond the Standard. An extension of "1" # therefore indicates that something beyond the # indicated Standard level has been added. A # subsequent release that did not further add # attributes or APIs to the implementation would # retain the same extension value - if it did # include further extensions, then the extension # value would increment to "2" regardless of the # magnitude of the changes. std_major=4 std_minor=1 std_extension=2 # PMIx Standard ABI Compliance Level(s) # The major and minor numbers (MAJOR.MINOR) indicate the version # of the official PMIx Standard ABI that is supported # by this release. This may be a comma separated list (no spaces) # if more than one PMIx Standard ABI level is supported. # The PMIx Standard defines a 'stable' and a 'provisional' ABI. # Therefore, there are two sets of major/minor values. # Since no PMIx Standard ABI exists at the moment, set to "0.0" std_abi_stable=0.0 std_abi_provisional=0.0 # If repo_rev is empty, then the repository version number will be # obtained during "make dist" via the "git describe --tags --always" # command, or with the date (if "git describe" fails) in the form of # "date". repo_rev= # If tarball_version is not empty, it is used as the version string in # the tarball filename, regardless of all other versions listed in # this file. For example, if tarball_version is empty, the tarball # filename will be of the form # openmpi-...tar.*. However, if # tarball_version is not empty, the tarball filename will be of the # form openmpi-.tar.*. tarball_version= # The date when this release was created date="Unreleased developer copy" # The shared library version of each of PMIx's public libraries. # These versions are maintained in accordance with the "Library # Interface Versions" chapter from the GNU Libtool documentation: # # - If the library source code has changed at all since the last # update, then increment revision (`c:r:a' becomes `c:r+1:a'). # # - If any interfaces have been added, removed, or changed since # the last update, increment current, and set revision to 0. # # - If any interfaces have been added since the last public release, # then increment age. # # - If any interfaces have been removed since the last public release, # then set age to 0. # # All changes in these version numbers are dictated by the PMIx # release managers (not individual developers). Notes: # 1. Since the PMIx master branch is maintained to always be compatible # with all prior releases (i.e., we never remove an interface), the # libtool 'c', 'r', and 'a' values are maintained equal to the highest # values found on any given release branch. This ensure that the .so # value remains the same as on the release branches, thereby indicating # compatibility. # 2. The version number of libpmix refers to the public pmix interfaces. # It does not refer to any internal interfaces. # Version numbers are described in the Libtool current:revision:age # format. libpmix_so_version=25:1:23 # "Common" components install standalone libraries that are run-time # # linked by one or more components. So they need to be versioned as # # well. Yuck; this somewhat breaks the # # components-don't-affect-the-build-system abstraction. # pmix-6.1.1~rc2/maint/0000775000175000017500000000000015203536752014605 5ustar alastairalastairpmix-6.1.1~rc2/maint/pmix.pc.in0000664000175000017500000000055115203536752016514 0ustar alastairalastairprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: pmix Description: Process Management Interface for Exascale (PMIx) Version: @PACKAGE_VERSION@ URL: https://pmix.org/ Libs: @PMIX_PC_LIBS@ Libs.private: @PMIX_PC_LIBS_PRIVATE@ Cflags: @PMIX_PC_CFLAGS@ Requires: @PMIX_PC_MODULES@ Requires.private: @PMIX_PC_MODULES_PRIVATE@ pmix-6.1.1~rc2/autogen.pl0000775000175000017500000011165415203536752015507 0ustar alastairalastair#!/usr/bin/env perl # # Copyright (c) 2009-2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013 Mellanox Technologies, Inc. # All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2015 IBM Corporation. All rights reserved. # # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # use strict; use Cwd; use File::Basename; use File::Find; use Data::Dumper; use Getopt::Long; # # Global variables # # Sentinel file to remove if we fail my $sentinel; # The m4 file we'll write at the end my $m4_output_file = "config/autogen_found_items.m4"; my $m4; # Sanity check file my $topdir_file = "include/pmix.h"; my $dnl_line = "dnl ---------------------------------------------------------------------------"; # The text file we'll write at the end that will contain # all the mca component directory paths my $mca_library_paths_file = "config/mca_library_paths.txt"; # Data structures to fill up with all the stuff we find my $mca_found; my @subdirs; # Command line parameters my $quiet_arg = 0; my $debug_arg = 0; my $help_arg = 0; my $include_arg = 0; my $exclude_arg = 0; my $force_arg = 0; # Include/exclude lists my $include_list; my $exclude_list; # Minimum versions my $pmix_automake_version = "1.13.4"; my $pmix_autoconf_version = "2.69"; my $pmix_libtool_version = "2.4.2"; # Search paths my $pmix_autoconf_search = "autoconf"; my $pmix_automake_search = "automake"; my $pmix_libtoolize_search = "libtoolize;glibtoolize"; # One-time setup my $username; my $hostname; my $full_hostname; # Patch program my $patch_prog = "patch"; $username = getpwuid($>); $full_hostname = `hostname`; chomp($full_hostname); $hostname = $full_hostname; $hostname =~ s/^([\w\-]+)\..+/\1/; ############################################################################## sub my_die { unlink($sentinel) if ($sentinel); die @_; } sub my_exit { my ($ret) = @_; unlink($sentinel) if ($sentinel && $ret != 0); exit($ret); } ############################################################################## sub verbose { print @_ if (!$quiet_arg); } sub debug { print @_ if ($debug_arg); } sub debug_dump { my $d = new Data::Dumper([@_]); $d->Purity(1)->Indent(1); debug $d->Dump; } ############################################################################## sub mca_process_component { my ($framework, $component) = @_; my $cdir = "src/mca/$framework/$component"; return if (! -d $cdir); # Process this directory my $found_component; $found_component = { name => $component, framework_name => $framework, abs_dir => $cdir, }; # Does this directory have a configure.m4 file? if (-f "$cdir/configure.m4") { $found_component->{"configure.m4"} = 1; verbose " Found configure.m4 file\n"; } # Push the results onto the $mca_found hash array push(@{$mca_found->{$framework}->{"components"}}, $found_component); # save the directory for later to create the paths # to all the component libraries push(@subdirs, $cdir); } ############################################################################## sub ignored { my ($dir) = @_; # If this directory does not have .pmix_ignore, or if it has a # .pmix_unignore that has my username in it, then add it to the # list of components. my $ignored = 0; if (-f "$dir/.pmix_ignore") { $ignored = 1; } if (-f "$dir/.pmix_unignore") { open(UNIGNORE, "$dir/.pmix_unignore") || my_die "Can't open $dir/.pmix_unignore file"; my $unignore; $unignore .= $_ while (); close(UNIGNORE); $ignored = 0 if ($unignore =~ /^$username$/m || $unignore =~ /^$username\@$hostname$/m || $unignore =~ /^$username\@$full_hostname$/m); } return $ignored; } ############################################################################## sub mca_process_framework { my ($framework) = @_; # Does this framework have a configure.m4 file? my $dir = "src/mca/$framework"; if (-f "$dir/configure.m4") { $mca_found->{$framework}->{"configure.m4"} = 1; verbose " Found framework configure.m4 file\n"; } # Did we exclude all components for this framework? if (exists($exclude_list->{$framework}) && $exclude_list->{$framework}[0] eq "AGEN_EXCLUDE_ALL") { verbose " => Excluded\n"; } else { # Look for component directories in this framework if (-d $dir) { $mca_found->{$framework}->{found} = 1; opendir(DIR, $dir) || my_die "Can't open $dir directory"; foreach my $d (sort(readdir(DIR))) { # Skip any non-directory, "base", or any dir that # begins with "." next if (! -d "$dir/$d" || $d eq "base" || substr($d, 0, 1) eq "."); # Skip any component that doesn't have a configure.m4 # or Makefile.am as we couldn't build it anyway if (! -f "$dir/$d/configure.m4" && ! -f "$dir/$d/Makefile.am" && ! -f "$dir/$d/configure.ac" && ! -f "$dir/$d/configure.in") { verbose " => No sentinel file found in $dir/$d -> Excluded\n"; next; } verbose "--- Found pmix / $framework / $d component: src/mca/$framework/$d\n"; # Skip if specifically excluded if (exists($exclude_list->{$framework})) { my $tst = 0; foreach my $ck (@{$exclude_list->{$framework}}) { if ($ck eq $d) { verbose " => Excluded\n"; $tst = 1; last; } } if ($tst) { next; } } # Skip if the framework is on the include list, but # doesn't contain this component if (exists($include_list->{$framework})) { my $tst = 0; foreach my $ck (@{$include_list->{$framework}}) { if ($ck ne $d) { verbose " => Not included\n"; $tst = 1; last; } } if ($tst) { next; } } # Check ignore status if (ignored("$dir/$d")) { verbose " => Ignored (found .pmix_ignore file)\n"; } else { mca_process_component($framework, $d); } } } closedir(DIR); } } ############################################################################## sub mca_generate_framework_header(\$\@) { my (@frameworks) = @_; my $framework_array_output=""; my $framework_decl_output=""; my $framework_name_output=""; foreach my $framework (@frameworks) { # There is no common framework object if ($framework ne "common" and $framework ne "src") { my $framework_name = "pmix_${framework}_base_framework"; $framework_array_output .= " &$framework_name,\n"; $framework_decl_output .= "extern pmix_mca_base_framework_t $framework_name;\n"; $framework_name_output .= " \"${framework}\",\n"; } } $framework_name_output .= " \"mca\",\n"; my $ifdef_string = uc "pmix_FRAMEWORKS_H"; open(FRAMEWORKS_OUT, ">src/include/pmix_frameworks.h"); printf FRAMEWORKS_OUT "%s", "/* * This file is autogenerated by autogen.pl. Do not edit this file by hand. */ #ifndef $ifdef_string #define $ifdef_string #include \"src/mca/base/pmix_mca_base_framework.h\" $framework_decl_output PMIX_EXPORT extern pmix_mca_base_framework_t *pmix_frameworks[]; PMIX_EXPORT extern char *pmix_framework_names[]; #endif /* $ifdef_string */\n\n"; close(FRAMEWORKS_OUT); open(FRAMEWORKS_OUT, ">src/include/pmix_frameworks.c"); printf FRAMEWORKS_OUT "%s", "/* * This file is autogenerated by autogen.pl. Do not edit this file by hand. */ #include \"src/include/pmix_config.h\" #include \"src/include/pmix_frameworks.h\" pmix_mca_base_framework_t *pmix_frameworks[] = { $framework_array_output NULL }; char *pmix_framework_names[] = { $framework_name_output NULL }; "; close(FRAMEWORKS_OUT); } ############################################################################## sub mca_process_project { # Look for framework directories my $dir = "src/mca"; opendir(DIR, $dir) || my_die "Can't open $dir directory"; my @my_dirs = readdir(DIR); @my_dirs = sort(@my_dirs); foreach my $d (@my_dirs) { # Skip any non-directory, "base", or any dir that begins with "." next if (! -d "$dir/$d" || $d eq "base" || substr($d, 0, 1) eq "."); # If this directory has a $dir.h file and a base/ # subdirectory, or its name is "common", then it's a # framework. if ("common" eq $d || (-f "$dir/$d/$d.h" && -d "$dir/$d/base")) { verbose "\n=== Found pmix framework: src/mca/$d\n"; mca_process_framework($d); } } closedir(DIR); } ############################################################################## sub mca_run_global { # Go find a list of frameworks, and for each of # those, go find a list of components. mca_process_project(); # Debugging output debug_dump($mca_found); $m4 .= "\n$dnl_line $dnl_line $dnl_line dnl MCA information\n"; # Array for all the m4_includes that we'll need to pick up the # configure.m4's. my @includes; # Write the list of frameworks my $frameworks_comma; # Print out project-level info my @mykeys = keys(%{$mca_found}); @mykeys = sort(@mykeys); # Ensure that the "common" framework is listed first # (if it exists) my @tmp; push(@tmp, "common") if (grep(/common/, @mykeys)); foreach my $f (@mykeys) { push(@tmp, $f) if ($f ne "common"); } @mykeys = @tmp; foreach my $f (@mykeys) { $frameworks_comma .= ", $f"; # Does this framework have a configure.m4 file? push(@includes, "src/mca/$f/configure.m4") if (exists($mca_found->{$f}->{"configure.m4"})); # This framework does have a Makefile.am (or at least, # it should!) my_die "Missing src/mca/$f/Makefile.am" if (! -f "src/mca/$f/Makefile.am"); } $frameworks_comma =~ s/^, //; &mca_generate_framework_header("src", @mykeys); $m4 .= "$dnl_line dnl Frameworks in the pmix project and their corresponding directories m4_define([mca_pmix_framework_list], [$frameworks_comma]) "; # Print out framework-level info foreach my $f (@mykeys) { my $components; my $m4_config_component_list; my $no_config_component_list; # Troll through each of the found components foreach my $comp (@{$mca_found->{$f}->{components}}) { my $c = $comp->{name}; $components .= "$c "; # Does this component have a configure.m4 file? if (exists($comp->{"configure.m4"})) { push(@includes, "src/mca/$f/$c/configure.m4"); $m4_config_component_list .= ", $c"; } else { $no_config_component_list .= ", $c"; } } $m4_config_component_list =~ s/^, //; $no_config_component_list =~ s/^, //; $m4 .= "dnl Components in the pmix / $f framework m4_define([mca_pmix_${f}_m4_config_component_list], [$m4_config_component_list]) m4_define([mca_pmix_${f}_no_config_component_list], [$no_config_component_list]) "; } # List out all the m4_include $m4 .= "$dnl_line dnl List of configure.m4 files to include\n"; foreach my $i (@includes) { $m4 .= "m4_include([$i])\n"; } } ############################################################################## # Find and remove stale files sub find_and_delete { foreach my $file (@_) { my $removed = 0; if (-f $file) { unlink($file); $removed = 1; } if (-f "config/$file") { unlink("config/$file"); $removed = 1; } debug " Removed stale copy of $file\n" if ($removed); } } ############################################################################## # Find a specific executable and ensure that it is a recent enough # version. sub find_and_check { my ($app, $app_name, $req_version) = @_; my @search_path = split(/;/, $app_name); my @min_version = split(/\./, $req_version); my @versions_found = (); foreach (@search_path) { verbose " Searching for $_\n"; my $version = `$_ --version`; if (!defined($version)) { verbose " $_ not found\n"; next; } # Matches a version string with 1 or more parts possibly prefixed with a letter (ex: # v2.2) or followed by a letter (ex: 2.2.6b). This regex assumes there is a space # before the version string and that the version is ok if there is no version. if (!($version =~ m/\s[vV]?(\d[\d\.]*\w?)/m)) { verbose " WARNING: $_ does not appear to support --version. Assuming it is ok\n"; return; } $version = $1; verbose " Found $_ version $version; checking version...\n"; push(@versions_found, $version); my @parts = split(/\./, $version); my $i = 0; # Check every component of the version number while ($i <= $#min_version) { verbose " Found version component $parts[$i] -- need $min_version[$i]\n"; # Check to see if there are any characters (!) in the # version number (e.g., Libtool's "2.2.6b" -- #%@#$%!!!). # Do separate comparisons between the number and any # trailing digits. You can't just "lt" compare the whole # string because "10 lt 2b" will return true. #@$@#$#@$ # Libtool!! $parts[$i] =~ m/(\d+)([a-z]*)/i; my $pn = $1; my $pa = $2; $min_version[$i] =~ m/(\d+)([a-z]*)/i; my $mn = $1; my $ma = $2; # If the version is higher, we're done. if ($pn > $mn) { verbose " ==> ACCEPTED\n"; return; } # If the version is lower, we're done. elsif ($pn < $mn || ($pn == $mn && $pa lt $ma)) { verbose " ==> Too low! Skipping this version\n"; last; } # If the version was equal, keep checking. ++$i; } # If we found a good version, return. if ($i > $#min_version) { verbose " ==> ACCEPTED\n"; return; } } # if no acceptable version found, reject it print " ================================================================= I could not find a recent enough copy of $app. I need at least $req_version, but only found the following versions:\n\n"; my $i = 0; foreach (@search_path) { print " $_: $versions_found[$i]\n"; $i++; } print "\nI am gonna abort. :-( Please make sure you are using at least the following versions of the tools: GNU Autoconf: $pmix_autoconf_version GNU Automake: $pmix_automake_version GNU Libtool: $pmix_libtool_version =================================================================\n"; my_exit(1); } ############################################################################## sub safe_system { print "Running: " . join(/ /, @_) . "\n"; my $ret = system(@_); $ret >>= 8; if (0 != $ret) { print "Command failed: @_\n"; my_exit($ret); } $ret; } ############################################################################## sub patch_autotools_output { my ($topdir) = @_; # Set indentation string for verbose output depending on current directory. my $indent_str = " "; if ($topdir eq ".") { $indent_str = "=== "; } # Patch ltmain.sh error for PGI version numbers. Redirect stderr to # /dev/null because this patch is only necessary for some versions of # Libtool (e.g., 2.2.6b); it'll [rightfully] fail if you have a new # enough Libtool that doesn't need this patch. But don't alarm the # user and make them think that autogen failed if this patch fails -- # make the errors be silent. # Also patch ltmain.sh for NAG compiler if (-f "config/ltmain.sh") { verbose "$indent_str"."Patching PGI compiler version numbers in ltmain.sh\n"; system("$patch_prog -N -p0 < $topdir/config/ltmain_pgi_tp.diff >/dev/null 2>&1"); unlink("config/ltmain.sh.rej"); verbose "$indent_str"."Patching \"-pthread\" option for NAG compiler in ltmain.sh\n"; system("$patch_prog -N -p0 < $topdir/config/ltmain_nag_pthread.diff >/dev/null 2>&1"); unlink("config/ltmain.sh.rej"); } # If there's no configure script, there's nothing else to do. return if (! -f "configure"); my @verbose_out; # Total ugh. We have to patch the configure script itself. See below # for explanations why. open(IN, "configure") || my_die "Can't open configure"; my $c; $c .= $_ while(); close(IN); my $c_orig = $c; # The PGI 10 version number broke <=LT # 2.2.6b's version number checking regexps. We can't fix the # Libtool install; all we can do is patch the resulting configure # script. :-( The following comes from the upstream patch: # http://lists.gnu.org/archive/html/libtool-patches/2009-11/msg00016.html push(@verbose_out, $indent_str . "Patching configure for Libtool PGI version number regexps\n"); $c =~ s/\*pgCC\\ \[1-5\]\* \| \*pgcpp\\ \[1-5\]\*/*pgCC\\ [1-5]\.* | *pgcpp\\ [1-5]\.*/g; # See http://git.savannah.gnu.org/cgit/libtool.git/commit/?id=v2.2.6-201-g519bf91 for details # Note that this issue was fixed in LT 2.2.8, however most distros are still using 2.2.6b push(@verbose_out, $indent_str . "Patching configure for IBM xlf libtool bug\n"); $c =~ s/(\$LD -shared \$libobjs \$deplibs \$)compiler_flags( -soname \$soname)/$1linker_flags$2/g; #Check if we are using a recent enough libtool that supports PowerPC little endian if(index($c, 'powerpc64le-*linux*)') == -1) { push(@verbose_out, $indent_str . "Patching configure for PowerPC little endian support\n"); my $replace_string = "x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*|"; $c =~ s/x86_64-\*kfreebsd\*-gnu\|x86_64-\*linux\*\|ppc\*-\*linux\*\|powerpc\*-\*linux\*\|/$replace_string/g; $replace_string = "powerpc64le-*linux*)\n\t LD=\"\${LD-ld} -m elf32lppclinux\"\n\t ;;\n\t powerpc64-*linux*)"; $c =~ s/ppc64-\*linux\*\|powerpc64-\*linux\*\)/$replace_string/g; $replace_string = "powerpcle-*linux*)\n\t LD=\"\${LD-ld} -m elf64lppc\"\n\t ;;\n\t powerpc-*linux*)"; $c =~ s/ppc\*-\*linux\*\|powerpc\*-\*linux\*\)/$replace_string/g; } # Fix consequence of broken libtool.m4 # see http://lists.gnu.org/archive/html/bug-libtool/2015-07/msg00002.html and # https://github.com/open-mpi/ompi/issues/751 push(@verbose_out, $indent_str . "Patching configure for -L/-R libtool.m4 bug\n"); # patch for libtool < 2.4.3 $c =~ s/# Some compilers place space between "-\{L,R\}" and the path.\n # Remove the space.\n if test \$p = \"-L\" \|\|/# Some compilers place space between "-\{L,-l,R\}" and the path.\n # Remove the spaces.\n if test \$p = \"-L\" \|\|\n test \$p = \"-l\" \|\|/g; # patch for libtool >= 2.4.3 $c =~ s/# Some compilers place space between "-\{L,R\}" and the path.\n # Remove the space.\n if test x-L = \"\$p\" \|\|\n test x-R = \"\$p\"\; then/# Some compilers place space between "-\{L,-l,R\}" and the path.\n # Remove the spaces.\n if test x-L = \"x\$p\" \|\|\n test x-l = \"x\$p\" \|\|\n test x-R = \"x\$p\"\; then/g; # Fix OS X Big Sur (11.0.x) support # From https://lists.gnu.org/archive/html/libtool-patches/2020-06/msg00001.html push(@verbose_out, $indent_str . "Patching configure for MacOS Big Sur libtool.m4 bug\n"); # Some versions of Libtool use ${wl} consistently, but others did # not (e.g., they used $wl). Make the regexp be able to handle # both. Additionally, the case string searching for 10.[012]* # changed over time. So make sure it can handle both of the case # strings that we're aware of. my $WL = '(\$\{wl\}|\$wl)'; my $SOMETIMES = '(\[,.\])*'; my $search_string = 'darwin\*\) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don\'t you love it\? case \$\{MACOSX_DEPLOYMENT_TARGET-10.0\},\$host in 10.0,\*86\*-darwin8\*\|10.0,\*-darwin\[91\]\*\) _lt_dar_allow_undefined=\'' . $WL . '-undefined ' . $WL . 'dynamic_lookup\' ;; 10.\[012\]' . $SOMETIMES . '\*\) _lt_dar_allow_undefined=\'' . $WL . '-flat_namespace ' . $WL . '-undefined ' . $WL . 'suppress\' ;; 10.\*\)'; my $replace_string = 'darwin*) # PMIx patched for Darwin / MacOS Big Sur. See # http://lists.gnu.org/archive/html/bug-libtool/2015-07/msg00001.html case ${MACOSX_DEPLOYMENT_TARGET},$host in 10.[012],*|,*powerpc*) _lt_dar_allow_undefined=\'${wl}-flat_namespace ${wl}-undefined ${wl}suppress\' ;; *)'; $c =~ s/$search_string/$replace_string/g; # Only write out verbose statements and a new configure if the # configure content actually changed return if ($c eq $c_orig); foreach my $str (@verbose_out) { verbose($str); } open(OUT, ">configure.patched") || my_die "Can't open configure.patched"; print OUT $c; close(OUT); # Use cp so that we preserve permissions on configure safe_system("cp configure.patched configure"); unlink("configure.patched"); } sub export_version { my ($name,$version) = @_; $version =~ s/[^a-zA-Z0-9,.]//g; my @version_splits = split(/\./,$version); my $hex = sprintf("0x%04x%02x%02x", $version_splits[0], $version_splits[1], $version_splits[2]); $m4 .= "m4_define([PMIX_${name}_MIN_VERSION], [$version])\n"; $m4 .= "m4_define([PMIX_${name}_NUMERIC_MIN_VERSION], [$hex])\n"; } sub get_and_define_min_versions() { open(IN, "VERSION") || my_die "Can't open VERSION"; while () { my $line = $_; my @fields = split(/=/,$line); if ($fields[0] eq "automake_min_version") { if ($fields[1] ne "\n") { $pmix_automake_version = $fields[1]; } } elsif($fields[0] eq "autoconf_min_version") { if ($fields[1] ne "\n") { $pmix_autoconf_version = $fields[1]; } } elsif($fields[0] eq "libtool_min_version") { if ($fields[1] ne "\n") { $pmix_libtool_version = $fields[1]; } } elsif($fields[0] eq "hwloc_min_version") { if ($fields[1] ne "\n") { export_version("HWLOC", $fields[1]); } } elsif($fields[0] eq "event_min_version") { if ($fields[1] ne "\n") { export_version("EVENT", $fields[1]); } } elsif($fields[0] eq "flex_min_version") { if ($fields[1] ne "\n") { export_version("FLEX", $fields[1]); } } elsif($fields[0] eq "python_min_version") { if ($fields[1] ne "\n") { export_version("PYTHON", $fields[1]); } } } close(IN); } ############################################################################## sub in_tarball { my $tarball = 0; open(IN, "VERSION") || my_die "Can't open VERSION"; # If repo_rev is not an empty string, we are in a tarball while () { my $line = $_; my @fields = split(/=/,$line); if ($fields[0] eq "repo_rev") { if ($fields[1] ne "\n") { $tarball = 1; last; } } } close(IN); return $tarball; } ############################################################################## sub replace_config_sub_guess { # This could be simpler if we could use some Perl modules for this # functionality (e.g., DateTime). But I don't want to introduce # any CPAN dependencies here, so just do sometime simple, even if # it's a bit laborious. Use a few private helper functions for # this kind of functionality. sub _get_timestamp { my $filename = shift; my $ret; if (-x $filename) { my $out = `$filename --version`; $out =~ m/GNU config\.[a-z]+ \((.+)\)/; $ret = $1; } return $ret; } sub _split_timestamp { my $ts = shift; $ts =~ m/(\d+)-(\d+)-(\d+)/; return $1, $2, $3; } # Returns true if timestamp $a > timestamp $b. sub _timestamp_gt { my ($a, $b) = @_; my ($year_a, $month_a, $day_a) = _split_timestamp($a); my ($year_b, $month_b, $day_b) = _split_timestamp($b); # Don't try to be clever -- just do a simple set of explicit # comparisons. if ($year_a > $year_b) { return 1; } elsif ($year_a < $year_b) { return 0; } else { if ($month_a > $month_b) { return 1; } elsif ($month_a < $month_b) { return 0; } else { if ($day_a > $day_b) { return 1; } else { return 0; } } } } my ($topdir) = @_; # Find the stashed known-good files, and get their version # timestamps. my $cached_dir = "$topdir/config/from-savannah"; my @files = qw/config.guess config.sub/; my %known_good_timestamps; foreach my $file (@files) { my $filename = "$cached_dir/upstream-$file"; my_die("Cannot find $filename") if (! -f $filename); my $ts = _get_timestamp($filename); $known_good_timestamps{$file} = $ts; } # Find all config.guess/config.sub files in the tree. If their # versions are older than the stashed known-good files, update # them from the stash. my @files; File::Find::find(sub { push(@files, $File::Find::name) if ($_ eq "config.guess" || $_ eq "config.sub") }, $topdir); foreach my $file (@files) { my $base = basename($file); my $ts = _get_timestamp($file); if (_timestamp_gt($known_good_timestamps{$base}, $ts)) { print("=== Replacing $file with newer version\n"); safe_system("cp -f $cached_dir/upstream-$base $file"); } } } ############################################################################## ############################################################################## ## main - do the real work... ############################################################################## ############################################################################## # Command line parameters my $ok = Getopt::Long::GetOptions("quiet|q" => \$quiet_arg, "debug|d" => \$debug_arg, "help|h" => \$help_arg, "include=s" => \$include_arg, "exclude=s" => \$exclude_arg, "force|f" => \$force_arg, ); if (!$ok || $help_arg) { print "Invalid command line argument.\n\n" if (!$ok); print "Options: --quiet | -q Do not display normal verbose output --debug | -d Output lots of debug information --help | -h This help list --include | -i Comma-separated list of framework-component pairs to be exclusively built - i.e., all other components will be ignored and only those specified will be marked to build --exclude | -e Comma-separated list of framework or framework-component to be excluded from the build --force | -f Run even if invoked from the source tree of an expanded distribution tarball\n"; my_exit($ok ? 0 : 1); } #--------------------------------------------------------------------------- # Check for project existence my $project_name_long = "PMIx"; my $project_name_short = "PMIx"; #--------------------------------------------------------------------------- $full_hostname = `hostname`; chomp($full_hostname); $m4 = "dnl dnl \$HEADER\$ dnl $dnl_line dnl This file is automatically created by autogen.pl; it should not dnl be edited by hand!! dnl dnl Generated by $username at " . localtime($ENV{SOURCE_DATE_EPOCH} || time) . " dnl on $full_hostname. $dnl_line\n\n"; #--------------------------------------------------------------------------- # Verify that we're in the PMIx root directory by checking for a token file. my_die "Not at the root directory of an PMIx source tree" if (! -f "config/pmix_mca.m4"); $force_arg = 1; my_die "autogen.pl has been invoked in the source tree of a PMIx distribution tarball; aborting... You likely do not need to invoke \"autogen.pl\" -- you can probably run \"configure\" directly. If you really know what you are doing, and really need to run autogen.pl, use the \"--force\" flag." if (!$force_arg && in_tarball()); # Now that we've verified that we're in the top-level OMPI directory, # set the sentinel file to remove if we abort. $sentinel = Cwd::cwd() . "/configure"; #--------------------------------------------------------------------------- my $step = 1; verbose "PMIx autogen (buckle up!) $step. Checking tool versions\n\n"; get_and_define_min_versions(); # Check the autotools revision levels &find_and_check("autoconf", $pmix_autoconf_search, $pmix_autoconf_version); &find_and_check("libtool", $pmix_libtoolize_search, $pmix_libtool_version); &find_and_check("automake", $pmix_automake_search, $pmix_automake_version); #--------------------------------------------------------------------------- ++$step; verbose "\n$step. Checking for git submodules\n\n"; # Make sure we got a submodule-full clone. If not, abort and let a # human figure it out. if (-f ".gitmodules") { print(" Doing some sanity checks for required submodule(s)...\n"); # Do a quick sanity check to ensure that required # submodule(s) are at least present (e.g., they won't be present # if you downloaded a GitHub.com-created tarball). open(IN, ".gitmodules") || die "Can't open .gitmodules"; while () { # Find "path = " lines if (!($_ =~ m/^\s+path = (.+)$/)) { next; } my $path = $1; # Check that the path exists and is non-empty. my $happy = 1; my $havefiles = 1; if (! -d $path) { $happy = 0; } else { opendir(DIR, $path) || my_die "Can't open $path directory"; my @files = readdir(DIR); closedir(DIR); $havefiles = 0 if ($#files < 4); } if (!$happy) { print(" ==> ERROR: Missing submodule directory The submodule path \"$path\" is missing.\n\n"); exit(1); } if (!$havefiles) { print(" ==> ERROR: Missing submodule files The submodule \"$path\" files are missing.\n\n"); exit(1); } } if (-d ".git") { open(IN, "git submodule status|") || die "Can't run \"git submodule status\""; while () { $_ =~ m/^(.)[0-9a-f]{40}\s+(\S+)/; my $status = $1; my $path = $2; print("=== Submodule: $path\n"); # Make sure the submodule is there if ($status eq "-") { print(" ==> ERROR: Missing The submodule \"$path\" is missing. Perhaps you forgot to \"git clone --recursive ...\", or you need to \"git submodule update --init --recursive\"...?\n\n"); exit(1); } # See if the commit in the submodule is not the same as the # commit that the git submodule thinks it should be. elsif ($status eq "+") { print(" ==> WARNING: Submodule hash is different than upstream. If this is not intentional, you may want to run: \"git submodule update --init --recursive\"\n"); } else { print(" Local hash is what is expected by the submodule (good!)\n"); } } } } #--------------------------------------------------------------------------- # No platform file -- write an empty list $m4 .= "m4_define([autogen_platform_file], [])\n\n"; if ($exclude_arg) { debug "Using exclude list: $exclude_arg"; my @list = split(/,/, $exclude_arg); foreach (@list) { my @pairs = split(/-/, $_); if (exists($pairs[1])) { # Remove any trailing newlines chomp($pairs[1]); debug " Adding ".$pairs[0]."->".$pairs[1]." to exclude list\n"; push(@{$exclude_list->{$pairs[0]}}, $pairs[1]); } else { debug " Adding $pairs[0] to exclude list\n"; push(@{$exclude_list->{$pairs[0]}}, "AGEN_EXCLUDE_ALL"); } } } if ($include_arg) { debug "Using include list: $include_arg"; my @list = split(/,/, $include_arg); foreach (@list) { my @pairs = split(/-/, $_); if (exists($pairs[1])) { # Remove any trailing newlines chomp($pairs[1]); debug " Adding ".$pairs[0]."->".$pairs[1]." to include list\n"; push(@{$include_list->{$pairs[0]}}, $pairs[1]); } # NOTE: it makes no sense to include all as that is the default # so ignore that scenario here, if given } } #--------------------------------------------------------------------------- # Find frameworks, components ++$step; verbose "\n$step. Searching for MCA frameworks and components\n"; my $ret; # Figure out if we're at the top level of the PMIx tree or not. if (! (-f "VERSION" && -f "configure.ac" && -f $topdir_file)) { print("\n\nYou must run this script from the top-level directory of the PMIx tree.\n\n"); my_exit(1); } $m4 .= "\ndnl Project names m4_define([project_name_long], [$project_name_long]) m4_define([project_name_short], [$project_name_short])\n"; # Setup MCA mca_run_global(); #--------------------------------------------------------------------------- # If we got here, all was good. Run the auto tools. ++$step; verbose "\n$step. Running autotools on top-level tree\n\n"; # Remove old versions of the files (this is probably overkill, but...) verbose "==> Remove stale files\n"; find_and_delete(qw/config.guess config.sub depcomp compile install-sh ltconfig ltmain.sh missing mkinstalldirs libtool/); # Remove the old m4 file and write the new one verbose "==> Writing m4 file with autogen.pl results\n"; unlink($m4_output_file); open(M4, ">$m4_output_file") || my_die "Can't open $m4_output_file"; print M4 $m4; close(M4); # Remove the old library path file and write the new one verbose "==> Writing txt file with all the mca component paths\n"; unlink($mca_library_paths_file); open(M4, ">$mca_library_paths_file") || my_die "Cannot open $mca_library_paths_file"; my $paths = join(":", @subdirs); print M4 $paths; close(M4); # Run autoreconf verbose "==> Running autoreconf\n"; my $cmd = "autoreconf -ivf --warnings=all,no-obsolete,no-override -I config -I config/oac"; safe_system($cmd); patch_autotools_output("."); # Per https://github.com/open-mpi/ompi/issues/8410, replace config.sub # and config.guess with known-good versions if the Autoconf-installed # versions are older. replace_config_sub_guess("."); #--------------------------------------------------------------------------- verbose " ================================================ PMIx autogen: completed successfully. w00t! ================================================\n\n"; # Done! exit(0); pmix-6.1.1~rc2/src/0000775000175000017500000000000015203536752014264 5ustar alastairalastairpmix-6.1.1~rc2/src/hwloc/0000775000175000017500000000000015203536752015400 5ustar alastairalastairpmix-6.1.1~rc2/src/hwloc/pmix_hwloc.c0000664000175000017500000015365115203536752017730 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_SYS_UTSNAME_H # include #endif #include #include #include #include #include #include #include #include #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/pnet/pnet.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_fd.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_path.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "src/util/pmix_vmem.h" #include "pmix_common.h" #include "pmix_hwloc.h" #include static bool topo_in_shmem = false; static bool passed_thru = false; static char *vmhole = "biggest"; static pmix_vmem_hole_kind_t hole_kind = VMEM_HOLE_BIGGEST; static char *topo_file = NULL; static char *testcpuset = NULL; static int pmix_hwloc_output = -1; static int pmix_hwloc_verbose = 0; static size_t shmemsize = 0; static size_t shmemaddr; static char *shmemfile = NULL; static int shmemfd = -1; static bool space_available = false; static uint64_t amount_space_avail = 0; static int enough_space(const char *filename, size_t space_req, uint64_t *space_avail, bool *result); static pmix_status_t load_xml(char *xml); static char *popstr(pmix_cb_t *cb); static size_t popsize(pmix_cb_t *cb); static void print_maps(void); static pmix_topology_t *popptr(pmix_cb_t *cb); static int get_locality_string_by_depth(int d, hwloc_cpuset_t cpuset, hwloc_cpuset_t result); static int set_flags(hwloc_topology_t topo, unsigned int flags); pmix_status_t pmix_hwloc_register(void) { (void) pmix_mca_base_var_register("pmix", "pmix", "hwloc", "verbose", "Verbosity for HWLOC operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_hwloc_verbose); if (0 < pmix_hwloc_verbose) { /* set default output */ pmix_hwloc_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_hwloc_output, pmix_hwloc_verbose); } vmhole = "biggest"; (void) pmix_mca_base_var_register("pmix", "pmix", "hwloc", "hole_kind", "Kind of VM hole to identify - none, begin, biggest, libs, heap, stack (default=biggest)", PMIX_MCA_BASE_VAR_TYPE_STRING, &vmhole); if (0 == strcasecmp(vmhole, "none")) { hole_kind = VMEM_HOLE_NONE; } else if (0 == strcasecmp(vmhole, "begin")) { hole_kind = VMEM_HOLE_BEGIN; } else if (0 == strcasecmp(vmhole, "biggest")) { hole_kind = VMEM_HOLE_BIGGEST; } else if (0 == strcasecmp(vmhole, "libs")) { hole_kind = VMEM_HOLE_IN_LIBS; } else if (0 == strcasecmp(vmhole, "heap")) { hole_kind = VMEM_HOLE_AFTER_HEAP; } else if (0 == strcasecmp(vmhole, "stack")) { hole_kind = VMEM_HOLE_BEFORE_STACK; } else { pmix_output(0, "INVALID VM HOLE TYPE"); return PMIX_ERROR; } (void) pmix_mca_base_var_register("pmix", "pmix", "hwloc", "topo_file", "Topology file to use instead of discovering it (mostly for testing purposes)", PMIX_MCA_BASE_VAR_TYPE_STRING, &topo_file); (void) pmix_mca_base_var_register("pmix", "pmix", "hwloc", "test_cpuset", "Cpuset for testing purposes", PMIX_MCA_BASE_VAR_TYPE_STRING, &testcpuset); return PMIX_SUCCESS; } void pmix_hwloc_finalize(void) { if (NULL == pmix_globals.topology.topology || pmix_globals.external_topology) { return; } if (topo_in_shmem) { if (NULL != shmemfile) { unlink(shmemfile); free(shmemfile); shmemfile = NULL; shmemsize = 0; } if (0 <= shmemfd) { close(shmemfd); shmemfd = -1; } } hwloc_topology_destroy(pmix_globals.topology.topology); pmix_globals.topology.topology = NULL; if (NULL != pmix_globals.topology.source) { free(pmix_globals.topology.source); pmix_globals.topology.source = NULL; } return; } pmix_status_t pmix_hwloc_setup_topology(pmix_info_t *info, size_t ninfo) { pmix_cb_t cb; pmix_proc_t wildcard; char *xmlbuffer = NULL; int len; size_t n; pmix_kval_t kv, *kptr; pmix_value_t val; bool share = false; bool found = false; pmix_topology_t *topo; char *file; pmix_status_t rc; /* only go thru here ONCE! */ if (passed_thru) { return PMIX_SUCCESS; } passed_thru = true; pmix_output_verbose(2, pmix_hwloc_output, "%s:%s", __FILE__, __func__); /* see if they want us to share the topology with our clients */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_SHARE_TOPOLOGY)) { share = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_TOPOLOGY2)) { if (found) { continue; } /* prefer this option */ if (NULL != pmix_globals.topology.source) { free(pmix_globals.topology.source); } topo = info[n].value.data.topo; pmix_globals.topology.source = strdup(topo->source); pmix_globals.topology.topology = topo->topology; pmix_globals.external_topology = true; found = true; } else if (PMIX_CHECK_KEY(&info[n], PMIX_TOPOLOGY)) { if (!found) { // prefer PMIX_TOPOLOGY2 if (NULL != pmix_globals.topology.source) { free(pmix_globals.topology.source); } pmix_globals.topology.source = strdup("hwloc"); // we cannot know the version they used pmix_globals.topology.topology = (hwloc_topology_t) info[n].value.data.ptr; pmix_globals.external_topology = true; } } } if (NULL != pmix_globals.topology.topology) { pmix_output_verbose(2, pmix_hwloc_output, "%s:%s topology externally provided", __FILE__, __func__); /* record locally in case someone does a PMIx_Get to retrieve it */ kv.key = PMIX_TOPOLOGY2; kv.value = &val; val.type = PMIX_TOPO; val.data.topo = &pmix_globals.topology; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, &kv); pmix_output_verbose(2, pmix_hwloc_output, "%s:%s stored", __FILE__, __func__); if (PMIX_SUCCESS != rc) { return rc; } /* if we need to share it, go do that */ if (share) { goto sharetopo; } /* otherwise, we are done */ return PMIX_SUCCESS; } PMIX_LOAD_PROCID(&wildcard, pmix_globals.myid.nspace, PMIX_RANK_WILDCARD); /* try to get it ourselves */ int fd; uint64_t addr, size; pmix_output_verbose(2, pmix_hwloc_output, "%s:%s checking shmem", __FILE__, __func__); /* first try to get the shmem link, if available */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.key = PMIX_HWLOC_SHMEM_FILE; cb.proc = &wildcard; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb); if (PMIX_SUCCESS != rc) { cb.key = NULL; PMIX_DESTRUCT(&cb); goto tryxml; } file = popstr(&cb); cb.key = PMIX_HWLOC_SHMEM_ADDR; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb); if (PMIX_SUCCESS != rc) { cb.key = NULL; PMIX_DESTRUCT(&cb); free(file); goto tryxml; } addr = popsize(&cb); cb.key = PMIX_HWLOC_SHMEM_SIZE; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb); if (PMIX_SUCCESS != rc) { cb.key = NULL; PMIX_DESTRUCT(&cb); free(file); goto tryxml; } size = popsize(&cb); cb.key = NULL; PMIX_DESTRUCT(&cb); if (0 > (fd = open(file, O_RDONLY))) { free(file); /* it may be that a tool has connected to a remote * daemon, in which case the file won't be found. * Could also be some other error, but let's not * treat this as fatal */ goto tryself; } free(file); rc = hwloc_shmem_topology_adopt((hwloc_topology_t *) &pmix_globals.topology.topology, fd, 0, (void *) addr, size, 0); if (0 == rc) { pmix_output_verbose(2, pmix_hwloc_output, "%s:%s shmem adopted", __FILE__, __func__); /* got it - we are done */ pmix_asprintf(&pmix_globals.topology.source, "hwloc:%s", HWLOC_VERSION); /* record locally in case someone does a PMIx_Get to retrieve it */ kv.key = PMIX_TOPOLOGY2; kv.value = &val; val.type = PMIX_TOPO; val.data.topo = &pmix_globals.topology; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, &kv); pmix_output_verbose(2, pmix_hwloc_output, "%s:%s stored", __FILE__, __func__); topo_in_shmem = true; return PMIX_SUCCESS; } /* failed to adopt from shmem, so provide some feedback and * then fallback to other ways to get the topology */ if (4 < pmix_output_get_verbosity(pmix_hwloc_output)) { print_maps(); } tryxml: pmix_output_verbose(2, pmix_hwloc_output, "%s:%s checking v2 xml", __FILE__, __func__); /* try to get the v2 XML string */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.key = PMIX_HWLOC_XML_V2; cb.proc = &wildcard; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb); if (PMIX_SUCCESS == rc) { file = popstr(&cb); if (NULL == file) { rc = PMIX_ERR_NOT_FOUND; } else { rc = load_xml(file); free(file); } cb.key = NULL; PMIX_DESTRUCT(&cb); if (PMIX_SUCCESS != rc) { goto tryv1; } pmix_output_verbose(2, pmix_hwloc_output, "%s:%s v2 xml adopted", __FILE__, __func__); /* record locally in case someone does a PMIx_Get to retrieve it */ kv.key = PMIX_TOPOLOGY2; kv.value = &val; val.type = PMIX_TOPO; val.data.topo = &pmix_globals.topology; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, &kv); pmix_output_verbose(2, pmix_hwloc_output, "%s:%s stored", __FILE__, __func__); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } if (share) { goto sharetopo; } return rc; } tryv1: /* try to get the v1 XML string */ pmix_output_verbose(2, pmix_hwloc_output, "%s:%s checking v1 xml", __FILE__, __func__); PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.key = PMIX_HWLOC_XML_V1; cb.proc = &wildcard; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb); if (PMIX_SUCCESS == rc) { file = popstr(&cb); if (NULL == file) { rc = PMIX_ERR_NOT_FOUND; } else { rc = load_xml(file); free(file); } cb.key = NULL; PMIX_DESTRUCT(&cb); if (PMIX_SUCCESS != rc) { goto tryself; } pmix_output_verbose(2, pmix_hwloc_output, "%s:%s v1 xml adopted", __FILE__, __func__); /* record locally in case someone does a PMIx_Get to retrieve it */ kv.key = PMIX_TOPOLOGY2; kv.value = &val; val.type = PMIX_TOPO; val.data.topo = &pmix_globals.topology; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, &kv); pmix_output_verbose(2, pmix_hwloc_output, "%s:%s stored", __FILE__, __func__); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } if (share) { goto sharetopo; } return rc; } tryself: /* did they give us one to use? */ if (NULL != topo_file) { pmix_output_verbose(2, pmix_hwloc_output, "%s:%s using MCA provided topo file", __FILE__, __func__); if (0 != hwloc_topology_init((hwloc_topology_t *) &pmix_globals.topology.topology)) { return PMIX_ERR_TAKE_NEXT_OPTION; } if (0 != hwloc_topology_set_xml((hwloc_topology_t) pmix_globals.topology.topology, topo_file)) { return PMIX_ERR_NOT_SUPPORTED; } /* since we are loading this from an external source, we have to * explicitly set a flag so hwloc sets things up correctly */ if (0 != set_flags(pmix_globals.topology.topology, HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)) { hwloc_topology_destroy(pmix_globals.topology.topology); return PMIX_ERROR; } /* now load the topology */ if (0 != hwloc_topology_load(pmix_globals.topology.topology)) { hwloc_topology_destroy(pmix_globals.topology.topology); return PMIX_ERROR; } /* we don't know the version */ if (NULL != pmix_globals.topology.source) { free(pmix_globals.topology.source); } pmix_globals.topology.source = strdup("hwloc"); } else { pmix_output_verbose(2, pmix_hwloc_output, "%s:%s doing discovery", __FILE__, __func__); /* we weren't given a topology, so get it for ourselves */ if (0 != hwloc_topology_init((hwloc_topology_t *) &pmix_globals.topology.topology)) { return PMIX_ERR_TAKE_NEXT_OPTION; } if (0 != set_flags(pmix_globals.topology.topology, 0)) { hwloc_topology_destroy(pmix_globals.topology.topology); return PMIX_ERR_INIT; } if (0 != hwloc_topology_load(pmix_globals.topology.topology)) { PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); hwloc_topology_destroy(pmix_globals.topology.topology); return PMIX_ERR_NOT_SUPPORTED; } pmix_asprintf(&pmix_globals.topology.source, "hwloc:%s", HWLOC_VERSION); pmix_output_verbose(2, pmix_hwloc_output, "%s:%s discovery complete - source %s", __FILE__, __func__, pmix_globals.topology.source); } /* record locally in case someone does a PMIx_Get to retrieve it */ kv.key = PMIX_TOPOLOGY2; kv.value = &val; val.type = PMIX_TOPO; val.data.topo = &pmix_globals.topology; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, &kv); pmix_output_verbose(2, pmix_hwloc_output, "%s:%s stored", __FILE__, __func__); /* if we don't need to share it, then we are done */ if (!share) { return PMIX_SUCCESS; } sharetopo: /* setup the XML representation(s) */ pmix_output_verbose(2, pmix_hwloc_output, "%s:%s sharing topology", __FILE__, __func__); /* pass the topology as a v2 xml string */ if (0 == hwloc_topology_export_xmlbuffer(pmix_globals.topology.topology, &xmlbuffer, &len, 0)) { pmix_output_verbose(2, pmix_hwloc_output, "%s:%s export v2 xml", __FILE__, __func__); kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_HWLOC_XML_V2); kptr->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_LOAD(kptr->value, xmlbuffer, PMIX_STRING); pmix_list_append(&pmix_server_globals.gdata, &kptr->super); /* save it with the deprecated key for older RMs */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_LOCAL_TOPO); kptr->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_LOAD(kptr->value, xmlbuffer, PMIX_STRING); pmix_list_append(&pmix_server_globals.gdata, &kptr->super); hwloc_free_xmlbuffer(pmix_globals.topology.topology, xmlbuffer); } /* and as a v1 xml string, should an older client attach */ if (0 == hwloc_topology_export_xmlbuffer(pmix_globals.topology.topology, &xmlbuffer, &len, HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1)) { pmix_output_verbose(2, pmix_hwloc_output, "%s:%s export v1 xml", __FILE__, __func__); kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_HWLOC_XML_V1); kptr->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_LOAD(kptr->value, xmlbuffer, PMIX_STRING); hwloc_free_xmlbuffer(pmix_globals.topology.topology, xmlbuffer); pmix_list_append(&pmix_server_globals.gdata, &kptr->super); /* cannot support the deprecated PMIX_LOCAL_TOPO key here as it would * overwrite the HWLOC v2 string */ } /* if they specified no shared memory, then we are done */ if (VMEM_HOLE_NONE == hole_kind) { pmix_output_verbose(2, pmix_hwloc_output, "%s:%s no shmem requested", __FILE__, __func__); return PMIX_SUCCESS; } /* get the size of the topology shared memory segment */ if (0 != hwloc_shmem_topology_get_length(pmix_globals.topology.topology, &shmemsize, 0)) { pmix_output_verbose(2, pmix_hwloc_output, "%s hwloc topology shmem not available", PMIX_NAME_PRINT(&pmix_globals.myid)); return PMIX_SUCCESS; } /* try and find a hole */ if (PMIX_SUCCESS != pmix_vmem_find_hole(hole_kind, &shmemaddr, shmemsize)) { /* we couldn't find a hole, so don't use the shmem support */ if (4 < pmix_output_get_verbosity(pmix_hwloc_output)) { print_maps(); } return PMIX_SUCCESS; } /* create the shmem file in our session dir so it * will automatically get cleaned up */ pmix_asprintf(&shmemfile, "%s/hwloc.sm", pmix_server_globals.tmpdir); /* let's make sure we have enough space for the backing file */ if (PMIX_SUCCESS != enough_space(shmemfile, shmemsize, &amount_space_avail, &space_available)) { pmix_output_verbose(2, pmix_hwloc_output, "%s an error occurred while determining " "whether or not %s could be created for topo shmem.", PMIX_NAME_PRINT(&pmix_globals.myid), shmemfile); free(shmemfile); shmemfile = NULL; return PMIX_SUCCESS; } if (!space_available) { if (1 < pmix_output_get_verbosity(pmix_hwloc_output)) { pmix_show_help("help-ploc.txt", "target full", true, shmemfile, pmix_globals.hostname, (unsigned long) shmemsize, (unsigned long long) amount_space_avail); } free(shmemfile); shmemfile = NULL; return PMIX_SUCCESS; } /* enough space is available, so create the segment */ if (-1 == (shmemfd = open(shmemfile, O_CREAT | O_RDWR, 0600))) { int err = errno; if (1 < pmix_output_get_verbosity(pmix_hwloc_output)) { pmix_show_help("help-ploc.txt", "sys call fail", true, pmix_globals.hostname, "open(2)", "", strerror(err), err); } free(shmemfile); shmemfile = NULL; return PMIX_SUCCESS; } /* ensure nobody inherits this fd */ pmix_fd_set_cloexec(shmemfd); /* populate the shmem segment with the topology */ rc = hwloc_shmem_topology_write(pmix_globals.topology.topology, shmemfd, 0, (void *) shmemaddr, shmemsize, 0); if (0 != rc) { pmix_output_verbose(2, pmix_hwloc_output, "%s an error %d (%s) occurred while writing topology to %s", PMIX_NAME_PRINT(&pmix_globals.myid), rc, strerror(errno), shmemfile); unlink(shmemfile); free(shmemfile); shmemfile = NULL; close(shmemfd); shmemfd = -1; return PMIX_SUCCESS; } pmix_output_verbose(2, pmix_hwloc_output, "%s:%s exported shmem", __FILE__, __func__); /* add the requisite key-values to the global data to be * given to each client for older PMIx versions */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_HWLOC_SHMEM_FILE); kptr->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_LOAD(kptr->value, shmemfile, PMIX_STRING); pmix_list_append(&pmix_server_globals.gdata, &kptr->super); kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_HWLOC_SHMEM_ADDR); kptr->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_LOAD(kptr->value, &shmemaddr, PMIX_SIZE); pmix_list_append(&pmix_server_globals.gdata, &kptr->super); kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_HWLOC_SHMEM_SIZE); kptr->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_LOAD(kptr->value, &shmemsize, PMIX_SIZE); pmix_list_append(&pmix_server_globals.gdata, &kptr->super); return PMIX_SUCCESS; } pmix_status_t pmix_hwloc_load_topology(pmix_topology_t *topo) { pmix_cb_t cb; pmix_proc_t wildcard; pmix_status_t rc; pmix_topology_t *t; pmix_output_verbose(2, pmix_hwloc_output, "%s:%s", __FILE__, __func__); /* see if they stipulated the type of topology they want */ if (NULL != topo->source) { if (0 != strncasecmp(topo->source, "hwloc", strlen("hwloc"))) { /* they want somebody else */ pmix_output_verbose(2, pmix_hwloc_output, "%s:%s no match - wanted %s", __FILE__, __func__, topo->source); return PMIX_ERR_TAKE_NEXT_OPTION; } /* if we already have a suitable version, just return it */ if (NULL != pmix_globals.topology.topology) { if (0 == strncasecmp(pmix_globals.topology.source, topo->source, strlen(topo->source))) { pmix_output_verbose(2, pmix_hwloc_output, "%s:%s matched sources", __FILE__, __func__); topo->topology = pmix_globals.topology.topology; return PMIX_SUCCESS; } /* nope - not a suitable version */ pmix_output_verbose(2, pmix_hwloc_output, "%s:%s present but not suitable", __FILE__, __func__); return PMIX_ERR_TAKE_NEXT_OPTION; } } else { /* they didn't stipulate a source, so if we already have something, just return it */ if (NULL != pmix_globals.topology.topology) { pmix_output_verbose(2, pmix_hwloc_output, "%s:%s no source stipulated - returning current version", __FILE__, __func__); topo->source = strdup(pmix_globals.topology.source); topo->topology = pmix_globals.topology.topology; return PMIX_SUCCESS; } } /* see if we have it in storage */ pmix_output_verbose(2, pmix_hwloc_output, "%s:%s checking storage", __FILE__, __func__); PMIX_CONSTRUCT(&cb, pmix_cb_t); PMIX_LOAD_PROCID(&wildcard, pmix_globals.myid.nspace, PMIX_RANK_WILDCARD); cb.proc = &wildcard; cb.copy = true; cb.key = PMIX_TOPOLOGY2; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb); if (PMIX_SUCCESS == rc) { cb.key = NULL; t = popptr(&cb); PMIX_DESTRUCT(&cb); if (NULL != t) { pmix_output_verbose(2, pmix_hwloc_output, "%s:%s found in storage", __FILE__, __func__); topo->source = strdup(t->source); topo->topology = t->topology; pmix_globals.topology.source = strdup(t->source); pmix_globals.topology.topology = t->topology; return PMIX_SUCCESS; } } /* we don't have it - better set it up */ pmix_output_verbose(2, pmix_hwloc_output, "%s:%s nothing found - calling setup", __FILE__, __func__); rc = pmix_hwloc_setup_topology(NULL, 0); if (PMIX_SUCCESS == rc) { topo->source = strdup(pmix_globals.topology.source); topo->topology = pmix_globals.topology.topology; } return rc; } pmix_status_t pmix_hwloc_generate_cpuset_string(const pmix_cpuset_t *cpuset, char **cpuset_string) { char *tmp; if (NULL == cpuset || NULL == cpuset->bitmap) { *cpuset_string = NULL; return PMIX_ERR_BAD_PARAM; } /* if we aren't the source, then nothing we can do */ if (0 != strncasecmp(cpuset->source, "hwloc", 5)) { return PMIX_ERR_TAKE_NEXT_OPTION; } hwloc_bitmap_list_asprintf(&tmp, cpuset->bitmap); pmix_asprintf(cpuset_string, "hwloc:%s", tmp); free(tmp); return PMIX_SUCCESS; } pmix_status_t pmix_hwloc_parse_cpuset_string(const char *cpuset_string, pmix_cpuset_t *cpuset) { char *src; int hrc; /* if we aren't the source, then pass */ src = strchr(cpuset_string, ':'); if (NULL == src) { /* bad string */ return PMIX_ERR_BAD_PARAM; } *src = '\0'; if (0 != strncasecmp(cpuset_string, "hwloc", 5)) { *src = ':'; return PMIX_ERR_TAKE_NEXT_OPTION; } *src = ':'; ++src; cpuset->source = strdup("hwloc"); cpuset->bitmap = hwloc_bitmap_alloc(); hrc = hwloc_bitmap_list_sscanf(cpuset->bitmap, src); if (0 != hrc) { return PMIX_ERR_BAD_PARAM; } return PMIX_SUCCESS; } pmix_status_t pmix_hwloc_generate_locality_string(const pmix_cpuset_t *cpuset, char **loc) { char *locality = NULL, *tmp, *t2; unsigned depth, d; hwloc_cpuset_t result; hwloc_obj_type_t type; /* if we aren't the source, then pass */ if (0 != strncasecmp(cpuset->source, "hwloc", 5)) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* if this proc is not bound, then there is no locality. We * know it isn't bound if the cpuset is NULL, or if it is * all 1's */ if (NULL == cpuset->bitmap || hwloc_bitmap_isfull(cpuset->bitmap)) { *loc = NULL; return PMIX_SUCCESS; } /* we are going to use a bitmap to save the results so * that we can use a hwloc utility to print them */ result = hwloc_bitmap_alloc(); /* get the max depth of the topology */ depth = hwloc_topology_get_depth(pmix_globals.topology.topology); /* start at the first depth below the top machine level */ for (d = 1; d < depth; d++) { /* get the object type at this depth */ type = hwloc_get_depth_type(pmix_globals.topology.topology, d); /* if it isn't one of interest, then ignore it */ if (HWLOC_OBJ_NUMANODE != type && HWLOC_OBJ_PACKAGE != type && HWLOC_OBJ_L1CACHE != type && HWLOC_OBJ_L2CACHE != type && HWLOC_OBJ_L3CACHE != type && HWLOC_OBJ_CORE != type && HWLOC_OBJ_PU != type) { continue; } if (get_locality_string_by_depth(d, cpuset->bitmap, result) < 0) { continue; } /* it should be impossible, but allow for the possibility * that we came up empty at this depth */ if (!hwloc_bitmap_iszero(result)) { hwloc_bitmap_list_asprintf(&tmp, result); switch (type) { case HWLOC_OBJ_NUMANODE: pmix_asprintf(&t2, "%sNM%s:", (NULL == locality) ? "" : locality, tmp); if (NULL != locality) { free(locality); } locality = t2; break; case HWLOC_OBJ_PACKAGE: pmix_asprintf(&t2, "%sSK%s:", (NULL == locality) ? "" : locality, tmp); if (NULL != locality) { free(locality); } locality = t2; break; case HWLOC_OBJ_L3CACHE: pmix_asprintf(&t2, "%sL3%s:", (NULL == locality) ? "" : locality, tmp); if (NULL != locality) { free(locality); } locality = t2; break; case HWLOC_OBJ_L2CACHE: pmix_asprintf(&t2, "%sL2%s:", (NULL == locality) ? "" : locality, tmp); if (NULL != locality) { free(locality); } locality = t2; break; case HWLOC_OBJ_L1CACHE: pmix_asprintf(&t2, "%sL1%s:", (NULL == locality) ? "" : locality, tmp); if (NULL != locality) { free(locality); } locality = t2; break; case HWLOC_OBJ_CORE: pmix_asprintf(&t2, "%sCR%s:", (NULL == locality) ? "" : locality, tmp); if (NULL != locality) { free(locality); } locality = t2; break; case HWLOC_OBJ_PU: pmix_asprintf(&t2, "%sHT%s:", (NULL == locality) ? "" : locality, tmp); if (NULL != locality) { free(locality); } locality = t2; break; default: /* just ignore it */ break; } free(tmp); } hwloc_bitmap_zero(result); } if (get_locality_string_by_depth(HWLOC_TYPE_DEPTH_NUMANODE, cpuset->bitmap, result) == 0) { /* it should be impossible, but allow for the possibility * that we came up empty at this depth */ if (!hwloc_bitmap_iszero(result)) { hwloc_bitmap_list_asprintf(&tmp, result); pmix_asprintf(&t2, "%sNM%s:", (NULL == locality) ? "" : locality, tmp); if (NULL != locality) { free(locality); } locality = t2; free(tmp); } hwloc_bitmap_zero(result); } hwloc_bitmap_free(result); /* remove the trailing colon */ if (NULL != locality) { locality[strlen(locality) - 1] = '\0'; } *loc = locality; return PMIX_SUCCESS; } pmix_status_t pmix_hwloc_get_relative_locality(const char *locality1, const char *locality2, pmix_locality_t *loc) { pmix_locality_t locality; char *loc1, *loc2, **set1, **set2; hwloc_bitmap_t bit1, bit2; size_t n1, n2; pmix_status_t rc = PMIX_ERR_TAKE_NEXT_OPTION; /* check that locality was generated by us */ if (0 != strncasecmp(locality1, "hwloc:", strlen("hwloc:")) || 0 != strncasecmp(locality2, "hwloc:", strlen("hwloc:"))) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* point to the first character past the ':' delimiter */ loc1 = (char *) &locality1[strlen("hwloc:")]; loc2 = (char *) &locality2[strlen("hwloc:")]; /* start with what we know - they share a node */ locality = PMIX_LOCALITY_SHARE_NODE; set1 = PMIx_Argv_split(loc1, ':'); set2 = PMIx_Argv_split(loc2, ':'); bit1 = hwloc_bitmap_alloc(); bit2 = hwloc_bitmap_alloc(); /* check each matching type */ for (n1 = 0; NULL != set1[n1]; n1++) { /* convert the location into bitmap */ hwloc_bitmap_list_sscanf(bit1, &set1[n1][2]); /* find the matching type in set2 */ for (n2 = 0; NULL != set2[n2]; n2++) { if (0 == strncmp(set1[n1], set2[n2], 2)) { /* convert the location into bitmap */ hwloc_bitmap_list_sscanf(bit2, &set2[n2][2]); /* see if they intersect */ if (hwloc_bitmap_intersects(bit1, bit2)) { /* set the corresponding locality bit */ if (0 == strncmp(set1[n1], "NM", 2)) { locality |= PMIX_LOCALITY_SHARE_NUMA; } else if (0 == strncmp(set1[n1], "SK", 2)) { locality |= PMIX_LOCALITY_SHARE_PACKAGE; } else if (0 == strncmp(set1[n1], "L3", 2)) { locality |= PMIX_LOCALITY_SHARE_L3CACHE; } else if (0 == strncmp(set1[n1], "L2", 2)) { locality |= PMIX_LOCALITY_SHARE_L2CACHE; } else if (0 == strncmp(set1[n1], "L1", 2)) { locality |= PMIX_LOCALITY_SHARE_L1CACHE; } else if (0 == strncmp(set1[n1], "CR", 2)) { locality |= PMIX_LOCALITY_SHARE_CORE; } else if (0 == strncmp(set1[n1], "HT", 2)) { locality |= PMIX_LOCALITY_SHARE_HWTHREAD; } else { /* should never happen */ pmix_output(0, "UNRECOGNIZED LOCALITY %s", set1[n1]); rc = PMIX_ERROR; } } break; } } } PMIx_Argv_free(set1); PMIx_Argv_free(set2); hwloc_bitmap_free(bit1); hwloc_bitmap_free(bit2); *loc = locality; return rc; } pmix_status_t pmix_hwloc_get_cpuset(pmix_cpuset_t *cpuset, pmix_bind_envelope_t ref) { int rc, flag; if (NULL != cpuset->source && 0 != strncasecmp(cpuset->source, "hwloc", 5)) { return PMIX_ERR_TAKE_NEXT_OPTION; } if (PMIX_CPUBIND_PROCESS == ref) { flag = HWLOC_CPUBIND_PROCESS; } else if (PMIX_CPUBIND_THREAD == ref) { flag = HWLOC_CPUBIND_THREAD; } else { return PMIX_ERR_BAD_PARAM; } cpuset->bitmap = hwloc_bitmap_alloc(); if (NULL != testcpuset) { rc = hwloc_bitmap_sscanf(cpuset->bitmap, testcpuset); } else { rc = hwloc_get_cpubind(pmix_globals.topology.topology, cpuset->bitmap, flag); } if (0 != rc) { hwloc_bitmap_free(cpuset->bitmap); cpuset->bitmap = NULL; return PMIX_ERR_NOT_FOUND; } if (NULL == cpuset->source) { cpuset->source = strdup("hwloc"); } return PMIX_SUCCESS; } static hwloc_obj_t dsearch(hwloc_topology_t t, int depth, hwloc_cpuset_t cpuset) { hwloc_obj_t obj; unsigned width, w; /* get the width of the topology at this depth */ width = hwloc_get_nbobjs_by_depth(t, depth); if (0 == width) { return NULL; } /* scan all objects at this depth to see if * the location is under one of them */ for (w = 0; w < width; w++) { /* get the object at this depth/index */ obj = hwloc_get_obj_by_depth(t, depth, w); /* if this object doesn't have a cpuset, then ignore it */ if (NULL == obj->cpuset) { continue; } /* see if the provided cpuset is completely included in this object */ if (hwloc_bitmap_isincluded(cpuset, obj->cpuset)) { return obj; } } return NULL; } typedef struct { pmix_list_item_t super; pmix_device_distance_t dist; } pmix_devdist_item_t; static void dvcon(pmix_devdist_item_t *p) { PMIX_DEVICE_DIST_CONSTRUCT(&p->dist); } static void dvdes(pmix_devdist_item_t *p) { PMIX_DEVICE_DIST_DESTRUCT(&p->dist); } static PMIX_CLASS_INSTANCE(pmix_devdist_item_t, pmix_list_item_t, dvcon, dvdes); typedef struct { hwloc_obj_osdev_type_t hwtype; pmix_device_type_t pxtype; char *name; } pmix_type_conversion_t; static pmix_type_conversion_t table[] = { {.hwtype = HWLOC_OBJ_OSDEV_BLOCK, .pxtype = PMIX_DEVTYPE_BLOCK, .name = "BLOCK"}, {.hwtype = HWLOC_OBJ_OSDEV_GPU, .pxtype = PMIX_DEVTYPE_GPU, .name = "GPU"}, {.hwtype = HWLOC_OBJ_OSDEV_NETWORK, .pxtype = PMIX_DEVTYPE_NETWORK, .name = "NETWORK"}, {.hwtype = HWLOC_OBJ_OSDEV_OPENFABRICS, .pxtype = PMIX_DEVTYPE_OPENFABRICS, .name = "OPENFABRICS"}, {.hwtype = HWLOC_OBJ_OSDEV_DMA, .pxtype = PMIX_DEVTYPE_DMA, .name = "DMA"}, {.hwtype = HWLOC_OBJ_OSDEV_COPROC, .pxtype = PMIX_DEVTYPE_COPROC, .name = "COPROCESSOR"}, }; static int countcolons(char *str) { int cnt = 0; char *p; p = strchr(str, ':'); while (NULL != p) { ++cnt; ++p; p = strchr(p, ':'); } return cnt; } pmix_status_t pmix_hwloc_compute_distances(pmix_topology_t *topo, pmix_cpuset_t *cpuset, pmix_info_t info[], size_t ninfo, pmix_device_distance_t **dist, size_t *ndist) { hwloc_obj_t obj = NULL; hwloc_obj_t tgt; hwloc_obj_t device; hwloc_obj_t ancestor; hwloc_obj_t pu; unsigned dp, depth; unsigned maxdist = 0; unsigned mindist = UINT_MAX; unsigned i; pmix_list_t dists; pmix_devdist_item_t *d; pmix_device_distance_t *array; size_t n, ntypes, dn; int cnt; unsigned w, width, pudepth; pmix_device_type_t type = 0; char **devids = NULL; bool found; if (NULL == topo->source || NULL == cpuset->source) { return PMIX_ERR_BAD_PARAM; } if (0 != strncasecmp(topo->source, "hwloc", 5) || 0 != strncasecmp(cpuset->source, "hwloc", 5)) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* set default returns */ *dist = NULL; *ndist = 0; /* determine number of types we support */ ntypes = sizeof(table) / sizeof(pmix_type_conversion_t); /* determine what they want us to look at */ if (NULL == info) { /* find everything */ for (n = 0; n < ntypes; n++) { type |= table[n].pxtype; } } else { for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_DEVICE_TYPE)) { type |= info[n].value.data.devtype; } else if (PMIX_CHECK_KEY(&info[n], PMIX_DEVICE_ID)) { PMIx_Argv_append_nosize(&devids, info[n].value.data.string); } } } /* find the max depth of this topology */ depth = hwloc_topology_get_depth(topo->topology); /* get the lowest object that completely covers the cpuset */ for (dp = 1; dp < depth; dp++) { tgt = dsearch(topo->topology, dp, cpuset->bitmap); if (NULL == tgt) { /* nothing found at that depth, so we are done */ break; } obj = tgt; } if (NULL == obj) { /* only the entire machine covers this cpuset - typically, * this means we are in some odd container where every * PU is in its own package. There is nothing useful * that can be done here */ return PMIX_ERR_NOT_AVAILABLE; } /* get the PU depth */ pudepth = (unsigned) hwloc_get_type_depth(topo->topology, HWLOC_OBJ_PU); width = hwloc_get_nbobjs_by_depth(topo->topology, pudepth); PMIX_CONSTRUCT(&dists, pmix_list_t); /* loop over the specified devices in the topology */ for (n = 0; n < ntypes; n++) { if (!(type & table[n].pxtype)) { continue; } if (HWLOC_OBJ_OSDEV_BLOCK == table[n].hwtype || HWLOC_OBJ_OSDEV_DMA == table[n].hwtype || HWLOC_OBJ_OSDEV_COPROC == table[n].hwtype ) { continue; } device = hwloc_get_obj_by_type(topo->topology, HWLOC_OBJ_OS_DEVICE, 0); while (NULL != device) { if (device->attr->osdev.type == table[n].hwtype) { d = PMIX_NEW(pmix_devdist_item_t); pmix_list_append(&dists, &d->super); d->dist.type = table[n].pxtype; /* Construct a UUID for this device */ if (HWLOC_OBJ_OSDEV_NETWORK == table[n].hwtype) { char *addr = NULL; /* find the address */ for (i = 0; i < device->infos_count; i++) { if (0 == strcasecmp(device->infos[i].name, "Address")) { addr = device->infos[i].value; break; } } if (NULL == addr) { /* couldn't find an address - report it as an error */ PMIX_LIST_DESTRUCT(&dists); return PMIX_ERROR; } /* could be IPv4 or IPv6 */ cnt = countcolons(addr); if (5 == cnt) { pmix_asprintf(&d->dist.uuid, "ipv4://%s", addr); } else if (19 == cnt) { pmix_asprintf(&d->dist.uuid, "ipv6://%s", addr); } else { /* unknown address type */ PMIX_LIST_DESTRUCT(&dists); return PMIX_ERROR; } } else if (HWLOC_OBJ_OSDEV_OPENFABRICS == table[n].hwtype) { char *ngid = NULL; char *sgid = NULL; /* find the UIDs */ for (i = 0; i < device->infos_count; i++) { if (0 == strcasecmp(device->infos[i].name, "NodeGUID")) { ngid = device->infos[i].value; } else if (0 == strcasecmp(device->infos[i].name, "SysImageGUID")) { sgid = device->infos[i].value; } } if (NULL == ngid || NULL == sgid) { PMIX_LIST_DESTRUCT(&dists); return PMIX_ERROR; } pmix_asprintf(&d->dist.uuid, "fab://%s::%s", ngid, sgid); } else if (HWLOC_OBJ_OSDEV_GPU == table[n].hwtype) { /* if the name starts with "card", then this is just the aux card of the GPU */ if (0 == strncasecmp(device->name, "card", 4)) { pmix_list_remove_item(&dists, &d->super); PMIX_RELEASE(d); device = hwloc_get_next_osdev(topo->topology, device); continue; } pmix_asprintf(&d->dist.uuid, "gpu://%s::%s", pmix_globals.hostname, device->name); } else { /* unknown type */ pmix_list_remove_item(&dists, &d->super); PMIX_RELEASE(d); device = hwloc_get_next_osdev(topo->topology, device); continue; } /* if device id was given, then check if this one matches either * the UUID or osname */ if (NULL != devids) { found = false; for (dn = 0; NULL != devids[dn]; dn++) { if (0 == strcasecmp(devids[dn], device->name) || 0 == strcasecmp(devids[dn], d->dist.uuid)) { found = true; } } if (!found) { /* skip this one */ pmix_list_remove_item(&dists, &d->super); PMIX_RELEASE(d); device = hwloc_get_next_osdev(topo->topology, device); continue; } } /* save the osname */ d->dist.osname = strdup(device->name); if (NULL == device->cpuset) { /* climb the topology until we find a non-NULL cpuset */ tgt = device->parent; while (NULL != tgt && NULL == tgt->cpuset) { tgt = tgt->parent; } if (NULL == tgt) { PMIX_LIST_DESTRUCT(&dists); return PMIX_ERR_NOT_FOUND; } } else { tgt = device; } /* loop over the PUs on this node */ maxdist = 0; mindist = UINT_MAX; for (w = 0; w < width; w++) { /* get the pu at this index */ pu = hwloc_get_obj_by_depth(topo->topology, pudepth, w); /* is this PU in our cpuset? */ if (!hwloc_bitmap_intersects(pu->cpuset, cpuset->bitmap)) { continue; } /* find the common ancestor between the cpuset and NIC objects */ ancestor = hwloc_get_common_ancestor_obj(topo->topology, obj, tgt); if (NULL != ancestor) { if (0 == ancestor->depth) { /* we only share the machine - need to do something more * to compute the distance. This can, however, get a little * hairy as there is no good measure of package-to-package * distance - it is all typically given in terms of NUMA * domains, which is no longer a valid way of looking at * locations due to overlapping domains. For now, we will * just take the depth of the device in its package and * add that to the depth of the object in its package * plus the depth of a package to ensure it is further away */ dp = obj->depth + depth; } else { /* the depth value can be used as an indicator of relative * locality - the higher the value, the closer the device. * We invert the pyramid to set the dist to be closer for * smaller values */ dp = depth - ancestor->depth; } } else { /* shouldn't happen - consider this an error condition */ PMIX_LIST_DESTRUCT(&dists); return PMIX_ERROR; } if (mindist > dp) { mindist = dp; } if (maxdist < dp) { maxdist = dp; } } d->dist.mindist = mindist; d->dist.maxdist = maxdist; } device = hwloc_get_next_osdev(topo->topology, device); } } /* create the return array */ n = pmix_list_get_size(&dists); if (0 == n) { /* no devices found */ return PMIX_ERR_NOT_FOUND; } PMIX_DEVICE_DIST_CREATE(array, n); *ndist = n; n = 0; PMIX_LIST_FOREACH (d, &dists, pmix_devdist_item_t) { array[n].uuid = strdup(d->dist.uuid); array[n].osname = strdup(d->dist.osname); array[n].type = d->dist.type; array[n].mindist = d->dist.mindist; array[n].maxdist = d->dist.maxdist; ++n; } PMIX_LIST_DESTRUCT(&dists); *dist = array; return PMIX_SUCCESS; } pmix_status_t pmix_hwloc_check_vendor(pmix_topology_t *topo, unsigned short vendorID, uint16_t class) { hwloc_obj_t device; if (NULL == topo->source || 0 != strncasecmp(topo->source, "hwloc", 5)) { return PMIX_ERR_TAKE_NEXT_OPTION; } device = hwloc_get_next_pcidev(topo->topology, NULL); while (NULL != device) { if (class == device->attr->pcidev.class_id && device->attr->pcidev.vendor_id == vendorID) { return PMIX_SUCCESS; } device = hwloc_get_next_pcidev(topo->topology, device); } return PMIX_ERR_NOT_AVAILABLE; } static int set_flags(hwloc_topology_t topo, unsigned int flags) { int ret = hwloc_topology_set_io_types_filter(topo, HWLOC_TYPE_FILTER_KEEP_IMPORTANT); if (0 != ret) { return ret; } if (0 != hwloc_topology_set_flags(topo, flags)) { return PMIX_ERR_INIT; } // Blacklist the "gl" component due to potential conflicts. // See "https://github.com/open-mpi/ompi/issues/10025" for // an explanation. Sadly, HWLOC doesn't define version numbers // until v2.0, so we cannot check versions here. Fortunately, // the blacklist ability was added in HWLOC v2.1, so we can't // do it for earlier versions anyway. hwloc_topology_set_components(topo, HWLOC_TOPOLOGY_COMPONENTS_FLAG_BLACKLIST, "gl"); return PMIX_SUCCESS; } static char *popstr(pmix_cb_t *cb) { pmix_list_t *kvs = &cb->kvs; pmix_kval_t *kv; char *str; if (1 != pmix_list_get_size(kvs)) { return NULL; } kv = (pmix_kval_t *) pmix_list_get_first(kvs); if (PMIX_STRING != kv->value->type) { return NULL; } str = kv->value->data.string; kv->value->data.string = NULL; kv = (pmix_kval_t *) pmix_list_remove_first(kvs); while (NULL != kv) { PMIX_RELEASE(kv); kv = (pmix_kval_t *) pmix_list_remove_first(kvs); } return str; } static size_t popsize(pmix_cb_t *cb) { pmix_list_t *kvs = &cb->kvs; pmix_kval_t *kv; size_t sz; if (1 != pmix_list_get_size(kvs)) { return UINT64_MAX; } kv = (pmix_kval_t *) pmix_list_get_first(kvs); if (PMIX_SIZE != kv->value->type) { return UINT64_MAX; } sz = kv->value->data.size; kv = (pmix_kval_t *) pmix_list_remove_first(kvs); while (NULL != kv) { PMIX_RELEASE(kv); kv = (pmix_kval_t *) pmix_list_remove_first(kvs); } return sz; } static pmix_topology_t *popptr(pmix_cb_t *cb) { pmix_list_t *kvs = &cb->kvs; pmix_kval_t *kv; pmix_topology_t *t; if (1 != pmix_list_get_size(kvs)) { return NULL; } kv = (pmix_kval_t *) pmix_list_get_first(kvs); if (PMIX_TOPO != kv->value->type) { return NULL; } t = kv->value->data.topo; kv->value->data.topo = NULL; kv = (pmix_kval_t *) pmix_list_remove_first(kvs); while (NULL != kv) { PMIX_RELEASE(kv); kv = (pmix_kval_t *) pmix_list_remove_first(kvs); } return t; } static pmix_status_t load_xml(char *xml) { /* load the topology */ if (0 != hwloc_topology_init((hwloc_topology_t *) &pmix_globals.topology.topology)) { return PMIX_ERROR; } if (0 != hwloc_topology_set_xmlbuffer(pmix_globals.topology.topology, xml, strlen(xml) + 1)) { hwloc_topology_destroy(pmix_globals.topology.topology); return PMIX_ERROR; } /* since we are loading this from an external source, we have to * explicitly set a flag so hwloc sets things up correctly */ if (0 != set_flags(pmix_globals.topology.topology, HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)) { hwloc_topology_destroy(pmix_globals.topology.topology); return PMIX_ERROR; } /* now load the topology */ if (0 != hwloc_topology_load(pmix_globals.topology.topology)) { hwloc_topology_destroy(pmix_globals.topology.topology); return PMIX_ERROR; } pmix_globals.topology.source = strdup("hwloc"); // don't know the version? return PMIX_SUCCESS; } static void print_maps(void) { FILE *maps_file = fopen("/proc/self/maps", "r"); if (maps_file) { char line[256]; pmix_output(0, "%s Dumping /proc/self/maps", PMIX_NAME_PRINT(&pmix_globals.myid)); while (fgets(line, sizeof(line), maps_file) != NULL) { char *end = strchr(line, '\n'); if (end) { *end = '\0'; } pmix_output(0, "%s", line); } fclose(maps_file); } } static int get_locality_string_by_depth(int d, hwloc_cpuset_t cpuset, hwloc_cpuset_t result) { hwloc_obj_t obj; unsigned width, w; /* get the width of the topology at this depth */ width = hwloc_get_nbobjs_by_depth(pmix_globals.topology.topology, d); if (0 == width) { return -1; } /* scan all objects at this depth to see if * the location overlaps with them */ for (w = 0; w < width; w++) { /* get the object at this depth/index */ obj = hwloc_get_obj_by_depth(pmix_globals.topology.topology, d, w); /* see if the location intersects with it */ if (hwloc_bitmap_intersects(obj->cpuset, cpuset)) { hwloc_bitmap_set(result, w); } } return 0; } static int enough_space(const char *filename, size_t space_req, uint64_t *space_avail, bool *result) { uint64_t avail = 0; size_t fluff = (size_t)(.05 * space_req); bool enough = false; char *last_sep = NULL; /* the target file name is passed here, but we need to check the parent * directory. store it so we can extract that info later. */ char *target_dir = strdup(filename); int rc; if (NULL == target_dir) { rc = PMIX_ERR_OUT_OF_RESOURCE; goto out; } /* get the parent directory */ last_sep = strrchr(target_dir, PMIX_PATH_SEP[0]); *last_sep = '\0'; /* now check space availability */ if (PMIX_SUCCESS != (rc = pmix_path_df(target_dir, &avail))) { goto out; } /* do we have enough space? */ if (avail >= space_req + fluff) { enough = true; } out: if (NULL != target_dir) { free(target_dir); } *result = enough; *space_avail = avail; return rc; } pmix-6.1.1~rc2/src/hwloc/pmix_hwloc.h0000664000175000017500000001136515203536752017730 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved. * * Copyright (c) 2015-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * This interface is for use by PMIx to obtain topology-related info * */ #ifndef PMIX_HWLOC_H #define PMIX_HWLOC_H #include "src/include/pmix_config.h" #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/mca.h" #include "src/server/pmix_server_ops.h" BEGIN_C_DECLS /** * Register params */ PMIX_EXPORT pmix_status_t pmix_hwloc_register(void); /** * Finalize. Tear down any allocated storage */ PMIX_EXPORT void pmix_hwloc_finalize(void); /* Setup the topology for delivery to clients */ PMIX_EXPORT pmix_status_t pmix_hwloc_setup_topology(pmix_info_t *info, size_t ninfo); /* Load the topology */ PMIX_EXPORT pmix_status_t pmix_hwloc_load_topology(pmix_topology_t *topo); /* Generate the string representation of a cpuset */ PMIX_EXPORT pmix_status_t pmix_hwloc_generate_cpuset_string(const pmix_cpuset_t *cpuset, char **cpuset_string); /* get cpuset from its string representation */ PMIX_EXPORT pmix_status_t pmix_hwloc_parse_cpuset_string(const char *cpuset_string, pmix_cpuset_t *cpuset); /* Get locality string */ PMIX_EXPORT pmix_status_t pmix_hwloc_generate_locality_string(const pmix_cpuset_t *cpuset, char **loc); /* Get relative locality */ PMIX_EXPORT pmix_status_t pmix_hwloc_get_relative_locality(const char *locality1, const char *locality2, pmix_locality_t *loc); /* Get current bound location */ PMIX_EXPORT pmix_status_t pmix_hwloc_get_cpuset(pmix_cpuset_t *cpuset, pmix_bind_envelope_t ref); /* Get distance array */ PMIX_EXPORT pmix_status_t pmix_hwloc_compute_distances(pmix_topology_t *topo, pmix_cpuset_t *cpuset, pmix_info_t info[], size_t ninfo, pmix_device_distance_t **dist, size_t *ndist); PMIX_EXPORT pmix_status_t pmix_hwloc_check_vendor(pmix_topology_t *topo, unsigned short vendorID, uint16_t class); /* cpuset pack/unpack/copy/print functions */ PMIX_EXPORT pmix_status_t pmix_hwloc_pack_cpuset(pmix_buffer_t *buf, pmix_cpuset_t *src, pmix_pointer_array_t *regtypes); PMIX_EXPORT pmix_status_t pmix_hwloc_unpack_cpuset(pmix_buffer_t *buf, pmix_cpuset_t *dest, pmix_pointer_array_t *regtypes); PMIX_EXPORT pmix_status_t pmix_hwloc_copy_cpuset(pmix_cpuset_t *dest, pmix_cpuset_t *src); PMIX_EXPORT char *pmix_hwloc_print_cpuset(pmix_cpuset_t *src); PMIX_EXPORT void pmix_hwloc_destruct_cpuset(pmix_cpuset_t *cpuset); PMIX_EXPORT void pmix_hwloc_release_cpuset(pmix_cpuset_t *ptr, size_t sz); PMIX_EXPORT pmix_status_t pmix_hwloc_get_cpuset_size(pmix_cpuset_t *ptr, size_t *sz); /* topology pack/unpack/copy/print functions */ PMIX_EXPORT pmix_status_t pmix_hwloc_pack_topology(pmix_buffer_t *buf, pmix_topology_t *src, pmix_pointer_array_t *regtypes); PMIX_EXPORT pmix_status_t pmix_hwloc_unpack_topology(pmix_buffer_t *buf, pmix_topology_t *dest, pmix_pointer_array_t *regtypes); PMIX_EXPORT pmix_status_t pmix_hwloc_copy_topology(pmix_topology_t *dest, pmix_topology_t *src); PMIX_EXPORT char *pmix_hwloc_print_topology(pmix_topology_t *src); PMIX_EXPORT void pmix_hwloc_destruct_topology(pmix_topology_t *ptr); PMIX_EXPORT void pmix_hwloc_release_topology(pmix_topology_t *ptr, size_t sz); PMIX_EXPORT pmix_status_t pmix_hwloc_get_topology_size(pmix_topology_t *ptr, size_t *sz); /**** PRESERVE ABI ****/ PMIX_EXPORT void pmix_ploc_base_destruct_cpuset(pmix_cpuset_t *cpuset); PMIX_EXPORT void pmix_ploc_base_release_cpuset(pmix_cpuset_t *ptr, size_t sz); PMIX_EXPORT void pmix_ploc_base_destruct_topology(pmix_topology_t *ptr); PMIX_EXPORT void pmix_ploc_base_release_topology(pmix_topology_t *ptr, size_t sz); END_C_DECLS #endif pmix-6.1.1~rc2/src/hwloc/Makefile.include0000664000175000017500000000055615203536752020470 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ EXTRA_DIST += hwloc/help-ploc.txt headers += \ hwloc/pmix_hwloc.h sources += \ hwloc/pmix_hwloc.c \ hwloc/pmix_hwloc_datatype.c pmix-6.1.1~rc2/src/hwloc/pmix_hwloc_datatype.c0000664000175000017500000003171115203536752021613 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include "pmix_common.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_printf.h" #include "pmix_hwloc.h" pmix_status_t pmix_hwloc_pack_cpuset(pmix_buffer_t *buf, pmix_cpuset_t *src, pmix_pointer_array_t *regtypes) { char *tmp; pmix_status_t rc; if (NULL == src) { /* pack a NULL string */ tmp = NULL; PMIX_BFROPS_PACK_TYPE(rc, buf, &tmp, 1, PMIX_STRING, regtypes); return PMIX_SUCCESS; } if (NULL != src->source && 0 != strncasecmp(src->source, "hwloc", 5)) { return PMIX_ERR_NOT_SUPPORTED; } if (NULL == src->bitmap) { /* the process isn't bound */ tmp = NULL; } else { /* express the cpuset as a string */ if (0 != hwloc_bitmap_list_asprintf(&tmp, src->bitmap)) { return PMIX_ERROR; } } /* pack the string */ PMIX_BFROPS_PACK_TYPE(rc, buf, &tmp, 1, PMIX_STRING, regtypes); free(tmp); return rc; } pmix_status_t pmix_hwloc_unpack_cpuset(pmix_buffer_t *buf, pmix_cpuset_t *dest, pmix_pointer_array_t *regtypes) { pmix_status_t rc; int cnt; char *tmp; /* unpack the cpustring */ cnt = 1; PMIX_BFROPS_UNPACK_TYPE(rc, buf, &tmp, &cnt, PMIX_STRING, regtypes); if (PMIX_SUCCESS != rc) { return rc; } if (NULL == tmp) { dest->bitmap = NULL; } else { /* convert to a bitmap */ dest->bitmap = hwloc_bitmap_alloc(); hwloc_bitmap_list_sscanf(dest->bitmap, tmp); free(tmp); } dest->source = strdup("hwloc"); return PMIX_SUCCESS; } pmix_status_t pmix_hwloc_copy_cpuset(pmix_cpuset_t *dest, pmix_cpuset_t *src) { if (NULL == src->source || 0 != strncasecmp(src->source, "hwloc", 5)) { return PMIX_ERR_NOT_SUPPORTED; } if (NULL == src->bitmap) { return PMIX_ERR_BAD_PARAM; } /* copy the src bitmap */ dest->bitmap = hwloc_bitmap_dup(src->bitmap); dest->source = strdup("hwloc"); return PMIX_SUCCESS; } char *pmix_hwloc_print_cpuset(pmix_cpuset_t *src) { char *tmp; if (NULL == src->source || 0 != strncasecmp(src->source, "hwloc", 5)) { return NULL; } if (NULL == src->bitmap) { return NULL; } /* express the cpuset as a string */ if (0 != hwloc_bitmap_list_asprintf(&tmp, src->bitmap)) { return NULL; } return tmp; } void pmix_hwloc_destruct_cpuset(pmix_cpuset_t *src) { if (NULL == src || NULL == src->source || 0 != strncasecmp(src->source, "hwloc", 5)) { return; } if (NULL != src->bitmap) { hwloc_bitmap_free(src->bitmap); src->bitmap = NULL; } free(src->source); src->source = NULL; } // avoid ABI break void pmix_ploc_base_destruct_cpuset(pmix_cpuset_t *cpuset) { pmix_hwloc_destruct_cpuset(cpuset); return; } void pmix_hwloc_release_cpuset(pmix_cpuset_t *ptr, size_t sz) { size_t n; if (NULL == ptr) { return; } for (n = 0; n < sz; n++) { pmix_hwloc_destruct_cpuset(&ptr[n]); } free(ptr); } // avoid ABI break void pmix_ploc_base_release_cpuset(pmix_cpuset_t *cpuset, size_t n) { pmix_hwloc_release_cpuset(cpuset, n); return; } pmix_status_t pmix_hwloc_get_cpuset_size(pmix_cpuset_t *ptr, size_t *sz) { hwloc_bitmap_t test; PMIX_HIDE_UNUSED_PARAMS(ptr); test = hwloc_bitmap_alloc(); hwloc_bitmap_fill(test); *sz = (size_t)hwloc_bitmap_weight(test); hwloc_bitmap_free(test); return PMIX_SUCCESS; } pmix_status_t pmix_hwloc_pack_topology(pmix_buffer_t *buf, pmix_topology_t *src, pmix_pointer_array_t *regtypes) { /* NOTE: hwloc defines topology_t as a pointer to a struct! */ pmix_status_t rc; char *xmlbuffer = NULL; int len; struct hwloc_topology_support *support; if (NULL == src) { /* pack a NULL string */ PMIX_BFROPS_PACK_TYPE(rc, buf, &xmlbuffer, 1, PMIX_STRING, regtypes); return PMIX_SUCCESS; } if (NULL != src->source && 0 != strncasecmp(src->source, "hwloc", 5)) { return PMIX_ERR_NOT_SUPPORTED; } /* extract an xml-buffer representation of the tree */ if (0 != hwloc_topology_export_xmlbuffer(src->topology, &xmlbuffer, &len, 0)) { return PMIX_ERROR; } /* add to buffer */ PMIX_BFROPS_PACK_TYPE(rc, buf, &xmlbuffer, 1, PMIX_STRING, regtypes); free(xmlbuffer); if (PMIX_SUCCESS != rc) { return rc; } /* get the available support - hwloc unfortunately does * not include this info in its xml export! */ support = (struct hwloc_topology_support *) hwloc_topology_get_support(src->topology); /* pack the discovery support */ PMIX_BFROPS_PACK_TYPE(rc, buf, support->discovery, sizeof(struct hwloc_topology_discovery_support), PMIX_BYTE, regtypes); if (PMIX_SUCCESS != rc) { return rc; } /* pack the cpubind support */ PMIX_BFROPS_PACK_TYPE(rc, buf, support->cpubind, sizeof(struct hwloc_topology_cpubind_support), PMIX_BYTE, regtypes); if (PMIX_SUCCESS != rc) { return rc; } /* pack the membind support */ PMIX_BFROPS_PACK_TYPE(rc, buf, support->membind, sizeof(struct hwloc_topology_membind_support), PMIX_BYTE, regtypes); if (PMIX_SUCCESS != rc) { return rc; } return PMIX_SUCCESS; } pmix_status_t pmix_hwloc_unpack_topology(pmix_buffer_t *buf, pmix_topology_t *dest, pmix_pointer_array_t *regtypes) { /* NOTE: hwloc defines topology_t as a pointer to a struct! */ pmix_status_t rc; char *xmlbuffer = NULL; int cnt; struct hwloc_topology_support *support; hwloc_topology_t t; unsigned long flags; /* unpack the xml string */ cnt = 1; PMIX_BFROPS_UNPACK_TYPE(rc, buf, &xmlbuffer, &cnt, PMIX_STRING, regtypes); if (PMIX_SUCCESS != rc) { return rc; } /* if it is NULL, then return a NULL topology */ if (NULL == xmlbuffer) { dest->source = strdup("hwloc"); dest->topology = NULL; return PMIX_SUCCESS; } /* convert the xml */ if (0 != hwloc_topology_init(&t)) { rc = PMIX_ERROR; free(xmlbuffer); return rc; } if (0 != hwloc_topology_set_xmlbuffer(t, xmlbuffer, strlen(xmlbuffer))) { rc = PMIX_ERROR; free(xmlbuffer); hwloc_topology_destroy(t); return rc; } free(xmlbuffer); /* since we are loading this from an external source, we have to * explicitly set a flag so hwloc sets things up correctly */ flags = HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM; if (0 != hwloc_topology_set_io_types_filter(t, HWLOC_TYPE_FILTER_KEEP_IMPORTANT)) { hwloc_topology_destroy(t); return PMIX_ERROR; } flags |= HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED; if (0 != hwloc_topology_set_flags(t, flags)) { hwloc_topology_destroy(t); return PMIX_ERROR; } /* now load the topology */ if (0 != hwloc_topology_load(t)) { hwloc_topology_destroy(t); return PMIX_ERROR; } /* get the available support - hwloc unfortunately does * not include this info in its xml import! */ support = (struct hwloc_topology_support *) hwloc_topology_get_support(t); cnt = sizeof(struct hwloc_topology_discovery_support); PMIX_BFROPS_UNPACK_TYPE(rc, buf, support->discovery, &cnt, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != rc) { hwloc_topology_destroy(t); return PMIX_ERROR; } cnt = sizeof(struct hwloc_topology_cpubind_support); PMIX_BFROPS_UNPACK_TYPE(rc, buf, support->cpubind, &cnt, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != rc) { hwloc_topology_destroy(t); return PMIX_ERROR; } cnt = sizeof(struct hwloc_topology_membind_support); PMIX_BFROPS_UNPACK_TYPE(rc, buf, support->membind, &cnt, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != rc) { hwloc_topology_destroy(t); return PMIX_ERROR; } dest->source = strdup("hwloc"); dest->topology = (void *) t; return PMIX_SUCCESS; } pmix_status_t pmix_hwloc_copy_topology(pmix_topology_t *dest, pmix_topology_t *src) { if (NULL == src->source || 0 != strncasecmp(src->source, "hwloc", 5)) { return PMIX_ERR_NOT_SUPPORTED; } /* use the hwloc dup function */ if (0 != hwloc_topology_dup((hwloc_topology_t *) &dest->topology, src->topology)) { return PMIX_ERROR; } dest->source = strdup("hwloc"); return PMIX_SUCCESS; } #define PMIX_HWLOC_MAX_STRING 2048 static void print_hwloc_obj(char **output, char *prefix, hwloc_topology_t topo, hwloc_obj_t obj) { hwloc_obj_t obj2; char string[1024], *tmp, *tmp2, *pfx; unsigned i; struct hwloc_topology_support *support; /* print the object type */ hwloc_obj_type_snprintf(string, 1024, obj, 1); pmix_asprintf(&pfx, "\n%s\t", (NULL == prefix) ? "" : prefix); pmix_asprintf(&tmp, "%sType: %s Number of child objects: %u%sName=%s", (NULL == prefix) ? "" : prefix, string, obj->arity, pfx, (NULL == obj->name) ? "NULL" : obj->name); if (0 < hwloc_obj_attr_snprintf(string, 1024, obj, pfx, 1)) { /* print the attributes */ pmix_asprintf(&tmp2, "%s%s%s", tmp, pfx, string); free(tmp); tmp = tmp2; } /* print the cpusets - apparently, some new HWLOC types don't * have cpusets, so protect ourselves here */ if (NULL != obj->cpuset) { hwloc_bitmap_snprintf(string, PMIX_HWLOC_MAX_STRING, obj->cpuset); pmix_asprintf(&tmp2, "%s%sCpuset: %s", tmp, pfx, string); free(tmp); tmp = tmp2; } if (HWLOC_OBJ_MACHINE == obj->type) { /* root level object - add support values */ support = (struct hwloc_topology_support *) hwloc_topology_get_support(topo); pmix_asprintf(&tmp2, "%s%sBind CPU proc: %s%sBind CPU thread: %s", tmp, pfx, (support->cpubind->set_thisproc_cpubind) ? "TRUE" : "FALSE", pfx, (support->cpubind->set_thisthread_cpubind) ? "TRUE" : "FALSE"); free(tmp); tmp = tmp2; pmix_asprintf(&tmp2, "%s%sBind MEM proc: %s%sBind MEM thread: %s", tmp, pfx, (support->membind->set_thisproc_membind) ? "TRUE" : "FALSE", pfx, (support->membind->set_thisthread_membind) ? "TRUE" : "FALSE"); free(tmp); tmp = tmp2; } pmix_asprintf(&tmp2, "%s%s\n", (NULL == *output) ? "" : *output, tmp); free(tmp); free(pfx); pmix_asprintf(&pfx, "%s\t", (NULL == prefix) ? "" : prefix); for (i = 0; i < obj->arity; i++) { obj2 = obj->children[i]; /* print the object */ print_hwloc_obj(&tmp2, pfx, topo, obj2); } free(pfx); if (NULL != *output) { free(*output); } *output = tmp2; } char *pmix_hwloc_print_topology(pmix_topology_t *src) { hwloc_obj_t obj; char *tmp = NULL; if (NULL == src->source || 0 != strncasecmp(src->source, "hwloc", 5)) { return NULL; } /* get root object */ obj = hwloc_get_root_obj(src->topology); /* print it */ print_hwloc_obj(&tmp, NULL, src->topology, obj); return tmp; } void pmix_hwloc_destruct_topology(pmix_topology_t *src) { if (NULL == src || NULL == src->source || 0 != strncasecmp(src->source, "hwloc", 5)) { return; } if (NULL != src->topology) { hwloc_topology_destroy(src->topology); src->topology = NULL; } free(src->source); src->source = NULL; } // avoid ABI break void pmix_ploc_base_destruct_topology(pmix_topology_t *topo) { pmix_hwloc_destruct_topology(topo); return; } void pmix_hwloc_release_topology(pmix_topology_t *src, size_t sz) { size_t n; if (NULL == src) { return; } for (n = 0; n < sz; n++) { pmix_hwloc_destruct_topology(&src[n]); } } // avoid ABI break void pmix_ploc_base_release_topology(pmix_topology_t *topo, size_t n) { pmix_hwloc_release_topology(topo, n); return; } pmix_status_t pmix_hwloc_get_topology_size(pmix_topology_t *ptr, size_t *sz) { int err; err = hwloc_shmem_topology_get_length(ptr->topology, sz, 0); if (0 != err) { *sz = 0; return PMIX_ERROR; } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/hwloc/help-ploc.txt0000664000175000017500000000127015203536752020024 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2018-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is a US/English help file # # [target full] PMIx was unable to create a shared memory backing file due to inadequate available space: File: %s Node: %s Shmem size: %lu Space available: %llu Please set the "PMIX_MCA_gds=hash" environmental variable to disable the shared memory system and try again. # [sys call fail] Node: %s SysCall: %s Error: %s (%d) Please set the "PMIX_MCA_gds=hash" environmental variable to disable the shared memory system and try again. pmix-6.1.1~rc2/src/common/0000775000175000017500000000000015203536752015554 5ustar alastairalastairpmix-6.1.1~rc2/src/common/pmix_pfexec.h0000664000175000017500000001464515203536752020246 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2011-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * The PMIx Fork/Exec Subsystem * */ #ifndef PMIX_PFEXEC_H #define PMIX_PFEXEC_H #include "pmix_config.h" #include "src/class/pmix_list.h" #include "src/common/pmix_iof.h" #include "src/server/pmix_server_ops.h" BEGIN_C_DECLS typedef struct { int usepty; bool connect_stdin; /* private - callers should not modify these fields */ int p_stdin[2]; int p_stdout[2]; int p_stderr[2]; } pmix_pfexec_base_io_conf_t; typedef struct { pmix_list_item_t super; pmix_event_t ev; pmix_proc_t proc; pid_t pid; bool completed; int exitcode; int keepalive[2]; pmix_pfexec_base_io_conf_t opts; pmix_iof_sink_t stdinsink; pmix_iof_read_event_t *stdoutev; pmix_iof_read_event_t *stderrev; } pmix_pfexec_child_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_pfexec_child_t); typedef struct { pmix_event_t *handler; bool active; pmix_list_t children; int timeout_before_sigkill; size_t nextid; bool selected; } pmix_pfexec_globals_t; PMIX_EXPORT extern pmix_pfexec_globals_t pmix_pfexec_globals; typedef struct { pmix_object_t super; pmix_event_t ev; pmix_proc_t *proc; int signal; pmix_lock_t *lock; } pmix_pfexec_signal_caddy_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_pfexec_signal_caddy_t); PMIX_EXPORT int pmix_pfexec_base_open(void); PMIX_EXPORT int pmix_pfexec_register(void); PMIX_EXPORT int pmix_pfexec_base_close(void); PMIX_EXPORT pmix_status_t pmix_pfexec_base_spawn_job(pmix_setup_caddy_t *fcd); PMIX_EXPORT void pmix_pfexec_base_spawn_proc(int sd, short args, void *cbdata); PMIX_EXPORT void pmix_pfexec_base_kill_proc(int sd, short args, void *cbdata); PMIX_EXPORT void pmix_pfexec_base_signal_proc(int sd, short args, void *cbdata); PMIX_EXPORT void pmix_pfexec_check_complete(int sd, short args, void *cbdata); #define PMIX_PFEXEC_SPAWN(fcd) \ do { \ pmix_event_assign(&(fcd->ev), pmix_globals.evbase, -1, EV_WRITE, \ pmix_pfexec_base_spawn_proc, fcd); \ PMIX_POST_OBJECT((fcd)); \ pmix_event_active(&((fcd)->ev), EV_WRITE, 1); \ } while (0) #define PMIX_PFEXEC_KILL(r, lk) \ do { \ pmix_pfexec_signal_caddy_t *scd; \ (scd) = PMIX_NEW(pmix_pfexec_signal_caddy_t); \ (scd)->proc = (r); \ (scd)->lock = (lk); \ pmix_event_assign(&((scd)->ev), pmix_globals.evbase, -1, EV_WRITE, \ pmix_pfexec_base_kill_proc, (scd)); \ PMIX_POST_OBJECT((scd)); \ pmix_event_active(&((scd)->ev), EV_WRITE, 1); \ } while (0) #define PMIX_PFEXEC_SIGNAL(scd, r, nm, fn, lk) \ do { \ pmix_pfexec_signal_caddy_t *scd; \ (scd) = PMIX_NEW(pmix_pfexec_signal_caddy_t); \ (scd)->proc = (r); \ (scd)->signal = (nm); \ (scd)->lock = (lk); \ pmix_event_assign(&((scd)->ev), pmix_globals.evbase, -1, EV_WRITE, \ pmix_pfexec_base_signal_proc, (scd)); \ PMIX_POST_OBJECT((scd)); \ pmix_event_active(&((scd)->ev), EV_WRITE, 1); \ } while (0) typedef struct { pmix_object_t super; pmix_event_t ev; pmix_pfexec_child_t *child; pmix_info_t info[2]; } pmix_pfexec_cmpl_caddy_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_pfexec_cmpl_caddy_t); #define PMIX_PFEXEC_CHK_COMPLETE(c) \ do { \ pmix_pfexec_cmpl_caddy_t *pc = PMIX_NEW(pmix_pfexec_cmpl_caddy_t); \ pc->child = (c); \ pmix_event_assign(&((pc)->ev), pmix_globals.evbase, -1, EV_WRITE, \ pmix_pfexec_check_complete, (pc)); \ PMIX_POST_OBJECT((pc)); \ pmix_event_active(&((pc)->ev), EV_WRITE, 1); \ } while (0) /* * Struct written up the pipe from the child to the parent. */ typedef struct { /* True if the child has died; false if this is just a warning to be printed. */ bool fatal; /* Relevant only if fatal==true */ int exit_status; /* Length of the strings that are written up the pipe after this struct */ int file_str_len; int topic_str_len; int msg_str_len; } pmix_pfexec_pipe_err_msg_t; PMIX_EXPORT pmix_status_t pmix_pfexec_base_setup_child(pmix_pfexec_child_t *child); /* * Max length of strings from the pmix_pfexec_pipe_err_msg_t */ #define PMIX_PFEXEC_MAX_FILE_LEN 511 #define PMIX_PFEXEC_MAX_TOPIC_LEN PMIX_PFEXEC_MAX_FILE_LEN END_C_DECLS #endif /* MCA_PFEXEC_H */ pmix-6.1.1~rc2/src/common/pmix_monitor.c0000664000175000017500000005437415203536752020461 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/pstat/pstat.h" #include "src/mca/ptl/ptl.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/server/pmix_server_ops.h" #include "src/common/pmix_monitor.h" static void query_cbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static void acb(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata); static void relcbfunc(void *cbdata) { pmix_cb_t *cd = (pmix_cb_t *) cbdata; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:monitor release callback"); PMIX_RELEASE(cd); } pmix_status_t PMIx_Process_monitor(const pmix_info_t *monitor, pmix_status_t error, const pmix_info_t directives[], size_t ndirs, pmix_info_t **results, size_t *nresults) { pmix_cb_t cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_globals.debug_output, "%s pmix:monitor called", PMIX_NAME_PRINT(&pmix_globals.myid)); // init return values *results = NULL; *nresults = 0; /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ PMIX_CONSTRUCT(&cb, pmix_cb_t); rc = PMIx_Process_monitor_nb(monitor, error, directives, ndirs, acb, &cb); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&cb); return rc; } /* wait for the operation to complete */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; if (0 < cb.ninfo) { *results = cb.info; *nresults = cb.ninfo; cb.info = NULL; cb.ninfo = 0; } PMIX_DESTRUCT(&cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:monitor completed"); return rc; } static void hostprocess(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_cb_t *cb2 = (pmix_cb_t*)scd->cbdata; pmix_cb_t *cb; pmix_info_t *info; size_t n, k, ninfo; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (cb2->copy) { // the local results are stored in cb2's info array cb = (pmix_cb_t*)cb2->cbdata; // combine the cached data with the new returned data ninfo = cb2->ninfo + scd->ninfo; PMIX_INFO_CREATE(info, ninfo); k = 0; for (n=0; n < cb2->ninfo; n++) { PMIX_INFO_XFER(&info[k], &cb2->info[n]); ++k; } for (n=0; n < scd->ninfo; n++) { PMIX_INFO_XFER(&info[k], &scd->info[n]); ++k; } cb->infocopy = true; // cb simply carries the original info array, so ignore it here // however, cb carries all the user provided cbdata etc, so let // that continue along cb->info = info; cb->ninfo = ninfo; PMIX_RELEASE(cb2); if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } if (NULL == cb->cbfunc.infofn) { PMIX_WAKEUP_THREAD(&cb->lock); } else { cb->cbfunc.infofn(cb->status, cb->info, cb->ninfo, cb->cbdata, relcbfunc, (void*)cb); } return; } // if this isn't a local/remote op, then just locally process the data acb(scd->status, scd->info, scd->ninfo, scd->cbdata, scd->cbfunc.relfn, scd->relcbdata); PMIX_RELEASE(scd); } static void hostcb(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *scd; // this is in the host's thread, so we need to shift it scd = PMIX_NEW(pmix_shift_caddy_t); scd->status = status; scd->cbdata = cbdata; scd->info = info; scd->ninfo = ninfo; scd->cbfunc.relfn = release_fn; scd->relcbdata = release_cbdata; PMIX_THREADSHIFT(scd, hostprocess); } void pmix_monitor_processing(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t*)cbdata, *cb2; pmix_status_t rc, error; pmix_proc_t *procs, proc; pmix_info_t *results; size_t sz, m, n; int k; pmix_peer_t *ptr; pmix_node_pid_t *ppid; char **hostnames; uint32_t *nids; bool local, remote; PMIX_HIDE_UNUSED_PARAMS(sd, args); // the monitor argument is in cb->info // directives are in cb->directives local = false; remote = false; error = cb->status; // see if the requested targets involve our node, or processes on // our local node for (n=0; n < cb->ndirs; n++) { if (PMIx_Check_key(cb->directives[n].key, PMIX_MONITOR_LOCAL_ONLY)) { local = true; remote = false; continue; } if (PMIx_Check_key(cb->directives[n].key, PMIX_MONITOR_TARGET_PROCS)) { // if there are no procs specified, then it is all procs everywhere if (NULL == cb->directives[n].value.data.darray || NULL == cb->directives[n].value.data.darray->array) { local = true; remote = true; continue; } // are any of the procs local? procs = (pmix_proc_t*)cb->directives[n].value.data.darray->array; sz = cb->directives[n].value.data.darray->size; for (m=0; (!local || !remote) && m < sz; m++) { for (k=0; (!local || !remote) && k < pmix_server_globals.clients.size; k++) { ptr = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, k); if (NULL == ptr) { continue; } PMIx_Load_procid(&proc, ptr->info->pname.nspace, ptr->info->pname.rank); if (PMIx_Check_procid(&procs[m], &proc)) { local = true; } else { remote = true; } } } if (local && remote) { continue; } continue; } if (PMIx_Check_key(cb->directives[n].key, PMIX_MONITOR_TARGET_NODES)) { // if there are no hosts specified, then it is all hosts everywhere if (NULL == cb->directives[n].value.data.darray || NULL == cb->directives[n].value.data.darray->array) { local = true; remote = true; continue; } // is our node included? hostnames = (char**)cb->directives[n].value.data.darray->array; sz = cb->directives[n].value.data.darray->size; for (m=0; (!local || !remote) && m < sz; m++) { // see if this node is us if (0 == strcmp(hostnames[m], pmix_globals.hostname)) { local = true; } else { remote = true; } } if (local && remote) { continue; } continue; } if (PMIx_Check_key(cb->directives[n].key, PMIX_MONITOR_TARGET_NODEIDS)) { // if there are no nodeIDs specified, then it is all hosts everywhere if (NULL == cb->directives[n].value.data.darray || NULL == cb->directives[n].value.data.darray->array) { local = true; remote = true; continue; } // is our node included? nids = (uint32_t*)cb->directives[n].value.data.darray->array; sz = cb->directives[n].value.data.darray->size; for (m=0; (!local || !remote) && m < sz; m++) { // see if this node is us if (nids[m] == pmix_globals.nodeid) { local = true; } else { remote = true; } } if (local && remote) { continue; } continue; } if (PMIx_Check_key(cb->directives[n].key, PMIX_MONITOR_TARGET_PIDS)) { // if there are no host/pids specified, then it is all host/pids everywhere if (NULL == cb->directives[n].value.data.darray || NULL == cb->directives[n].value.data.darray->array) { local = true; remote = true; continue; } // is our node included? ppid = (pmix_node_pid_t*)cb->directives[n].value.data.darray->array; sz = cb->directives[n].value.data.darray->size; for (m=0; (!local || !remote) && m < sz; m++) { // see if this node is us if (ppid[m].nodeid == pmix_globals.nodeid || 0 == strcmp(ppid[m].hostname, pmix_globals.hostname)) { local = true; } else { remote = true; } } if (local && remote) { continue; } } } // if it involves other nodes or processes on other nodes, // then we must pass it to the host - check if we can do so if (remote && NULL == pmix_host_server.monitor) { /* nothing we can do */ rc = PMIX_ERR_NOT_SUPPORTED; cb->status = rc; goto complete; } if (!remote) { // we have strictly local participation, so pass it down for processing // and return the results directly to the caller cb->status = pmix_pstat.query(cb->proc, cb->info, error, cb->directives, cb->ndirs, &results, &sz); if (PMIX_SUCCESS != cb->status) { if (NULL != cb->proc) { PMIX_PROC_FREE(cb->proc, 1); } if (cb->infocopy) { PMIX_INFO_FREE(cb->info, cb->ninfo); cb->info = NULL; cb->ninfo = 0; cb->infocopy = false; } goto complete; } // replace the monitor struct with the returned results if (cb->infocopy) { PMIX_INFO_FREE(cb->info, cb->ninfo); } cb->infocopy = true; cb->info = results; cb->ninfo = sz; if (NULL != cb->cbfunc.infofn) { PMIX_RETAIN(cb); cb->cbfunc.infofn(cb->status, cb->info, cb->ninfo, cb->cbdata, relcbfunc, (void*)cb); } else { PMIX_WAKEUP_THREAD(&cb->lock); } } else if (!local) { // strictly remote participation, so pass it up - we already checked // for host-level support pmix_output_verbose(2, pmix_globals.debug_output, "pmix:monitor handed to RM"); cb->status = pmix_host_server.monitor(cb->proc, cb->info, error, cb->directives, cb->ndirs, hostcb, cb); if (PMIX_SUCCESS != cb->status) { if (NULL != cb->proc) { PMIX_PROC_FREE(cb->proc, 1); } if (cb->infocopy) { PMIX_INFO_FREE(cb->info, cb->ninfo); cb->info = NULL; cb->ninfo = 0; cb->infocopy = false; } goto complete; } } else { // we have both local and remote participation, so handle the local // contribution first cb->status = pmix_pstat.query(cb->proc, cb->info, error, cb->directives, cb->ndirs, &results, &sz); if (PMIX_SUCCESS != cb->status) { if (NULL != cb->proc) { PMIX_PROC_FREE(cb->proc, 1); } if (cb->infocopy) { PMIX_INFO_FREE(cb->info, cb->ninfo); cb->info = NULL; cb->ninfo = 0; cb->infocopy = false; } goto complete; } // create a tracking object to hold the local results cb2 = PMIX_NEW(pmix_cb_t); // cache the local results cb2->copy = true; cb2->infocopy = true; cb2->info = results; cb2->ninfo = sz; // cache the original object cb2->cbdata = cb; // now pass it up for distribution cb2->status = pmix_host_server.monitor(cb->proc, cb->info, error, cb->directives, cb->ndirs, hostcb, cb2); if (PMIX_SUCCESS != cb2->status) { PMIX_RELEASE(cb2); PMIX_INFO_FREE(cb->info, cb->ninfo); cb->info = NULL; cb->ninfo = 0; cb->infocopy = false; goto complete; } } // wait for callback return; complete: if (NULL != cb->cbfunc.infofn) { cb->cbfunc.infofn(cb->status, cb->info, cb->ninfo, cb->cbdata, relcbfunc, (void*)cb); } else { PMIX_WAKEUP_THREAD(&cb->lock); } } pmix_status_t PMIx_Process_monitor_nb(const pmix_info_t *monitor, pmix_status_t error, const pmix_info_t directives[], size_t ndirs, pmix_info_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_MONITOR_CMD; pmix_status_t rc; pmix_query_caddy_t *qcd; pmix_cb_t *cb; bool proxy; size_t n; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: monitor_nb called with status %s", PMIx_Error_string(error)); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* sanity check */ if (NULL == monitor) { return PMIX_ERR_BAD_PARAM; } /* if we are the server, then we locally handle this */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { // makes mo sense for server to send heartbeat if (PMIx_Check_key(monitor->key, PMIX_SEND_HEARTBEAT)) { return PMIX_ERR_BAD_PARAM; } // threadshift for internal access cb = PMIX_NEW(pmix_cb_t); PMIX_PROC_CREATE(cb->proc, 1); proxy = false; for (n=0; n < ndirs; n++) { if (PMIx_Check_key(directives[n].key, PMIX_MONITOR_PROXY)) { memcpy(&cb->proc[0], directives[n].value.data.proc, sizeof(pmix_proc_t)); proxy = true; break; } } if (!proxy) { memcpy(&cb->proc[0], &pmix_globals.myid, sizeof(pmix_proc_t)); } cb->nprocs = 1; cb->infocopy = false; cb->info = (pmix_info_t*)monitor; cb->ninfo = 1; cb->status = error; cb->directives = (pmix_info_t*)directives; cb->ndirs = ndirs; if (NULL != cbfunc) { cb->cbfunc.infofn = cbfunc; cb->cbdata = cbdata; } else { cb->cbfunc.infofn = acb; cb->cbdata = cb; } PMIX_THREADSHIFT(cb, pmix_monitor_processing); return PMIX_SUCCESS; } /* non-servers cannot perform the monitoring - we need to send * the request to our server, so check for connection */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } /* if the monitor is PMIX_SEND_HEARTBEAT, then send it */ if (PMIX_CHECK_KEY(monitor, PMIX_SEND_HEARTBEAT)) { PMIx_Heartbeat(); return PMIX_SUCCESS; } /* if we are a client, then relay this request to the server */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the monitor */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, monitor, 1, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the error */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &error, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the directives */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, directives, ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ qcd = PMIX_NEW(pmix_query_caddy_t); qcd->cbfunc = cbfunc; qcd->cbdata = cbdata; /* threadshift to push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, query_cbfunc, (void *) qcd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(qcd); } return rc; } void PMIx_Heartbeat(void) { pmix_buffer_t *msg; pmix_status_t rc; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return; } msg = PMIX_NEW(pmix_buffer_t); if (NULL == msg) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } // threadshift to push msg into our event base for transmission PMIX_PTL_SEND_ONEWAY(rc, pmix_client_globals.myserver, msg, PMIX_PTL_TAG_HEARTBEAT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); } } static void query_cbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; pmix_status_t rc; pmix_cb_t *results; int cnt; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:monitor cback from server with %d bytes", (int) buf->bytes_used); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { /* release the caller */ if (NULL != cd->cbfunc) { cd->cbfunc(PMIX_ERR_COMM_FAILURE, NULL, 0, cd->cbdata, NULL, NULL); } PMIX_RELEASE(cd); return; } results = PMIX_NEW(pmix_cb_t); /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &results->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS != results->status && PMIX_ERR_PARTIAL_SUCCESS != results->status) { goto complete; } /* unpack any returned data */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &results->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < results->ninfo) { results->infocopy = true; PMIX_INFO_CREATE(results->info, results->ninfo); cnt = results->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, results->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } complete: pmix_output_verbose(2, pmix_globals.debug_output, "pmix:monitor cback from server releasing"); /* release the caller */ if (NULL != cd->cbfunc) { cd->cbfunc(results->status, results->info, results->ninfo, cd->cbdata, relcbfunc, results); } else { PMIX_RELEASE(results); } PMIX_RELEASE(cd); } static void acb(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; size_t n; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:monitor acb cback"); cb->status = status; if (0 < ninfo) { // we ignore the info that was provided as that data belongs // to the original caller cb->infocopy = true; PMIX_INFO_CREATE(cb->info, ninfo); cb->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&cb->info[n], &info[n]); } } else { cb->info = NULL; } if (NULL != release_fn) { release_fn(release_cbdata); } if (NULL == cb->cbfunc.infofn) { PMIX_WAKEUP_THREAD(&cb->lock); } else { cb->cbfunc.infofn(cb->status, cb->info, cb->ninfo, cb->cbdata, relcbfunc, (void*)cb); } } pmix-6.1.1~rc2/src/common/pmix_log.c0000664000175000017500000002451315203536752017543 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/plog/base/base.h" #include "src/mca/ptl/base/base.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/server/pmix_server_ops.h" static void opcbfunc(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; cb->status = status; pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:log opcbfunc called"); PMIX_WAKEUP_THREAD(&cb->lock); } static void log_cbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; int32_t m; pmix_status_t rc, status; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:log log_cbfunc called"); /* unpack the return status */ m = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &status, &m, PMIX_STATUS); if (PMIX_SUCCESS != rc) { status = rc; } if (NULL != cd->cbfunc.opcbfn) { cd->cbfunc.opcbfn(status, cd->cbdata); } PMIX_RELEASE(cd); } PMIX_EXPORT pmix_status_t PMIx_Log(const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs) { pmix_cb_t cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "%s pmix:log", PMIX_NAME_PRINT(&pmix_globals.myid)); /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ PMIX_CONSTRUCT(&cb, pmix_cb_t); rc = PMIx_Log_nb(data, ndata, directives, ndirs, opcbfunc, &cb); if (PMIX_SUCCESS == rc) { /* wait for the operation to complete */ PMIX_WAIT_THREAD(&cb.lock); } else { PMIX_DESTRUCT(&cb); if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } return rc; } rc = cb.status; PMIX_DESTRUCT(&cb); pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:log completed"); return rc; } void pmix_log_local_op(int sd, short args, void *cbdata_) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata_; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); /* call down to process the request - the various components * will thread shift as required */ rc = pmix_plog.log(cd->proc, cd->info, cd->ninfo, cd->directives, cd->ndirs); // need to execute the caller's cbfunc to release them if (NULL != cd->cbfunc.opcbfn) { cd->cbfunc.opcbfn(rc, cd->cbdata); } PMIX_PROC_FREE(cd->proc, 1); PMIX_RELEASE(cd); } static void localcbfn(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:log local callback"); if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(status, cb->cbdata); } PMIX_PROC_FREE(cb->proc, 1); cb->proc = NULL; PMIX_RELEASE(cb); } PMIX_EXPORT pmix_status_t PMIx_Log_nb(const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_cmd_t cmd = PMIX_LOG_CMD; pmix_buffer_t *msg; pmix_status_t rc = PMIX_SUCCESS; time_t timestamp = 0; pmix_proc_t *source; bool found = false; pmix_shift_caddy_t *cd; pmix_cb_t *cb; size_t n; pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:log non-blocking"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (0 == ndata || NULL == data) { return PMIX_ERR_BAD_PARAM; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } PMIX_PROC_CREATE(source, 1); /* check the directives - if they requested a timestamp, then * get the time, also look for a source */ if (NULL != directives) { for (n = 0; n < ndirs; n++) { if (0 == strncmp(directives[n].key, PMIX_LOG_GENERATE_TIMESTAMP, PMIX_MAX_KEYLEN)) { if (PMIX_INFO_TRUE(&directives[n])) { /* pickup the timestamp */ timestamp = time(NULL); } } else if (0 == strncmp(directives[n].key, PMIX_LOG_SOURCE, PMIX_MAX_KEYLEN)) { memcpy(source, directives[n].value.data.proc, sizeof(pmix_proc_t)); found = true; } } } if (!found) { memcpy(source, &pmix_globals.myid, sizeof(pmix_proc_t)); } /* if we are a client or tool, pass this request to our * server for execution unless we are not connected */ if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer) || PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { // if we are not connected, then locally process if (!pmix_atomic_check_bool(&pmix_globals.connected)) { goto local; } PMIX_PROC_FREE(source, 1); // don't need this value // otherwise, we send to our server cd = PMIX_NEW(pmix_shift_caddy_t); cd->cbfunc.opcbfn = cbfunc; cd->cbdata = cbdata; msg = PMIX_NEW(pmix_buffer_t); PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } if (!PMIX_PEER_IS_EARLIER(pmix_client_globals.myserver, 3, PMIX_MINOR_WILDCARD, PMIX_RELEASE_WILDCARD)) { /* provide the timestamp - zero will indicate * that it wasn't taken */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, ×tamp, 1, PMIX_TIME); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } } /* pack the number of data entries */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ndata, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } if (0 < ndata) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, data, ndata, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } if (0 < ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, directives, ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } } pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:log sending to server"); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, log_cbfunc, (void *) cd); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd); } return rc; } /* get here if we are a server - if we are not a gateway, then * we don't handle this ourselves if the host support is available */ if (!PMIX_PEER_IS_GATEWAY(pmix_globals.mypeer)) { cb = PMIX_NEW(pmix_cb_t); cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; cb->proc = source; if (NULL != pmix_host_server.log2) { rc = pmix_host_server.log2(cb->proc, data, ndata, directives, ndirs, localcbfn, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_PROC_FREE(source, 1); cb->proc = NULL; PMIX_RELEASE(cb); return rc; } } else if (NULL != pmix_host_server.log) { pmix_host_server.log(cb->proc, data, ndata, directives, ndirs, localcbfn, (void *) cb); } else { // no choice but to process locally goto local; } return PMIX_SUCCESS; } local: pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:log processing locally"); // threadshift this into our own progress thread cd = PMIX_NEW(pmix_shift_caddy_t); cd->info = (pmix_info_t*)data; cd->ninfo = ndata; cd->directives = (pmix_info_t*)directives; cd->ndirs = ndirs; cd->cbfunc.opcbfn = cbfunc; cd->cbdata = cbdata; cd->proc = source; PMIX_THREADSHIFT(cd, pmix_log_local_op); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/common/pmix_query.c0000664000175000017500000004646615203536752020142 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2022 IBM Corporation. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/common/pmix_attributes.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/ptl/base/base.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/server/pmix_server_ops.h" static void relcbfunc(void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:query release callback"); if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } PMIX_RELEASE(cd); } static void query_cbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; pmix_status_t rc, status = PMIX_ERR_UNPACK_FAILURE; int cnt; pmix_info_t *info; size_t n, ninfo; pmix_kval_t *kv; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:query cback from server"); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { return; } /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS != status && PMIX_ERR_PARTIAL_SUCCESS != status) { rc = status; goto complete; } /* unpack any returned data */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); status = rc; goto complete; } if (0 < ninfo) { PMIX_INFO_CREATE(info, ninfo); cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_INFO_FREE(info, ninfo); status = rc; goto complete; } /* add the results to our cache */ for (n = 0; n < ninfo; n++) { PMIX_KVAL_NEW(kv, info[n].key); PMIX_BFROPS_VALUE_XFER(rc, pmix_globals.mypeer, kv->value, &info[n].value); pmix_list_append(&cd->results, &kv->super); } PMIX_INFO_FREE(info, ninfo); } complete: pmix_output_verbose(2, pmix_globals.debug_output, "pmix:query cback from server releasing with status %s", PMIx_Error_string(status)); /* release the caller */ if (NULL != cd->cbfunc) { if (0 < pmix_list_get_size(&cd->results)) { cd->ninfo = pmix_list_get_size(&cd->results); PMIX_INFO_CREATE(cd->info, cd->ninfo); n = 0; PMIX_LIST_FOREACH(kv, &cd->results, pmix_kval_t) { PMIX_LOAD_KEY(cd->info[n].key, kv->key); PMIX_BFROPS_VALUE_XFER(rc, pmix_globals.mypeer, &cd->info[n].value, kv->value); if (PMIX_SUCCESS != rc) { status = rc; } ++n; } } cd->cbfunc(status, cd->info, cd->ninfo, cd->cbdata, relcbfunc, cd); } else { PMIX_RELEASE(cd); } } static void qinfocb(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; size_t n; // transfer the results cd->status = status; if (0 < ninfo) { cd->ninfo = ninfo; PMIX_INFO_CREATE(cd->info, cd->ninfo); for (n=0; n < ninfo; n++) { PMIX_INFO_XFER(&cd->info[n], &info[n]); } } if (NULL != release_fn) { release_fn(release_cbdata); } PMIX_WAKEUP_THREAD(&cd->lock); } static pmix_status_t send_for_help(pmix_query_caddy_t *cd) { pmix_cmd_t cmd = PMIX_QUERY_CMD; pmix_buffer_t *msg; pmix_status_t rc; msg = PMIX_NEW(pmix_buffer_t); PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cd->nqueries, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cd->queries, cd->nqueries, PMIX_QUERY); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } pmix_output_verbose(2, pmix_globals.debug_output, "pmix:query sending to server"); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, query_cbfunc, (void *) cd); return rc; } static void finalstep(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t*)cbdata; pmix_status_t rc, lstat = status; size_t n; pmix_kval_t *kv; // transfer any returned answers for (n = 0; n < ninfo; n++) { PMIX_KVAL_NEW(kv, info[n].key); PMIX_BFROPS_VALUE_XFER(rc, pmix_globals.mypeer, kv->value, &info[n].value); pmix_list_append(&cd->results, &kv->super); } /* construct the final response */ if (NULL != cd->cbfunc) { if (0 < pmix_list_get_size(&cd->results)) { cd->ninfo = pmix_list_get_size(&cd->results); PMIX_INFO_CREATE(cd->info, cd->ninfo); n = 0; PMIX_LIST_FOREACH(kv, &cd->results, pmix_kval_t) { PMIX_LOAD_KEY(cd->info[n].key, kv->key); PMIX_BFROPS_VALUE_XFER(rc, pmix_globals.mypeer, &cd->info[n].value, kv->value); if (PMIX_SUCCESS != rc) { lstat = rc; } ++n; } } cd->cbfunc(lstat, cd->info, cd->ninfo, cd->cbdata, relcbfunc, cd); } if (NULL != release_fn) { release_fn(release_cbdata); } return; } static pmix_status_t request_help(pmix_query_caddy_t *cd) { pmix_status_t rc; /* if our host has support, then we just issue the query and * return the response - but don't pass it back to the host * is the host is a server as that would be a loopback */ if (!cd->host_called && NULL != pmix_host_server.query) { pmix_output_verbose(2, pmix_globals.debug_output, "pmix:query handed to RM"); cd->host_called = true; rc = pmix_host_server.query(&pmix_globals.myid, cd->queries, cd->nqueries, finalstep, (void*)cd); return rc; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } rc = send_for_help(cd); return rc; } static void _local_relcb(void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } PMIX_RELEASE(cd); } void pmix_parse_localquery(int sd, short args, void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; pmix_query_t *queries = cd->queries; size_t nqueries = cd->nqueries; pmix_status_t rc = PMIX_SUCCESS; pmix_cb_t cb; size_t n, p, m; pmix_list_t unresolved; pmix_kval_t *kv, *kvnxt; pmix_proc_t proc; bool rank_given; pmix_querylist_t *qry; PMIX_HIDE_UNUSED_PARAMS(sd, args); // setup the list of unresolved queries PMIX_CONSTRUCT(&unresolved, pmix_list_t); for (n = 0; n < nqueries; n++) { rank_given = false; PMIX_LOAD_PROCID(&proc, NULL, PMIX_RANK_INVALID); for (p = 0; p < queries[n].nqual; p++) { if (PMIX_CHECK_KEY(&queries[n].qualifiers[p], PMIX_PROCID)) { PMIX_LOAD_NSPACE(proc.nspace, queries[n].qualifiers[p].value.data.proc->nspace); proc.rank = queries[n].qualifiers[p].value.data.proc->rank; rank_given = true; } else if (PMIX_CHECK_KEY(&queries[n].qualifiers[p], PMIX_NSPACE)) { PMIX_LOAD_NSPACE(proc.nspace, queries[n].qualifiers[p].value.data.string); } else if (PMIX_CHECK_KEY(&queries[n].qualifiers[p], PMIX_RANK)) { proc.rank = queries[n].qualifiers[p].value.data.rank; rank_given = true; } } /* setup to try a local "get" on the data to see if we already have it */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.copy = false; /* if they are querying about node or app values not directly * associated with a proc (i.e., they didn't specify the proc), * then we obtain those by leaving the proc info as undefined */ if (!rank_given) { proc.rank = PMIX_RANK_UNDEF; cb.proc = &proc; } else { /* set the proc */ if (PMIX_RANK_INVALID == proc.rank && 0 == strlen(proc.nspace)) { /* use our id */ cb.proc = &pmix_globals.myid; } else { if (0 == strlen(proc.nspace)) { /* use our nspace */ PMIX_LOAD_NSPACE(cb.proc->nspace, pmix_globals.myid.nspace); } if (PMIX_RANK_INVALID == proc.rank) { /* user the wildcard rank */ proc.rank = PMIX_RANK_WILDCARD; } cb.proc = &proc; } } /* see if we already have this info */ for (p = 0; NULL != queries[n].keys[p]; p++) { cb.key = queries[n].keys[p]; // Locally resolvable keys if (0 == strcmp(queries[n].keys[p], PMIX_QUERY_STABLE_ABI_VERSION)) { PMIX_KVAL_NEW(kv, cb.key); PMIx_Value_load(kv->value, PMIX_STD_ABI_STABLE_VERSION, PMIX_STRING); pmix_list_append(&cd->results, &kv->super); } else if (0 == strcmp(queries[n].keys[p], PMIX_QUERY_PROVISIONAL_ABI_VERSION)) { PMIX_KVAL_NEW(kv, cb.key); PMIx_Value_load(kv->value, PMIX_STD_ABI_PROVISIONAL_VERSION, PMIX_STRING); pmix_list_append(&cd->results, &kv->super); } else if (0 == strcmp(queries[n].keys[p], PMIX_QUERY_ATTRIBUTE_SUPPORT)) { // supported attrs will be appended to cd->results // any that must be sent for help will be appended to unresolved pmix_attrs_query_support(cd, &queries[n], &unresolved); /* check for request to scan the local node for available * servers the caller could connect to */ } else if (0 == strcmp(queries[n].keys[p], PMIX_QUERY_AVAIL_SERVERS)) { PMIX_THREADSHIFT(cd, pmix_ptl_base_query_servers); return; } else { PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS == rc) { /* need to retain this result */ PMIX_LIST_FOREACH_SAFE (kv, kvnxt, &cb.kvs, pmix_kval_t) { pmix_list_remove_item(&cb.kvs, &kv->super); pmix_list_append(&cd->results, &kv->super); } } else { // cache this as unresolved qry = PMIX_NEW(pmix_querylist_t); PMIX_ARGV_APPEND(rc, qry->query.keys, queries[n].keys[p]); if (0 < queries[n].nqual) { qry->query.nqual = queries[n].nqual; PMIX_INFO_CREATE(qry->query.qualifiers, qry->query.nqual); for (m=0; m < queries[n].nqual; m++) { PMIX_INFO_XFER(&qry->query.qualifiers[m], &queries[n].qualifiers[m]); } } pmix_list_append(&unresolved, &qry->super); } } cb.key = NULL; // protect the key } PMIX_DESTRUCT(&cb); } if (0 == pmix_list_get_size(&unresolved)) { /* if we get here, then all queries were locally * resolved, so construct the results for return */ cd->status = PMIX_SUCCESS; cd->ninfo = pmix_list_get_size(&cd->results); if (0 < cd->ninfo) { PMIX_INFO_CREATE(cd->info, cd->ninfo); n = 0; PMIX_LIST_FOREACH(kv, &cd->results, pmix_kval_t) { PMIX_LOAD_KEY(cd->info[n].key, kv->key); rc = PMIx_Value_xfer(&cd->info[n].value, kv->value); if (PMIX_SUCCESS != rc) { cd->status = rc; PMIX_INFO_FREE(cd->info, cd->ninfo); break; } ++n; } } /* done with the list of unresolved queries */ PMIX_LIST_DESTRUCT(&unresolved); if (NULL != cd->cbfunc) { cd->cbfunc(cd->status, cd->info, cd->ninfo, cd->cbdata, _local_relcb, cd); } return; } // move the unresolved queries into the queries cache PMIX_QUERY_FREE(cd->queries, cd->nqueries); cd->nqueries = pmix_list_get_size(&unresolved); PMIX_QUERY_CREATE(cd->queries, cd->nqueries); n = 0; PMIX_LIST_FOREACH(qry, &unresolved, pmix_querylist_t) { cd->queries[n].keys = PMIx_Argv_copy(qry->query.keys); if (0 < qry->query.nqual) { cd->queries[n].nqual = qry->query.nqual; PMIX_INFO_CREATE(cd->queries[n].qualifiers, cd->queries[n].nqual); for (m=0; m < qry->query.nqual; m++) { PMIX_INFO_XFER(&cd->queries[n].qualifiers[m], &qry->query.qualifiers[m]); } } ++n; } /* ask for help */ rc = request_help(cd); if (PMIX_SUCCESS != rc) { /* if there are some results, then we return them * as "partial success" */ cd->ninfo = pmix_list_get_size(&cd->results); if (0 < cd->ninfo) { rc = PMIX_ERR_PARTIAL_SUCCESS; PMIX_INFO_CREATE(cd->info, cd->ninfo); n = 0; PMIX_LIST_FOREACH(kv, &cd->results, pmix_kval_t) { PMIX_LOAD_KEY(cd->info[n].key, kv->key); rc = PMIx_Value_xfer(&cd->info[n].value, kv->value); if (PMIX_SUCCESS != rc) { cd->status = rc; PMIX_INFO_FREE(cd->info, cd->ninfo); break; } ++n; } if (NULL != cd->cbfunc) { cd->cbfunc(rc, cd->info, cd->ninfo, cd->cbdata, _local_relcb, cd); } } else { /* we have to return the error to the caller */ if (NULL != cd->cbfunc) { cd->cbfunc(rc, NULL, 0, cd->cbdata, _local_relcb, cd); } } } return; /* get here if the request returned PMIX_SUCCESS, which means * that the query is being processed and will call the cbfunc * when complete */ } PMIX_EXPORT pmix_status_t PMIx_Query_info(pmix_query_t queries[], size_t nqueries, pmix_info_t **results, size_t *nresults) { pmix_query_caddy_t *cd; pmix_status_t rc; // setup default response *results = NULL; *nresults = 0; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* pass this to the non-blocking version for processing */ cd = PMIX_NEW(pmix_query_caddy_t); rc = PMIx_Query_info_nb(queries, nqueries, qinfocb, (void*)cd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); return rc; } /* wait for the operation to complete */ PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; if (NULL != cd->info) { *results = cd->info; *nresults = cd->ninfo; cd->info = NULL; cd->ninfo = 0; } PMIX_RELEASE(cd); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:query completed"); return rc; } PMIX_EXPORT pmix_status_t PMIx_Query_info_nb(pmix_query_t queries[], size_t nqueries, pmix_info_cbfunc_t cbfunc, void *cbdata) { pmix_query_caddy_t *cd; size_t n, p; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:query non-blocking"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (0 == nqueries || NULL == queries) { return PMIX_ERR_BAD_PARAM; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* do a quick check of the qualifiers arrays to ensure * the nqual field has been set */ for (n = 0; n < nqueries; n++) { if (NULL != queries[n].qualifiers && 0 == queries[n].nqual) { /* look for the info marked as "end" */ p = 0; while (!(PMIX_INFO_IS_END(&queries[n].qualifiers[p])) && p < SIZE_MAX) { ++p; } if (SIZE_MAX == p) { /* nothing we can do */ return PMIX_ERR_BAD_PARAM; } queries[n].nqual = p; } } /* we get here if a refresh isn't required - need to * threadshift this to access our internal data */ cd = PMIX_NEW(pmix_query_caddy_t); cd->host_called = false; // copy the queries as we will modify them cd->nqueries = nqueries; PMIX_QUERY_CREATE(cd->queries, cd->nqueries); for (n=0; n < nqueries; n++) { cd->queries[n].keys = PMIx_Argv_copy(queries[n].keys); if (0 < queries[n].nqual) { cd->queries[n].nqual = queries[n].nqual; PMIX_INFO_CREATE(cd->queries[n].qualifiers, cd->queries[n].nqual); for (p=0; p < queries[n].nqual; p++) { PMIX_INFO_XFER(&cd->queries[n].qualifiers[p], &queries[n].qualifiers[p]); } } } cd->cbfunc = cbfunc; cd->cbdata = cbdata; PMIX_THREADSHIFT(cd, pmix_parse_localquery); /* regardless of the result of the query, we return * PMIX_SUCCESS here to indicate that the operation * was accepted for processing */ return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/common/pmix_monitor.h0000664000175000017500000000317715203536752020461 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2017 IBM Corporation. All rights reserved. * Copyright (c) 2017 Mellanox Technologies. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * I/O Forwarding Service */ #ifndef PMIX_MONITOR_H #define PMIX_MONITOR_H #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TYPES_H # include #endif #include "pmix_common.h" BEGIN_C_DECLS PMIX_EXPORT void pmix_monitor_processing(int sd, short args, void *cbdata); END_C_DECLS #endif /* PMIX_MONITOR_H */ pmix-6.1.1~rc2/src/common/pmix_alloc.c0000664000175000017500000004721715203536752020062 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2022 IBM Corporation. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/common/pmix_attributes.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/ptl/base/base.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/server/pmix_server_ops.h" typedef struct { pmix_object_t super; pmix_event_t ev; pmix_lock_t lock; pmix_alloc_directive_t directive; pmix_info_t *info; size_t ninfo; pmix_info_t *results; size_t nresults; pmix_info_cbfunc_t cbfunc; void *cbdata; } pmix_alloc_caddy_t; static void acon(pmix_alloc_caddy_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); p->results = NULL; p->nresults = 0; p->cbfunc = NULL; p->cbdata = NULL; } static void ades(pmix_alloc_caddy_t *p) { PMIX_DESTRUCT_LOCK(&p->lock); } static PMIX_CLASS_INSTANCE(pmix_alloc_caddy_t, pmix_object_t, acon, ades); static void acb(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; size_t n; cb->status = status; if (NULL != info) { PMIX_INFO_CREATE(cb->info, ninfo); if (NULL == cb->info) { cb->status = PMIX_ERR_NOMEM; goto done; } cb->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&cb->info[n], &info[n]); } } done: if (NULL != release_fn) { release_fn(release_cbdata); } PMIX_WAKEUP_THREAD(&cb->lock); } static void relcbfunc(void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:alloc release callback"); if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } PMIX_RELEASE(cd); } static void alloc_cbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; pmix_status_t rc; pmix_shift_caddy_t *results; int cnt; size_t n; pmix_kval_t *kv; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:alloc cback from server"); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { return; } results = PMIX_NEW(pmix_shift_caddy_t); /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &results->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); results->status = rc; goto complete; } if (PMIX_SUCCESS != results->status) { goto complete; } /* unpack any returned data */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &results->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); results->status = rc; goto complete; } if (0 < results->ninfo) { PMIX_INFO_CREATE(results->info, results->ninfo); cnt = results->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, results->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); results->status = rc; goto complete; } /* locally cache the results */ for (n = 0; n < results->ninfo; n++) { kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(results->info[n].key); PMIX_VALUE_CREATE(kv->value, 1); PMIX_BFROPS_VALUE_XFER(rc, pmix_globals.mypeer, kv->value, &results->info[n].value); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kv); PMIX_RELEASE(kv); // maintain accounting } } complete: pmix_output_verbose(2, pmix_globals.debug_output, "pmix:alloc cback from server releasing with status %s", PMIx_Error_string(results->status)); /* release the caller */ if (NULL != cd->cbfunc) { cd->cbfunc(results->status, results->info, results->ninfo, cd->cbdata, relcbfunc, results); } PMIX_RELEASE(cd); } PMIX_EXPORT pmix_status_t PMIx_Allocation_request(pmix_alloc_directive_t directive, pmix_info_t *info, size_t ninfo, pmix_info_t **results, size_t *nresults) { pmix_cb_t cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_globals.debug_output, "%s pmix:allocate", PMIX_NAME_PRINT(&pmix_globals.myid)); /* set the default response */ *results = NULL; *nresults = 0; /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ PMIX_CONSTRUCT(&cb, pmix_cb_t); if (PMIX_SUCCESS != (rc = PMIx_Allocation_request_nb(directive, info, ninfo, acb, &cb))) { PMIX_DESTRUCT(&cb); return rc; } /* wait for the operation to complete */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; if (NULL != cb.info) { *results = cb.info; *nresults = cb.ninfo; /* protect the data */ cb.info = NULL; cb.ninfo = 0; } PMIX_DESTRUCT(&cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:allocate completed"); return rc; } static void myrel(void *cbdata) { pmix_alloc_caddy_t *acd = (pmix_alloc_caddy_t*)cbdata; PMIX_RELEASE(acd); } static void mycbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_alloc_caddy_t *acd = (pmix_alloc_caddy_t*)cbdata; if (NULL != acd->cbfunc) { acd->cbfunc(status, info, ninfo, acd->cbdata, myrel, acd); } else { PMIX_RELEASE(acd); } if (NULL != release_fn) { release_fn(release_cbdata); } } static void _allocreq(int sd, short args, void *cbdata) { pmix_alloc_caddy_t *acd = (pmix_alloc_caddy_t*)cbdata; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); rc = pmix_host_server.allocate(&pmix_globals.myid, acd->directive, acd->info, acd->ninfo, mycbfunc, acd); if (PMIX_SUCCESS != rc) { // must not be supported - cannot return OPERATION_SUCCEEDED as there // is no way to return the results if (NULL != acd->cbfunc) { acd->cbfunc(rc, NULL, 0, acd->cbdata, myrel, acd); } else { PMIX_RELEASE(acd); } } } PMIX_EXPORT pmix_status_t PMIx_Allocation_request_nb(pmix_alloc_directive_t directive, pmix_info_t *info, size_t ninfo, pmix_info_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_ALLOC_CMD; pmix_status_t rc; pmix_query_caddy_t *cb; pmix_alloc_caddy_t *acd; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: allocate called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* if we are hosted by the scheduler, then this makes no sense */ if (PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { return PMIX_ERR_NOT_SUPPORTED; } /* if our server is the scheduler, then send it */ if (PMIX_PEER_IS_SCHEDULER(pmix_client_globals.myserver)) { goto sendit; } /* if we are the system controller, then nothing we can do * since the scheduler is not attached */ if (PMIX_PEER_IS_SYS_CTRLR(pmix_globals.mypeer)) { return PMIX_ERR_NOT_SUPPORTED; } /* if we are a server and our host provides an allocate * entry, then pass it up - they might need to forward * it to their system controller or via some outside * path to the scheduler */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && NULL != pmix_host_server.allocate) { pmix_output_verbose(2, pmix_globals.debug_output, "pmix:allocate handed to host"); // need to be in our thread context to perform the upcall acd = PMIX_NEW(pmix_alloc_caddy_t); acd->directive = directive; acd->info = info; acd->ninfo = ninfo; acd->cbfunc = cbfunc; acd->cbdata = cbdata; PMIX_THREADSHIFT(acd, _allocreq); return PMIX_SUCCESS; } sendit: /* for all other cases, we need to send this to someone * if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } /* all other cases, relay this request to our server, which * might (for a tool) actually be the scheduler itself */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the directive */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &directive, 1, PMIX_ALLOC_DIRECTIVE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the info */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_query_caddy_t); cb->cbfunc = cbfunc; cb->cbdata = cbdata; /* threadshift to push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, alloc_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } return rc; } typedef struct { pmix_object_t super; pmix_event_t ev; pmix_resource_block_directive_t directive; char *block; const pmix_resource_unit_t *units; size_t nunits; const pmix_info_t *info; size_t ninfo; pmix_op_cbfunc_t cbfunc; void *cbdata; } pmix_rb_caddy_t; static void rbcon(pmix_rb_caddy_t *p) { p->cbfunc = NULL; p->cbdata = NULL; } static PMIX_CLASS_INSTANCE(pmix_rb_caddy_t, pmix_object_t, rbcon, NULL); static void blkcbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; pmix_status_t rc, status; int cnt; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:resource block cback from server"); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { return; } /* unpack the returned status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); status = rc; } /* if we have a cbfunc, execute it */ if (NULL != cd->cbfunc.opcbfn) { cd->cbfunc.opcbfn(status, cd->cbdata); } /* cleanup */ PMIX_RELEASE(cd); } static void opcb(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t*)cbdata; cb->status = status; PMIX_RELEASE_THREAD(&cb->lock); } PMIX_EXPORT pmix_status_t PMIx_Resource_block(pmix_resource_block_directive_t directive, char *block, const pmix_resource_unit_t *units, size_t nunits, const pmix_info_t *info, size_t ninfo) { pmix_cb_t cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_globals.debug_output, "%s pmix:resource block op", PMIX_NAME_PRINT(&pmix_globals.myid)); /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ PMIX_CONSTRUCT(&cb, pmix_cb_t); rc = PMIx_Resource_block_nb(directive, block, units, nunits, info, ninfo, opcb, &cb); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&cb); return rc; } /* wait for the operation to complete */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; PMIX_DESTRUCT(&cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:resource block operation completed"); return rc; } static void _rbreq(int sd, short args, void *cbdata) { pmix_rb_caddy_t *cd = (pmix_rb_caddy_t*)cbdata; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); rc = pmix_host_server.resource_block(&pmix_globals.myid, cd->directive, cd->block, cd->units, cd->nunits, cd->info, cd->ninfo, cd->cbfunc, cd->cbdata); if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } if (NULL != cd->cbfunc) { cd->cbfunc(rc, cd->cbdata); } PMIX_RELEASE(cd); } PMIX_EXPORT pmix_status_t PMIx_Resource_block_nb(pmix_resource_block_directive_t directive, char *block, const pmix_resource_unit_t *units, size_t nunits, const pmix_info_t *info, size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_RESBLK_CMD; pmix_status_t rc; pmix_shift_caddy_t *cb; pmix_rb_caddy_t *cd; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: allocate called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we are hosted by the scheduler, then this makes no sense */ if (PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { return PMIX_ERR_NOT_SUPPORTED; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* if our server is the scheduler, then send it */ if (PMIX_PEER_IS_SCHEDULER(pmix_client_globals.myserver)) { goto sendit; } /* if we are the system controller, then nothing we can do * since the scheduler is not attached */ if (PMIX_PEER_IS_SYS_CTRLR(pmix_globals.mypeer)) { return PMIX_ERR_NOT_SUPPORTED; } /* if we are a server and our host provides a resource block * entry, then pass it up - they might need to forward * it to their system controller or via some outside * path to the scheduler */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && NULL != pmix_host_server.resource_block) { pmix_output_verbose(2, pmix_globals.debug_output, "pmix:resource_block handed to host"); cd = PMIX_NEW(pmix_rb_caddy_t); cd->directive = directive; cd->block = block; cd->units = units; cd->nunits = nunits; cd->info = info; cd->ninfo = ninfo; cd->cbfunc = cbfunc; cd->cbdata = cbdata; PMIX_THREADSHIFT(cd, _rbreq); return PMIX_SUCCESS; } sendit: /* for all other cases, we need to send this to someone * if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } /* all other cases, relay this request to our server */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the directive */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &directive, 1, PMIX_RESBLOCK_DIRECTIVE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the block name */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &block, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the units */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nunits, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < nunits) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, units, nunits, PMIX_RESOURCE_UNIT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* pack the info */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_shift_caddy_t); cb->cbfunc.opcbfn = cbfunc; cb->cbdata = cbdata; /* threadshift to push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, blkcbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } return rc; } pmix-6.1.1~rc2/src/common/pmix_strings.c0000664000175000017500000003601115203536752020447 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2012 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_STRING_H # include #endif #include #include #ifdef HAVE_STDLIB_H # include #endif #include "pmix_common.h" #include "src/common/pmix_attributes.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_printf.h" PMIX_EXPORT const char *PMIx_Proc_state_string(pmix_proc_state_t state) { switch (state) { case PMIX_PROC_STATE_UNDEF: return "UNDEFINED"; case PMIX_PROC_STATE_PREPPED: return "PREPPED FOR LAUNCH"; case PMIX_PROC_STATE_LAUNCH_UNDERWAY: return "LAUNCH UNDERWAY"; case PMIX_PROC_STATE_RESTART: return "PROC READY FOR RESTART"; case PMIX_PROC_STATE_TERMINATE: return "PROC MARKED FOR TERMINATION"; case PMIX_PROC_STATE_RUNNING: return "PROC EXECUTING"; case PMIX_PROC_STATE_CONNECTED: return "PROC HAS CONNECTED TO LOCAL PMIX SERVER"; case PMIX_PROC_STATE_UNTERMINATED: return "PROC HAS NOT TERMINATED"; case PMIX_PROC_STATE_TERMINATED: return "PROC HAS TERMINATED"; case PMIX_PROC_STATE_ERROR: return "PROC ERROR"; case PMIX_PROC_STATE_KILLED_BY_CMD: return "PROC KILLED BY CMD"; case PMIX_PROC_STATE_ABORTED: return "PROC ABNORMALLY ABORTED"; case PMIX_PROC_STATE_FAILED_TO_START: return "PROC FAILED TO START"; case PMIX_PROC_STATE_ABORTED_BY_SIG: return "PROC ABORTED BY SIGNAL"; case PMIX_PROC_STATE_TERM_WO_SYNC: return "PROC TERMINATED WITHOUT CALLING PMIx_Finalize"; case PMIX_PROC_STATE_COMM_FAILED: return "PROC LOST COMMUNICATION"; case PMIX_PROC_STATE_SENSOR_BOUND_EXCEEDED: return "PROC SENSOR BOUND EXCEEDED"; case PMIX_PROC_STATE_CALLED_ABORT: return "PROC CALLED PMIx_Abort"; case PMIX_PROC_STATE_HEARTBEAT_FAILED: return "PROC FAILED TO REPORT HEARTBEAT"; case PMIX_PROC_STATE_MIGRATING: return "PROC WAITING TO MIGRATE"; case PMIX_PROC_STATE_CANNOT_RESTART: return "PROC CANNOT BE RESTARTED"; case PMIX_PROC_STATE_TERM_NON_ZERO: return "PROC TERMINATED WITH NON-ZERO STATUS"; case PMIX_PROC_STATE_FAILED_TO_LAUNCH: return "PROC FAILED TO LAUNCH"; default: return "UNKNOWN STATE"; } } PMIX_EXPORT const char *PMIx_Scope_string(pmix_scope_t scope) { switch (scope) { case PMIX_SCOPE_UNDEF: return "UNDEFINED"; case PMIX_LOCAL: return "SHARE ON LOCAL NODE ONLY"; case PMIX_REMOTE: return "SHARE ON REMOTE NODES ONLY"; case PMIX_GLOBAL: return "SHARE ACROSS ALL NODES"; case PMIX_INTERNAL: return "STORE INTERNALLY"; default: return "UNKNOWN SCOPE"; } } PMIX_EXPORT const char *PMIx_Persistence_string(pmix_persistence_t persist) { switch (persist) { case PMIX_PERSIST_INDEF: return "INDEFINITE"; case PMIX_PERSIST_FIRST_READ: return "DELETE ON FIRST ACCESS"; case PMIX_PERSIST_PROC: return "RETAIN UNTIL PUBLISHING PROCESS TERMINATES"; case PMIX_PERSIST_APP: return "RETAIN UNTIL APPLICATION OF PUBLISHING PROCESS TERMINATES"; case PMIX_PERSIST_SESSION: return "RETAIN UNTIL ALLOCATION OF PUBLISHING PROCESS TERMINATES"; case PMIX_PERSIST_INVALID: return "INVALID"; default: return "UNKNOWN PERSISTENCE"; } } PMIX_EXPORT const char *PMIx_Data_range_string(pmix_data_range_t range) { switch (range) { case PMIX_RANGE_UNDEF: return "UNDEFINED"; case PMIX_RANGE_RM: return "INTENDED FOR HOST RESOURCE MANAGER ONLY"; case PMIX_RANGE_LOCAL: return "AVAIL ON LOCAL NODE ONLY"; case PMIX_RANGE_NAMESPACE: return "AVAIL TO PROCESSES IN SAME JOB ONLY"; case PMIX_RANGE_SESSION: return "AVAIL TO PROCESSES IN SAME ALLOCATION ONLY"; case PMIX_RANGE_GLOBAL: return "AVAIL TO ANYONE WITH AUTHORIZATION"; case PMIX_RANGE_CUSTOM: return "AVAIL AS SPECIFIED IN DIRECTIVES"; case PMIX_RANGE_PROC_LOCAL: return "AVAIL ON LOCAL PROC ONLY"; case PMIX_RANGE_INVALID: return "INVALID"; default: return "UNKNOWN"; } } PMIX_EXPORT char *PMIx_Info_directives_string(pmix_info_directives_t directives) { char **tmp = NULL; char *ret; if (PMIX_INFO_QUALIFIER & directives) { PMIx_Argv_append_nosize(&tmp, "QUALIFIER"); } else { if (PMIX_INFO_REQD & directives) { PMIx_Argv_append_nosize(&tmp, "REQUIRED"); } else { PMIx_Argv_append_nosize(&tmp, "OPTIONAL"); } if (PMIX_INFO_REQD_PROCESSED & directives) { PMIx_Argv_append_nosize(&tmp, "PROCESSED"); } if (PMIX_INFO_ARRAY_END & directives) { PMIx_Argv_append_nosize(&tmp, "END"); } } if (NULL != tmp) { ret = PMIx_Argv_join(tmp, ':'); PMIx_Argv_free(tmp); } else { ret = strdup("UNSPECIFIED"); } return ret; } PMIX_EXPORT const char *PMIx_Alloc_directive_string(pmix_alloc_directive_t directive) { switch (directive) { case PMIX_ALLOC_NEW: return "NEW"; case PMIX_ALLOC_EXTEND: return "EXTEND"; case PMIX_ALLOC_RELEASE: return "RELEASE"; case PMIX_ALLOC_REAQUIRE: return "REACQUIRE"; default: return "UNSPECIFIED"; } } PMIX_EXPORT const char *PMIx_Resource_block_directive_string(pmix_resource_block_directive_t directive) { switch (directive) { case PMIX_RESOURCE_BLOCK_DEFINE: return "DEFINE"; case PMIX_RESOURCE_BLOCK_EXTEND: return "EXTEND"; case PMIX_RESOURCE_BLOCK_REMOVE: return "REMOVE"; case PMIX_RESOURCE_BLOCK_DELETE: return "DELETE"; default: return "UNSPECIFIED"; } } PMIX_EXPORT const char *pmix_command_string(pmix_cmd_t cmd) { switch (cmd) { case PMIX_REQ_CMD: return "REQUEST INIT INFO"; case PMIX_ABORT_CMD: return "ABORT"; case PMIX_COMMIT_CMD: return "COMMIT"; case PMIX_FENCENB_CMD: return "FENCE"; case PMIX_GETNB_CMD: return "GET"; case PMIX_FINALIZE_CMD: return "FINALIZE"; case PMIX_PUBLISHNB_CMD: return "PUBLISH"; case PMIX_LOOKUPNB_CMD: return "LOOKUP"; case PMIX_UNPUBLISHNB_CMD: return "UNPUBLISH"; case PMIX_SPAWNNB_CMD: return "SPAWN"; case PMIX_CONNECTNB_CMD: return "CONNECT"; case PMIX_DISCONNECTNB_CMD: return "DISCONNECT"; case PMIX_NOTIFY_CMD: return "NOTIFY"; case PMIX_REGEVENTS_CMD: return "REGISTER EVENT HANDLER"; case PMIX_DEREGEVENTS_CMD: return "DEREGISTER EVENT HANDLER"; case PMIX_QUERY_CMD: return "QUERY"; case PMIX_LOG_CMD: return "LOG"; case PMIX_ALLOC_CMD: return "ALLOCATE"; case PMIX_JOB_CONTROL_CMD: return "JOB CONTROL"; case PMIX_MONITOR_CMD: return "MONITOR"; case PMIX_IOF_PUSH_CMD: return "IOF PUSH"; case PMIX_IOF_PULL_CMD: return "IOF PULL"; case PMIX_GROUP_CONSTRUCT_CMD: return "GROUP CONSTRUCT"; case PMIX_GROUP_JOIN_CMD: return "GROUP JOIN"; case PMIX_GROUP_INVITE_CMD: return "GROUP INVITE"; case PMIX_GROUP_LEAVE_CMD: return "GROUP LEAVE"; case PMIX_GROUP_DESTRUCT_CMD: return "GROUP DESTRUCT"; case PMIX_IOF_DEREG_CMD: return "IOF DEREG"; case PMIX_FABRIC_REGISTER_CMD: return "FABRIC REGISTER"; case PMIX_FABRIC_UPDATE_CMD: return "FABRIC UPDATE"; case PMIX_COMPUTE_DEVICE_DISTANCES_CMD: return "COMPUTE DEVICE DIST"; case PMIX_REFRESH_CACHE: return "REFRESH CACHE"; case PMIX_RESBLK_CMD: return "RESOURCE BLOCK"; case PMIX_SESSION_CTRL_CMD: return "SESSION CONTROL"; case PMIX_REQ_SYSINFO_CMD: return "REQUEST SYSTEM INFO"; case PMIX_RESOLVE_PEERS_CMD: return "RESOLVE PEERS"; case PMIX_RESOLVE_NODE_CMD: return "RESOLVE NODE"; default: return "UNKNOWN"; } } /* this is not a thread-safe implementation. To correctly implement this, * we need to port the thread-safe data code from OPAL and use it here */ static char answer[300]; PMIX_EXPORT const char *PMIx_IOF_channel_string(pmix_iof_channel_t channel) { size_t cnt = 0; if (PMIX_FWD_STDIN_CHANNEL & channel) { strcpy(&answer[cnt], "STDIN "); cnt += strlen("STDIN "); } if (PMIX_FWD_STDOUT_CHANNEL & channel) { strcpy(&answer[cnt], "STDOUT "); cnt += strlen("STDOUT "); } if (PMIX_FWD_STDERR_CHANNEL & channel) { strcpy(&answer[cnt], "STDERR "); cnt += strlen("STDERR "); } if (PMIX_FWD_STDDIAG_CHANNEL & channel) { strcpy(&answer[cnt], "STDDIAG "); cnt += strlen("STDDIAG "); } if (0 == cnt) { strcpy(&answer[cnt], "NONE"); } return answer; } PMIX_EXPORT const char *PMIx_Job_state_string(pmix_job_state_t state) { switch (state) { case PMIX_JOB_STATE_UNDEF: return "UNDEFINED"; case PMIX_JOB_STATE_PREPPED: return "PREPPED FOR LAUNCH"; case PMIX_JOB_STATE_LAUNCH_UNDERWAY: return "LAUNCHING"; case PMIX_JOB_STATE_RUNNING: return "RUNNING"; case PMIX_JOB_STATE_SUSPENDED: return "SUSPENDED"; case PMIX_JOB_STATE_CONNECTED: return "CONNECTED"; case PMIX_JOB_STATE_UNTERMINATED: return "UNTERMINATED"; case PMIX_JOB_STATE_TERMINATED: return "TERMINATED"; case PMIX_JOB_STATE_TERMINATED_WITH_ERROR: return "TERMINATED WITH ERROR"; default: return "UNKNOWN"; } } PMIX_EXPORT const char *PMIx_Get_attribute_string(const char *attribute) { return pmix_attributes_lookup(attribute); } PMIX_EXPORT const char *PMIx_Get_attribute_name(const char *attrstring) { return pmix_attributes_reverse_lookup(attrstring); } PMIX_EXPORT const char *PMIx_Link_state_string(pmix_link_state_t state) { switch (state) { case PMIX_LINK_STATE_UNKNOWN: return "UNKNOWN"; case PMIX_LINK_DOWN: return "INACTIVE"; case PMIX_LINK_UP: return "ACTIVE"; default: return "UNKNOWN"; } } const char *PMIx_Device_type_string(pmix_device_type_t type) { switch (type) { case PMIX_DEVTYPE_UNKNOWN: return "UNKNOWN"; case PMIX_DEVTYPE_BLOCK: return "BLOCK"; case PMIX_DEVTYPE_GPU: return "GPU"; case PMIX_DEVTYPE_NETWORK: return "NETWORK"; case PMIX_DEVTYPE_OPENFABRICS: return "OPENFABRICS"; case PMIX_DEVTYPE_DMA: return "DMA"; case PMIX_DEVTYPE_COPROC: return "COPROCESSOR"; default: return "UNKNOWN"; } } const char* PMIx_Value_comparison_string(pmix_value_cmp_t cmp) { switch (cmp) { case PMIX_EQUAL: return "EQUAL"; case PMIX_VALUE1_GREATER: return "VALUE1 GREATER"; case PMIX_VALUE2_GREATER: return "VALUE2 GREATER"; case PMIX_VALUE_TYPE_DIFFERENT: return "DIFFERENT TYPES"; case PMIX_VALUE_COMPARISON_NOT_AVAIL: return "COMPARISON NOT AVAILABLE"; case PMIX_VALUE_INCOMPATIBLE_OBJECTS: return "INCOMPATIBLE OBJECTS"; default: return "UNKNOWN VALUE"; } } char* PMIx_App_string(const pmix_app_t *app) { char **ans = NULL; char *tmp, *str; size_t n; pmix_status_t rc; /* add the command */ pmix_asprintf(&tmp, "CMD: %s", app->cmd); PMIx_Argv_append_nosize(&ans, tmp); free(tmp); /* add the argv */ PMIx_Argv_append_nosize(&ans, " ARGV:"); if (NULL == app->argv) { PMIx_Argv_append_nosize(&ans, " NONE"); } else { for (n=0; NULL != app->argv[n]; n++) { pmix_asprintf(&tmp, " ARGV[%d]: %s", (int)n, app->argv[n]); PMIx_Argv_append_nosize(&ans, tmp); free(tmp); } } /* add the env */ PMIx_Argv_append_nosize(&ans, " ENV:"); if (NULL == app->env) { PMIx_Argv_append_nosize(&ans, " NONE"); } else { for (n=0; NULL != app->env[n]; n++) { pmix_asprintf(&tmp, " ENV[%d]: %s", (int)n, app->env[n]); PMIx_Argv_append_nosize(&ans, tmp); free(tmp); } } /* add the cwd */ if (NULL == app->cwd) { PMIx_Argv_append_nosize(&ans, " CWD: NULL"); } else { pmix_asprintf(&tmp, " CWD: %s", app->cwd); PMIx_Argv_append_nosize(&ans, tmp); free(tmp); } /* add the maxprocs */ pmix_asprintf(&tmp, " MAXPROCS: %d", app->maxprocs); PMIx_Argv_append_nosize(&ans, tmp); free(tmp); /* add any info */ if (NULL == app->info) { PMIx_Argv_append_nosize(&ans, " INFO: NONE"); } else { PMIx_Argv_append_nosize(&ans, " INFO:"); for (n=0; n < app->ninfo; n++) { rc = pmix_bfrops_base_print_info(&str, NULL, (void*)&app->info[n], PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIx_Argv_free(ans); return NULL; } pmix_asprintf(&tmp, " INFO[%d]: %s", (int)n, str); PMIx_Argv_append_nosize(&ans, tmp); free(tmp); free(str); } } tmp = PMIx_Argv_join(ans, '\n'); PMIx_Argv_free(ans); return tmp; } char* PMIx_Proc_string(const pmix_proc_t *proc) { char *tmp, *result; tmp = pmix_util_print_name_args(proc); result = strdup(tmp); return result; } char* PMIx_Resource_unit_string(const pmix_resource_unit_t *p) { char *tmp; pmix_asprintf(&tmp, "TYPE: %s COUNT: %" PRIsize_t "", PMIx_Device_type_string(p->type), p->count); return tmp; } const char* PMIx_Group_operation_string(pmix_group_operation_t op) { switch(op) { case PMIX_GROUP_CONSTRUCT: return "CONSTRUCT"; case PMIX_GROUP_DESTRUCT: return "DESTRUCT"; case PMIX_GROUP_NONE: return "NONE"; default: return "UNKNOWN VALUE"; } } pmix-6.1.1~rc2/src/common/pmix_data.c0000664000175000017500000003770515203536752017702 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2012 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_STRING_H # include #endif #include #include #ifdef HAVE_STDLIB_H # include #endif #include "include/pmix.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/pcompress/pcompress.h" #include "src/server/pmix_server_ops.h" #define PMIX_EMBED_DATA_BUFFER(b, db) \ do { \ (b)->type = pmix_globals.mypeer->nptr->compat.type; \ (b)->base_ptr = (db)->base_ptr; \ (b)->pack_ptr = (db)->pack_ptr; \ (b)->unpack_ptr = (db)->unpack_ptr; \ (b)->bytes_allocated = (db)->bytes_allocated; \ (b)->bytes_used = (db)->bytes_used; \ (db)->base_ptr = NULL; \ (db)->pack_ptr = NULL; \ (db)->unpack_ptr = NULL; \ (db)->bytes_allocated = 0; \ (db)->bytes_used = 0; \ } while (0) #define PMIX_EXTRACT_DATA_BUFFER(b, db) \ do { \ (db)->base_ptr = (b)->base_ptr; \ (db)->pack_ptr = (b)->pack_ptr; \ (db)->unpack_ptr = (b)->unpack_ptr; \ (db)->bytes_allocated = (b)->bytes_allocated; \ (db)->bytes_used = (b)->bytes_used; \ (b)->base_ptr = NULL; \ (b)->pack_ptr = NULL; \ (b)->unpack_ptr = NULL; \ (b)->bytes_allocated = 0; \ (b)->bytes_used = 0; \ } while (0) static void _findpeer(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_peer_t *peer; pmix_proc_t wildcard, *proc; pmix_info_t optional; pmix_cb_t cb; pmix_kval_t *kv; int i; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); proc = scd->proc; /* see if we know this proc */ for (i = 0; i < pmix_server_globals.clients.size; i++) { peer = (pmix_peer_t *) pmix_pointer_array_get_item(&pmix_server_globals.clients, i); if (NULL == peer) { continue; } if (PMIx_Check_nspace(proc->nspace, peer->nptr->nspace)) { scd->status = PMIX_SUCCESS; scd->peer = peer; PMIX_WAKEUP_THREAD(&scd->lock); return; } } /* didn't find it, so try to get the library version of the target * from the host - the result will be cached, so we will only have * to retrieve it once */ PMIX_LOAD_PROCID(&wildcard, proc->nspace, PMIX_RANK_WILDCARD); PMIX_INFO_LOAD(&optional, PMIX_OPTIONAL, NULL, PMIX_BOOL); PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &wildcard; cb.key = PMIX_BFROPS_MODULE; cb.info = &optional; cb.ninfo = 1; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS != rc && PMIX_OPERATION_SUCCEEDED != rc) { // couldn't be found scd->status = PMIX_ERR_NOT_FOUND; PMIX_DESTRUCT(&cb); PMIX_WAKEUP_THREAD(&scd->lock); return; } kv = (pmix_kval_t*)pmix_list_remove_first(&cb.kvs); if (NULL == kv) { // should never be NULL scd->status = PMIX_ERR_NOT_FOUND; PMIX_DESTRUCT(&cb); PMIX_WAKEUP_THREAD(&scd->lock); return; } PMIX_DESTRUCT(&cb); /* setup a peer for this nspace */ peer = PMIX_NEW(pmix_peer_t); if (NULL == peer) { PMIX_RELEASE(kv); scd->status = PMIX_ERR_NOMEM; PMIX_WAKEUP_THREAD(&scd->lock); return; } peer->nptr = PMIX_NEW(pmix_namespace_t); if (NULL == peer->nptr) { PMIX_RELEASE(peer); PMIX_RELEASE(kv); scd->status = PMIX_ERR_NOMEM; PMIX_WAKEUP_THREAD(&scd->lock); return; } peer->nptr->nspace = strdup(proc->nspace); /* assign a module to it based on the returned version */ peer->nptr->compat.bfrops = pmix_bfrops_base_assign_module(kv->value->data.string); PMIX_RELEASE(kv); if (NULL == peer->nptr->compat.bfrops) { scd->status = PMIX_ERR_NOMEM; PMIX_RELEASE(peer); PMIX_WAKEUP_THREAD(&scd->lock); return; } /* cache the peer object */ pmix_pointer_array_add(&pmix_server_globals.clients, peer); scd->status = PMIX_SUCCESS; scd->peer = peer; PMIX_WAKEUP_THREAD(&scd->lock); return; } PMIX_EXPORT pmix_status_t PMIx_Data_pack(const pmix_proc_t *target, pmix_data_buffer_t *buffer, void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t rc; pmix_buffer_t buf; pmix_peer_t *peer; pmix_shift_caddy_t scd; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } // if the target is a member of my own nspace, then use our own peer if (NULL == target || PMIx_Check_nspace(target->nspace, pmix_globals.myid.nspace)) { peer = pmix_globals.mypeer; goto execute; } // if the target is my server, use it if (NULL != pmix_client_globals.myserver && PMIx_Check_nspace(target->nspace, pmix_client_globals.myserver->nptr->nspace)) { peer = pmix_client_globals.myserver; goto execute; } // if I am a server, then we need to look for the peer // corresponding to this target if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { // must threadshift this request as it accesses // global data PMIX_CONSTRUCT(&scd, pmix_shift_caddy_t); scd.proc = (pmix_proc_t*)target; PMIX_THREADSHIFT(&scd, _findpeer); PMIX_WAIT_THREAD(&scd.lock); rc = scd.status; if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&scd); return rc; } peer = scd.peer; PMIX_DESTRUCT(&scd); } else { // if I am a client or tool, then we can only talk to the // server, so use that peer peer = pmix_client_globals.myserver; if (NULL == peer) { // we don't have a server return PMIX_ERR_NOT_FOUND; } if (!PMIx_Check_nspace(target->nspace, peer->nptr->nspace)) { // trying to talk to someone we don't know return PMIX_ERR_NOT_FOUND; } } execute: /* setup the host */ PMIX_CONSTRUCT(&buf, pmix_buffer_t); /* embed the data buffer into a buffer */ PMIX_EMBED_DATA_BUFFER(&buf, buffer); /* pack the value */ PMIX_BFROPS_PACK(rc, peer, &buf, src, num_vals, type); /* extract the data buffer - the pointers may have changed */ PMIX_EXTRACT_DATA_BUFFER(&buf, buffer); /* no need to cleanup as all storage was xfered */ return rc; } PMIX_EXPORT pmix_status_t PMIx_Data_unpack(const pmix_proc_t *target, pmix_data_buffer_t *buffer, void *dest, int32_t *max_num_values, pmix_data_type_t type) { pmix_status_t rc; pmix_buffer_t buf; pmix_peer_t *peer; pmix_shift_caddy_t scd; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } // if the target is a member of my own nspace, then use our own peer if (NULL == target || PMIx_Check_nspace(target->nspace, pmix_globals.myid.nspace)) { peer = pmix_globals.mypeer; goto execute; } // if the target is my server, use it if (NULL != pmix_client_globals.myserver && PMIx_Check_nspace(target->nspace, pmix_client_globals.myserver->nptr->nspace)) { peer = pmix_client_globals.myserver; goto execute; } // if I am a server, then we need to look for the peer // corresponding to this target if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { // must threadshift this request as it accesses // global data PMIX_CONSTRUCT(&scd, pmix_shift_caddy_t); scd.proc = (pmix_proc_t*)target; PMIX_THREADSHIFT(&scd, _findpeer); PMIX_WAIT_THREAD(&scd.lock); rc = scd.status; if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&scd); return rc; } peer = scd.peer; PMIX_DESTRUCT(&scd); } else { // if I am a client or tool, then we can only talk to the // server, so use that peer peer = pmix_client_globals.myserver; } execute: /* setup the host */ PMIX_CONSTRUCT(&buf, pmix_buffer_t); /* embed the data buffer into a buffer */ PMIX_EMBED_DATA_BUFFER(&buf, buffer); /* unpack the value */ PMIX_BFROPS_UNPACK(rc, peer, &buf, dest, max_num_values, type); /* extract the data buffer - the pointers may have changed */ PMIX_EXTRACT_DATA_BUFFER(&buf, buffer); /* no need to cleanup as all storage was xfered */ return rc; } PMIX_EXPORT pmix_status_t PMIx_Data_copy(void **dest, void *src, pmix_data_type_t type) { pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* copy the value */ PMIX_BFROPS_COPY(rc, pmix_globals.mypeer, dest, src, type); return rc; } PMIX_EXPORT pmix_status_t PMIx_Data_print(char **output, char *prefix, void *src, pmix_data_type_t type) { pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* print the value */ PMIX_BFROPS_PRINT(rc, pmix_globals.mypeer, output, prefix, src, type); return rc; } PMIX_EXPORT pmix_status_t PMIx_Data_copy_payload(pmix_data_buffer_t *dest, pmix_data_buffer_t *src) { pmix_status_t rc; pmix_buffer_t buf1, buf2; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (NULL == src) { return PMIX_SUCCESS; } /* setup the hosts */ PMIX_CONSTRUCT(&buf1, pmix_buffer_t); PMIX_CONSTRUCT(&buf2, pmix_buffer_t); /* embed the data buffer into a buffer */ PMIX_EMBED_DATA_BUFFER(&buf1, dest); PMIX_EMBED_DATA_BUFFER(&buf2, src); /* copy payload */ PMIX_BFROPS_COPY_PAYLOAD(rc, pmix_globals.mypeer, &buf1, &buf2); /* extract the dest data buffer - the pointers may have changed */ PMIX_EXTRACT_DATA_BUFFER(&buf1, dest); PMIX_EXTRACT_DATA_BUFFER(&buf2, src); /* no need to cleanup as all storage was xfered */ return rc; } pmix_status_t PMIx_Data_unload(pmix_data_buffer_t *buffer, pmix_byte_object_t *payload) { if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* check that buffer is not null */ if (!buffer) { return PMIX_ERR_BAD_PARAM; } /* were we given someplace to point to the payload */ if (NULL == payload) { return PMIX_ERR_BAD_PARAM; } /* init default response */ PMIX_BYTE_OBJECT_CONSTRUCT(payload); /* anything in the buffer - if not, nothing to do */ if (NULL == buffer->base_ptr || 0 == buffer->bytes_used) { return PMIX_SUCCESS; } /* if nothing has been unpacked, we can pass the entire * region back and protect it - no need to copy. This is * an optimization */ if (buffer->unpack_ptr == buffer->base_ptr) { payload->bytes = buffer->base_ptr; payload->size = buffer->bytes_used; buffer->base_ptr = NULL; buffer->bytes_used = 0; goto cleanup; } /* okay, we have something to provide - pass it back */ payload->size = buffer->bytes_used - (buffer->unpack_ptr - buffer->base_ptr); if (0 < payload->size) { /* we cannot just set the pointer as it might be * partway in a malloc'd region */ payload->bytes = (char *) malloc(payload->size); memcpy(payload->bytes, buffer->unpack_ptr, payload->size); } cleanup: /* All done - reset the buffer */ PMIX_DATA_BUFFER_DESTRUCT(buffer); PMIX_DATA_BUFFER_CONSTRUCT(buffer); return PMIX_SUCCESS; } pmix_status_t PMIx_Data_load(pmix_data_buffer_t *buffer, pmix_byte_object_t *payload) { if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* check to see if the buffer has been initialized */ if (NULL == buffer) { return PMIX_ERR_BAD_PARAM; } /* check if buffer already has payload - free it if so */ PMIX_DATA_BUFFER_DESTRUCT(buffer); PMIX_DATA_BUFFER_CONSTRUCT(buffer); /* if it's a NULL payload, just set things and return */ if (NULL == payload) { return PMIX_SUCCESS; } /* populate the buffer */ buffer->base_ptr = payload->bytes; /* set pack/unpack pointers */ buffer->pack_ptr = ((char *) buffer->base_ptr) + payload->size; buffer->unpack_ptr = buffer->base_ptr; /* set counts for size and space */ buffer->bytes_allocated = buffer->bytes_used = payload->size; /* protect the payload */ payload->bytes = NULL; payload->size = 0; /* All done */ return PMIX_SUCCESS; } pmix_status_t PMIx_Data_embed(pmix_data_buffer_t *buffer, const pmix_byte_object_t *payload) { pmix_data_buffer_t src; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* check to see if the buffer has been initialized */ if (NULL == buffer) { return PMIX_ERR_BAD_PARAM; } /* check if buffer already has payload - free it if so */ PMIX_DATA_BUFFER_DESTRUCT(buffer); PMIX_DATA_BUFFER_CONSTRUCT(buffer); /* if it's a NULL payload, we are done */ if (NULL == payload) { return PMIX_SUCCESS; } /* setup the source */ src.base_ptr = payload->bytes; src.pack_ptr = ((char *) src.base_ptr) + payload->size; src.unpack_ptr = src.base_ptr; src.bytes_allocated = src.bytes_used = payload->size; /* execute a copy operation */ rc = PMIx_Data_copy_payload(buffer, &src); /* do NOT destruct the source as that would release * data in the payload */ return rc; } bool PMIx_Data_compress(const uint8_t *inbytes, size_t size, uint8_t **outbytes, size_t *nbytes) { if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (NULL == inbytes) { return PMIX_ERR_BAD_PARAM; } return pmix_compress.compress(inbytes, size, outbytes, nbytes); } bool PMIx_Data_decompress(const uint8_t *inbytes, size_t size, uint8_t **outbytes, size_t *nbytes) { if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (NULL == inbytes) { return PMIX_ERR_BAD_PARAM; } return pmix_compress.decompress(outbytes, nbytes, inbytes, size); } pmix-6.1.1~rc2/src/common/pmix_security.c0000664000175000017500000003772415203536752020641 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/psec/psec.h" #include "src/mca/ptl/ptl.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/server/pmix_server_ops.h" static void getcbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; pmix_status_t rc, status = PMIX_ERR_UNPACK_FAILURE; int cnt; pmix_byte_object_t cred; pmix_info_t *info = NULL; size_t ninfo = 0; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:security cback from server with %d bytes", (int) buf->bytes_used); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { /* release the caller */ if (NULL != cd->credcbfunc) { cd->credcbfunc(PMIX_ERR_COMM_FAILURE, NULL, NULL, 0, cd->cbdata); } PMIX_RELEASE(cd); return; } PMIX_BYTE_OBJECT_CONSTRUCT(&cred); /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS != status) { goto complete; } /* unpack the credential */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cred, &cnt, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } /* unpack any returned info */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < ninfo) { PMIX_INFO_CREATE(info, ninfo); cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } complete: pmix_output_verbose(2, pmix_globals.debug_output, "pmix:security cback from server releasing"); /* release the caller */ if (NULL != cd->credcbfunc) { cd->credcbfunc(status, &cred, info, ninfo, cd->cbdata); } PMIX_BYTE_OBJECT_DESTRUCT(&cred); if (NULL != info) { PMIX_INFO_FREE(info, ninfo); } PMIX_RELEASE(cd); } static void mycdcb(pmix_status_t status, pmix_byte_object_t *credential, pmix_info_t info[], size_t ninfo, void *cbdata) { pmix_query_caddy_t *cb = (pmix_query_caddy_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(info, ninfo); PMIX_ACQUIRE_OBJECT(cb); cb->status = status; if (PMIX_SUCCESS == status && NULL != credential) { cb->bo.bytes = malloc(credential->size); memcpy(cb->bo.bytes, credential->bytes, credential->size); cb->bo.size = credential->size; } PMIX_WAKEUP_THREAD(&cb->lock); } PMIX_EXPORT pmix_status_t PMIx_Get_credential(const pmix_info_t info[], size_t ninfo, pmix_byte_object_t *credential) { pmix_query_caddy_t cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } PMIX_CONSTRUCT(&cb, pmix_query_caddy_t); rc = PMIx_Get_credential_nb(info, ninfo, mycdcb, &cb); if (PMIX_SUCCESS == rc) { PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; if (NULL != cb.bo.bytes) { credential->bytes = malloc(cb.bo.size); memcpy(credential->bytes, cb.bo.bytes, cb.bo.size); credential->size = cb.bo.size; } } PMIX_DESTRUCT(&cb); return rc; } PMIX_EXPORT pmix_status_t PMIx_Get_credential_nb(const pmix_info_t info[], size_t ninfo, pmix_credential_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_GET_CREDENTIAL_CMD; pmix_status_t rc; pmix_query_caddy_t *cb; pmix_byte_object_t cred; pmix_info_t *results = NULL; size_t nresults = 0; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: Get_credential called with %d info", (int) ninfo); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* if we are the server */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { /* if the host doesn't support this operation, * see if we can generate it ourselves */ if (NULL == pmix_host_server.get_credential) { PMIX_BYTE_OBJECT_CONSTRUCT(&cred); PMIX_PSEC_CREATE_CRED(rc, pmix_globals.mypeer, info, ninfo, &results, &nresults, &cred); if (PMIX_SUCCESS == rc) { /* pass it back in the callback function */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, &cred, results, nresults, cbdata); if (NULL != results) { PMIX_INFO_FREE(results, nresults); } PMIX_BYTE_OBJECT_DESTRUCT(&cred); } } return rc; } /* the host is available, so let them try to create it */ pmix_output_verbose(2, pmix_globals.debug_output, "pmix:get_credential handed to RM"); rc = pmix_host_server.get_credential(&pmix_globals.myid, info, ninfo, cbfunc, cbdata); return rc; } /* if we are a client or tool and we aren't connected, see * if one of our internal plugins is capable of meeting the request */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { PMIX_BYTE_OBJECT_CONSTRUCT(&cred); PMIX_PSEC_CREATE_CRED(rc, pmix_globals.mypeer, info, ninfo, &results, &nresults, &cred); if (PMIX_SUCCESS == rc) { /* pass it back in the callback function */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, &cred, results, nresults, cbdata); if (NULL != results) { PMIX_INFO_FREE(results, nresults); } PMIX_BYTE_OBJECT_DESTRUCT(&cred); } } return rc; } /* if we are a client, then relay this request to the server */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the directives */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_query_caddy_t); cb->credcbfunc = cbfunc; cb->cbdata = cbdata; /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, getcbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } return rc; } static void valid_cbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; pmix_status_t rc, status = PMIX_ERR_UNPACK_FAILURE; int cnt; pmix_info_t *info = NULL; size_t ninfo = 0; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:security cback from server with %d bytes", (int) buf->bytes_used); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { /* release the caller */ if (NULL != cd->validcbfunc) { cd->validcbfunc(PMIX_ERR_COMM_FAILURE, NULL, 0, cd->cbdata); } PMIX_RELEASE(cd); return; } /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS != status) { goto complete; } /* unpack any returned info */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < ninfo) { PMIX_INFO_CREATE(info, ninfo); cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } complete: pmix_output_verbose(2, pmix_globals.debug_output, "pmix:security cback from server releasing"); /* release the caller */ if (NULL != cd->validcbfunc) { cd->validcbfunc(status, info, ninfo, cd->cbdata); } if (NULL != info) { PMIX_INFO_FREE(info, ninfo); } PMIX_RELEASE(cd); } static void myvalcb(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *cbdata) { pmix_query_caddy_t *cb = (pmix_query_caddy_t *) cbdata; size_t n; PMIX_ACQUIRE_OBJECT(cb); cb->status = status; if (PMIX_SUCCESS == status && NULL != info) { cb->ninfo = ninfo; PMIX_INFO_CREATE(cb->info, cb->ninfo); for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&cb->info[n], &info[n]); } } PMIX_WAKEUP_THREAD(&cb->lock); } PMIX_EXPORT pmix_status_t PMIx_Validate_credential(const pmix_byte_object_t *cred, const pmix_info_t directives[], size_t ndirs, pmix_info_t *results[], size_t *nresults) { pmix_query_caddy_t cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } PMIX_CONSTRUCT(&cb, pmix_query_caddy_t); rc = PMIx_Validate_credential_nb(cred, directives, ndirs, myvalcb, &cb); if (PMIX_SUCCESS == rc) { PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; if (NULL != cb.info) { *results = cb.info; *nresults = cb.ninfo; cb.info = NULL; cb.ninfo = 0; } } PMIX_DESTRUCT(&cb); return rc; } PMIX_EXPORT pmix_status_t PMIx_Validate_credential_nb(const pmix_byte_object_t *cred, const pmix_info_t directives[], size_t ndirs, pmix_validation_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_VALIDATE_CRED_CMD; pmix_status_t rc; pmix_query_caddy_t *cb; pmix_info_t *results = NULL; size_t nresults = 0; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: monitor called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* if we are the server */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { /* if the host doesn't support this operation, * see if we can validate it ourselves */ if (NULL == pmix_host_server.validate_credential) { PMIX_PSEC_VALIDATE_CRED(rc, pmix_globals.mypeer, directives, ndirs, &results, &nresults, cred); if (PMIX_SUCCESS == rc) { /* pass it back in the callback function */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, results, nresults, cbdata); if (NULL != results) { PMIX_INFO_FREE(results, nresults); } } } return rc; } /* the host is available, so let them try to validate it */ pmix_output_verbose(2, pmix_globals.debug_output, "pmix:get_credential handed to RM"); rc = pmix_host_server.validate_credential(&pmix_globals.myid, cred, directives, ndirs, cbfunc, cbdata); return rc; } /* if we are a client or tool and we aren't connected, see * if one of our internal plugins is capable of meeting the request */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { PMIX_PSEC_VALIDATE_CRED(rc, pmix_globals.mypeer, directives, ndirs, &results, &nresults, cred); if (PMIX_SUCCESS == rc) { /* pass it back in the callback function */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, results, nresults, cbdata); if (NULL != results) { PMIX_INFO_FREE(results, nresults); } } } return rc; } /* if we are a client, then relay this request to the server */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the credential */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cred, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the directives */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, directives, ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_query_caddy_t); cb->validcbfunc = cbfunc; cb->cbdata = cbdata; /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, valid_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } return rc; } pmix-6.1.1~rc2/src/common/help-pfexec-base.txt0000664000175000017500000000330115203536752021422 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2014 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2017-2019 Intel, Inc. All rights reserved. # Copyright (c) 2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English general help file for Open RTE's ODLS Framework # # [fork-agent-not-found] The specified fork agent was not found: Node: %s Fork agent: %s The application cannot be launched. # [syscall fail] A system call failed that should not have. In this particular case, a warning or error message was not displayed that should have been. Your job may behave unpredictably after this, or abort. Local host: %s Application name: %s Function: %s Location: %s:%d # [execve error] PMIx tried to fork a new process via the "execve" system call but failed. PMIx checks many things before attempting to launch a child process, but nothing is perfect. This error may be indicative of another problem on the target host, or even something as silly as having specified a directory for your application. Local host: %s Working dir: %s Application name: %s Error: %s # [msg-too-large] The error message being sent back to parent by new child is too large: Msg size: %lu Limit: %lu This is an unrecoverable error. pmix-6.1.1~rc2/src/common/pmix_attributes.c0000664000175000017500000013156515203536752021156 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022-2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/gds/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_hash.h" #include "src/common/pmix_attributes.h" #include "src/include/pmix_dictionary.h" static bool initialized = false; static pmix_list_t client_attrs; static pmix_list_t server_attrs; static pmix_list_t host_attrs; static pmix_list_t tool_attrs; typedef struct { char *function; char **attrs; } pmix_attr_init_t; typedef struct { pmix_list_item_t super; char *function; char **attrs; } pmix_attribute_trk_t; static void atrkcon(pmix_attribute_trk_t *p) { p->function = NULL; p->attrs = NULL; } static void atrkdes(pmix_attribute_trk_t *p) { if (NULL != p->function) { free(p->function); } PMIx_Argv_free(p->attrs); } static PMIX_CLASS_INSTANCE(pmix_attribute_trk_t, pmix_list_item_t, atrkcon, atrkdes); PMIX_EXPORT void pmix_init_registered_attrs(void) { size_t n; pmix_regattr_input_t *p; if (!initialized) { PMIX_CONSTRUCT(&client_attrs, pmix_list_t); PMIX_CONSTRUCT(&server_attrs, pmix_list_t); PMIX_CONSTRUCT(&host_attrs, pmix_list_t); PMIX_CONSTRUCT(&tool_attrs, pmix_list_t); /* cycle across the dictionary and load a hash * table with translations of key -> index */ pmix_pointer_array_set_size(pmix_globals.keyindex.table, PMIX_INDEX_BOUNDARY); // minimize realloc's for (n=0; n < PMIX_INDEX_BOUNDARY; n++) { p = (pmix_regattr_input_t*)pmix_malloc(sizeof(pmix_regattr_input_t)); p->index = pmix_dictionary[n].index; p->name = strdup(pmix_dictionary[n].name); p->string = strdup(pmix_dictionary[n].string); p->type = pmix_dictionary[n].type; p->description = PMIx_Argv_copy(pmix_dictionary[n].description); pmix_hash_register_key(p->index, p, &pmix_globals.keyindex); } pmix_globals.keyindex.next_id = PMIX_INDEX_BOUNDARY; initialized = true; } } static void process_reg(int sd, short args, void *cbdata) { pmix_setup_caddy_t *scd = (pmix_setup_caddy_t*)cbdata; char *level = (char*)scd->cbdata; char *function = scd->nspace; char **attrs = scd->keys; pmix_attribute_trk_t *fnptr; pmix_list_t *lst; PMIX_HIDE_UNUSED_PARAMS(sd, args); /* select the list this will appear on */ if (0 == strcmp(level, PMIX_CLIENT_ATTRIBUTES)) { lst = &client_attrs; } else if (0 == strcmp(level, PMIX_SERVER_ATTRIBUTES)) { lst = &server_attrs; } else if (0 == strcmp(level, PMIX_HOST_ATTRIBUTES)) { lst = &host_attrs; } else if (0 == strcmp(level, PMIX_TOOL_ATTRIBUTES)) { lst = &tool_attrs; } else { scd->status = PMIX_ERR_BAD_PARAM; PMIX_WAKEUP_THREAD(&scd->lock); return; } /* see if we already have this function */ PMIX_LIST_FOREACH (fnptr, lst, pmix_attribute_trk_t) { if (0 == strcmp(function, fnptr->function)) { /* we already have this function at this level * so we must return an error */ scd->status = PMIX_ERR_REPEAT_ATTR_REGISTRATION; PMIX_WAKEUP_THREAD(&scd->lock); return; } } fnptr = PMIX_NEW(pmix_attribute_trk_t); pmix_list_append(lst, &fnptr->super); fnptr->function = strdup(function); if (NULL != attrs) { fnptr->attrs = PMIx_Argv_copy(attrs); } scd->status = PMIX_SUCCESS; if (scd->copied) { PMIX_WAKEUP_THREAD(&scd->lock); } } PMIX_EXPORT pmix_status_t PMIx_Register_attributes(char *function, char *attrs[]) { pmix_setup_caddy_t *scd; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } scd = PMIX_NEW(pmix_setup_caddy_t); scd->nspace = function; scd->keys = attrs; scd->cbdata = PMIX_HOST_ATTRIBUTES; scd->copied = true; PMIX_THREADSHIFT(scd, process_reg); PMIX_WAIT_THREAD(&scd->lock); rc = scd->status; PMIX_RELEASE(scd); return rc; } PMIX_EXPORT void pmix_release_registered_attrs(void) { if (initialized) { PMIX_LIST_DESTRUCT(&client_attrs); PMIX_LIST_DESTRUCT(&server_attrs); PMIX_LIST_DESTRUCT(&host_attrs); PMIX_LIST_DESTRUCT(&tool_attrs); } initialized = false; } /* sadly, we cannot dynamically register our supported attributes * as that would require the user to first call the function whose * attributes they want to know about - which somewhat defeats the * purpose. Until someone comes up with a better solution, we will * manually maintain the list */ static pmix_attr_init_t client_fns[] = { {.function = "PMIx_Init", .attrs = (char *[]){"PMIX_GDS_MODULE", "PMIX_EVENT_BASE", "PMIX_HOSTNAME", "PMIX_NODEID", "PMIX_PROGRAMMING_MODEL", "PMIX_MODEL_LIBRARY_NAME", "PMIX_MODEL_LIBRARY_VERSION", "PMIX_THREADING_MODEL", "PMIX_NODE_INFO_ARRAY", "PMIX_EXTERNAL_PROGRESS", "PMIX_HOSTNAME_KEEP_FQDN", "PMIX_TOPOLOGY2", "PMIX_SERVER_URI", "PMIX_DEBUG_STOP_IN_INIT", "PMIX_IOF_TAG_OUTPUT", "PMIX_TAG_OUTPUT", "PMIX_IOF_RANK_OUTPUT", "PMIX_IOF_TIMESTAMP_OUTPUT", "PMIX_TIMESTAMP_OUTPUT", "PMIX_IOF_XML_OUTPUT", "PMIX_IOF_OUTPUT_TO_FILE", "PMIX_OUTPUT_TO_FILE", "PMIX_IOF_OUTPUT_TO_DIRECTORY", "PMIX_OUTPUT_TO_DIRECTORY", "PMIX_IOF_FILE_ONLY", "PMIX_OUTPUT_NOCOPY", "PMIX_IOF_MERGE_STDERR_STDOUT", "PMIX_MERGE_STDERR_STDOUT", "PMIX_IOF_LOCAL_OUTPUT", "PMIX_IOF_FILE_PATTERN", NULL}}, {.function = "PMIx_Finalize", .attrs = (char *[]){"PMIX_EMBED_BARRIER", NULL}}, {.function = "PMIx_Initialized", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Abort", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Store_internal", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Put", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Commit", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Fence", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Fence_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Get", .attrs = (char *[]){"PMIX_NODE_INFO", "PMIX_HOSTNAME", "PMIX_NODEID", "PMIX_APP_INFO", "PMIX_APPNUM", "PMIX_SESSION_INFO", "PMIX_GET_REFRESH_CACHE", "PMIX_OPTIONAL", "PMIX_DATA_SCOPE", NULL}}, {.function = "PMIx_Get_nb", .attrs = (char *[]){"PMIX_NODE_INFO", "PMIX_HOSTNAME", "PMIX_NODEID", "PMIX_APP_INFO", "PMIX_APPNUM", "PMIX_SESSION_INFO", "PMIX_GET_REFRESH_CACHE", "PMIX_OPTIONAL", "PMIX_DATA_SCOPE", NULL}}, {.function = "PMIx_Publish", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Publish_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Lookup", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Lookup_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Unpublish", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Unpublish_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Spawn", .attrs = (char *[]){"PMIX_SETUP_APP_ENVARS", NULL}}, {.function = "PMIx_Spawn_nb", .attrs = (char *[]){"PMIX_SETUP_APP_ENVARS", NULL}}, {.function = "PMIx_Connect", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Connect_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Disconnect", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Disconnect_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Resolve_peers", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Resolve_nodes", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Query_info", .attrs = (char *[]){"PMIX_QUERY_ATTRIBUTE_SUPPORT", "PMIX_QUERY_AVAIL_SERVERS", "PMIX_QUERY_REFRESH_CACHE", "PMIX_QUERY_SUPPORTED_KEYS", "PMIX_QUERY_SUPPORTED_QUALIFIERS", NULL}}, {.function = "PMIx_Query_info_nb", .attrs = (char *[]){"PMIX_QUERY_ATTRIBUTE_SUPPORT", "PMIX_QUERY_AVAIL_SERVERS", "PMIX_QUERY_REFRESH_CACHE", "PMIX_QUERY_SUPPORTED_KEYS", "PMIX_QUERY_SUPPORTED_QUALIFIERS", NULL}}, {.function = "PMIx_Log", .attrs = (char *[]){"PMIX_LOG_GENERATE_TIMESTAMP", "PMIX_LOG_SOURCE", NULL}}, {.function = "PMIx_Log_nb", .attrs = (char *[]){"PMIX_LOG_GENERATE_TIMESTAMP", "PMIX_LOG_SOURCE", NULL}}, {.function = "PMIx_Allocation_request", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Allocation_request_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Job_control", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Job_control_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Process_monitor", .attrs = (char *[]){"PMIX_SEND_HEARTBEAT", NULL}}, {.function = "PMIx_Process_monitor_nb", .attrs = (char *[]){"PMIX_SEND_HEARTBEAT", NULL}}, {.function = "PMIx_Get_credential", .attrs = (char *[]){"PMIX_CRED_TYPE", NULL}}, {.function = "PMIx_Get_credential_nb", .attrs = (char *[]){"PMIX_CRED_TYPE", NULL}}, {.function = "PMIx_Validate_credential", .attrs = (char *[]){"PMIX_CRED_TYPE", NULL}}, {.function = "PMIx_Validate_credential_nb", .attrs = (char *[]){"PMIX_CRED_TYPE", NULL}}, {.function = "PMIx_Group_construct", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Group_construct_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Group_invite", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Group_invite_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Group_join", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Group_join_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Group_leave", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Group_leave_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Group_destruct", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Group_destruct_nb", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Register_event_handler", .attrs = (char *[]){"PMIX_EVENT_HDLR_FIRST", "PMIX_EVENT_HDLR_LAST", "PMIX_EVENT_HDLR_PREPEND", "PMIX_EVENT_HDLR_APPEND", "PMIX_EVENT_HDLR_NAME", "PMIX_EVENT_RETURN_OBJECT", "PMIX_EVENT_HDLR_FIRST_IN_CATEGORY", "PMIX_EVENT_HDLR_LAST_IN_CATEGORY", "PMIX_EVENT_HDLR_BEFORE", "PMIX_EVENT_HDLR_AFTER", "PMIX_RANGE", "PMIX_EVENT_CUSTOM_RANGE", "PMIX_EVENT_AFFECTED_PROC", "PMIX_EVENT_AFFECTED_PROCS", NULL}}, {.function = "PMIx_Deregister_event_handler", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Notify_event", .attrs = (char *[]){"PMIX_EVENT_NON_DEFAULT", "PMIX_EVENT_CUSTOM_RANGE", "PMIX_EVENT_AFFECTED_PROC", "PMIX_EVENT_AFFECTED_PROCS", NULL}}, {.function = "PMIx_Error_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Proc_state_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Scope_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Persistence_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Data_range_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Info_directives_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Data_type_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Alloc_directive_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_IOF_channel_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Job_state_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Get_attribute_string", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Get_attribute_name", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Get_version", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Data_pack", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Data_unpack", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Data_copy", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Data_print", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_Data_copy_payload", .attrs = (char *[]){"N/A", NULL}}, {.function = ""}}; /***** REGISTER CLIENT ATTRS *****/ static bool client_attrs_regd = false; /* this is executed by "pmix_init" prior to an event base * being available, so we cannot threadshift it */ PMIX_EXPORT pmix_status_t pmix_register_client_attrs(void) { pmix_setup_caddy_t cd; size_t n; pmix_status_t rc = PMIX_SUCCESS; if (client_attrs_regd) { return PMIX_SUCCESS; } client_attrs_regd = true; PMIX_CONSTRUCT(&cd, pmix_setup_caddy_t); cd.cbdata = PMIX_CLIENT_ATTRIBUTES; for (n = 0; 0 != strlen(client_fns[n].function); n++) { cd.nspace = client_fns[n].function; cd.keys = client_fns[n].attrs; process_reg(0, 0, &cd); rc = cd.status; if (PMIX_SUCCESS != rc) { break; } } PMIX_DESTRUCT(&cd); return rc; } static pmix_attr_init_t server_fns[] = { {.function = "PMIx_server_init", .attrs = (char *[]){"PMIX_SERVER_GATEWAY", "PMIX_SERVER_SCHEDULER", "PMIX_SERVER_TMPDIR", "PMIX_SYSTEM_TMPDIR", "PMIX_SERVER_NSPACE", "PMIX_SERVER_RANK", "PMIX_SERVER_SHARE_TOPOLOGY", "PMIX_TOPOLOGY2", "PMIX_TOPOLOGY", "PMIX_IOF_LOCAL_OUTPUT", "PMIX_GDS_MODULE", "PMIX_EVENT_BASE", "PMIX_HOSTNAME", "PMIX_NODEID", "PMIX_TCP_IF_INCLUDE", "PMIX_TCP_IF_EXCLUDE", "PMIX_TCP_IPV4_PORT", "PMIX_TCP_IPV6_PORT", "PMIX_TCP_DISABLE_IPV4", "PMIX_TCP_DISABLE_IPV6", "PMIX_SERVER_REMOTE_CONNECTIONS", "PMIX_TCP_REPORT_URI", "PMIX_SERVER_SESSION_SUPPORT", "PMIX_SERVER_SYSTEM_SUPPORT", "PMIX_SERVER_TOOL_SUPPORT", "PMIX_LAUNCHER_RENDEZVOUS_FILE", "PMIX_SERVER_ENABLE_MONITORING", "PMIX_IOF_TAG_OUTPUT", "PMIX_TAG_OUTPUT", "PMIX_IOF_RANK_OUTPUT", "PMIX_IOF_TIMESTAMP_OUTPUT", "PMIX_TIMESTAMP_OUTPUT", "PMIX_IOF_XML_OUTPUT", "PMIX_IOF_OUTPUT_TO_FILE", "PMIX_OUTPUT_TO_FILE", "PMIX_IOF_OUTPUT_TO_DIRECTORY", "PMIX_OUTPUT_TO_DIRECTORY", "PMIX_IOF_FILE_ONLY", "PMIX_OUTPUT_NOCOPY", "PMIX_IOF_MERGE_STDERR_STDOUT", "PMIX_MERGE_STDERR_STDOUT", "PMIX_IOF_LOCAL_OUTPUT", "PMIX_IOF_FILE_PATTERN", NULL}}, {.function = "PMIx_server_finalize", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_generate_regex", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_generate_ppn", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_server_register_nspace", .attrs = (char *[]){"PMIX_REGISTER_NODATA", NULL}}, {.function = "PMIx_server_deregister_nspace", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_server_register_client", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_server_deregister_client", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_server_setup_fork", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_server_dmodex_request", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_server_setup_application", .attrs = (char *[]){"PMIX_SETUP_APP_ENVARS", "PMIX_SETUP_APP_ALL", "PMIX_SETUP_APP_NONENVARS", "PMIX_ALLOC_FABRIC", "PMIX_ALLOC_FABRIC_SEC_KEY", "PMIX_ALLOC_FABRIC_ID", "PMIX_ALLOC_FABRIC_TYPE", "PMIX_ALLOC_FABRIC_PLANE", "PMIX_ALLOC_FABRIC_ENDPTS", NULL}}, {.function = "PMIx_server_setup_local_support", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_server_IOF_deliver", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_server_collect_inventory", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_server_deliver_inventory", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_Register_attributes", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_server_register_fabric", .attrs = (char *[]){"PMIX_FABRIC_PLANE", "PMIX_FABRIC_IDENTIFIER", "PMIX_FABRIC_VENDOR", NULL}}, {.function = "PMIx_server_update_fabric", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_server_deregister_fabric", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_server_get_vertex_info", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_server_get_index", .attrs = (char *[]){"PMIX_HOSTNAME", "PMIX_NODEID", "PMIX_FABRIC_DEVICE_NAME", "PMIX_FABRIC_DEVICE_VENDOR", "PMIX_FABRIC_DEVICE_BUS_TYPE", "PMIX_FABRIC_DEVICE_PCI_DEVID", NULL}}, {.function = ""}}; /***** REGISTER SERVER ATTRS *****/ static bool server_attrs_regd = false; /* this is executed by "server_init" prior to an event base * being available, so we cannot threadshift it */ PMIX_EXPORT pmix_status_t pmix_register_server_attrs(void) { pmix_setup_caddy_t cd; pmix_status_t rc = PMIX_SUCCESS; size_t n; if (server_attrs_regd) { return PMIX_SUCCESS; } server_attrs_regd = true; PMIX_CONSTRUCT(&cd, pmix_setup_caddy_t); cd.cbdata = PMIX_SERVER_ATTRIBUTES; for (n = 0; 0 != strlen(server_fns[n].function); n++) { cd.nspace = server_fns[n].function; cd.keys = server_fns[n].attrs; process_reg(0, 0, &cd); rc = cd.status; if (PMIX_SUCCESS != rc) { break; } } PMIX_DESTRUCT(&cd); return rc; } static pmix_attr_init_t tool_fns[] = {{.function = "PMIx_tool_init", .attrs = (char *[]){"PMIX_GDS_MODULE", "PMIX_EVENT_BASE", "PMIX_HOSTNAME", "PMIX_NODEID", "PMIX_TOOL_DO_NOT_CONNECT", "PMIX_DEBUG_STOP_IN_INIT", "PMIX_TOOL_NSPACE", "PMIX_TOOL_RANK", "PMIX_FWD_STDIN", "PMIX_LAUNCHER", "PMIX_SERVER_TMPDIR", "PMIX_SYSTEM_TMPDIR", "PMIX_TOOL_CONNECT_OPTIONAL", "PMIX_RECONNECT_SERVER", "PMIX_TOOL_ATTACHMENT_FILE", "PMIX_CONNECT_MAX_RETRIES", "PMIX_CONNECT_RETRY_DELAY", "PMIX_CONNECT_TO_SYSTEM", "PMIX_CONNECT_SYSTEM_FIRST", "PMIX_SERVER_PIDINFO", "PMIX_SERVER_NSPACE", "PMIX_SERVER_URI", "PMIX_TCP_IF_INCLUDE", "PMIX_TCP_IF_EXCLUDE", "PMIX_TCP_IPV4_PORT", "PMIX_TCP_IPV6_PORT", "PMIX_TCP_DISABLE_IPV4", "PMIX_TCP_DISABLE_IPV6", "PMIX_IOF_TAG_OUTPUT", "PMIX_TAG_OUTPUT", "PMIX_IOF_RANK_OUTPUT", "PMIX_IOF_TIMESTAMP_OUTPUT", "PMIX_TIMESTAMP_OUTPUT", "PMIX_IOF_XML_OUTPUT", "PMIX_IOF_OUTPUT_TO_FILE", "PMIX_OUTPUT_TO_FILE", "PMIX_IOF_OUTPUT_TO_DIRECTORY", "PMIX_OUTPUT_TO_DIRECTORY", "PMIX_IOF_FILE_ONLY", "PMIX_OUTPUT_NOCOPY", "PMIX_IOF_MERGE_STDERR_STDOUT", "PMIX_MERGE_STDERR_STDOUT", "PMIX_IOF_LOCAL_OUTPUT", "PMIX_IOF_FILE_PATTERN", NULL}}, {.function = "PMIx_tool_finalize", .attrs = (char *[]){"N/A", NULL}}, {.function = "PMIx_tool_connect_to_server", .attrs = (char *[]){"PMIX_CONNECT_TO_SYSTEM", "PMIX_CONNECT_SYSTEM_FIRST", "PMIX_SERVER_PIDINFO", "PMIX_SERVER_NSPACE", "PMIX_SERVER_URI", "PMIX_CONNECT_RETRY_DELAY", "PMIX_CONNECT_MAX_RETRIES", "PMIX_RECONNECT_SERVER", "PMIX_TOOL_ATTACHMENT_FILE", NULL}}, {.function = "PMIx_IOF_pull", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_IOF_deregister", .attrs = (char *[]){"NONE", NULL}}, {.function = "PMIx_IOF_push", .attrs = (char *[]){"PMIX_IOF_PUSH_STDIN", "PMIX_IOF_COMPLETE", NULL}}, {.function = ""}}; /***** REGISTER TOOL ATTRS *****/ static bool tool_attrs_regd = false; /* this is executed by "tool_init" prior to an event base * being available, so we cannot threadshift it */ PMIX_EXPORT pmix_status_t pmix_register_tool_attrs(void) { pmix_setup_caddy_t cd; pmix_status_t rc = PMIX_SUCCESS; size_t n; if (tool_attrs_regd) { return PMIX_SUCCESS; } tool_attrs_regd = true; PMIX_CONSTRUCT(&cd, pmix_setup_caddy_t); cd.cbdata = PMIX_TOOL_ATTRIBUTES; for (n = 0; 0 != strlen(tool_fns[n].function); n++) { cd.nspace = tool_fns[n].function; cd.keys = tool_fns[n].attrs; process_reg(0, 0, &cd); rc = cd.status; if (PMIX_SUCCESS != rc) { break; } } PMIX_DESTRUCT(&cd); return rc; } /***** PROCESS QUERY ATTRS *****/ static void _get_attrs(pmix_list_t *lst, pmix_info_t *info, pmix_list_t *attrs) { pmix_attribute_trk_t *trk, *tptr; pmix_infolist_t *ip; pmix_data_array_t *darray; pmix_regattr_t *regarray; size_t m, nattr; char **fns = NULL; const pmix_regattr_input_t *dptr; /* the value in the info is a comma-delimited list of * functions whose attributes are being requested */ if (NULL != info) { fns = PMIx_Argv_split(info->key, ','); } /* search the list for these functions */ PMIX_LIST_FOREACH (tptr, attrs, pmix_attribute_trk_t) { if (NULL == fns) { // want them all - ignore if no attrs if (NULL == tptr->attrs) { continue; } } else { trk = NULL; for (m = 0; NULL != fns[m]; m++) { if (0 == strcmp(fns[m], tptr->function) || 0 == strcmp(fns[m], "all")) { trk = tptr; break; } } if (NULL == trk || NULL == trk->attrs) { /* function wasn't found - no attrs * registered for it */ continue; } } /* add the found attrs to the results */ ip = PMIX_NEW(pmix_infolist_t); PMIX_LOAD_KEY(ip->info.key, tptr->function); /* create the data array to hold the results */ nattr = PMIx_Argv_count(tptr->attrs); if (0 == nattr || (1 == nattr && (0 == strcmp("N/A", tptr->attrs[0]) || 0 == strcmp("NONE", tptr->attrs[0])))) { nattr = 1; PMIX_DATA_ARRAY_CREATE(darray, nattr, PMIX_REGATTR); ip->info.value.type = PMIX_DATA_ARRAY; ip->info.value.data.darray = darray; regarray = (pmix_regattr_t *) darray->array; regarray[0].name = strdup("NONE"); } else { PMIX_DATA_ARRAY_CREATE(darray, nattr, PMIX_REGATTR); ip->info.value.type = PMIX_DATA_ARRAY; ip->info.value.data.darray = darray; regarray = (pmix_regattr_t *) darray->array; for (m = 0; m < nattr; m++) { regarray[m].name = strdup(tptr->attrs[m]); PMIX_LOAD_KEY(regarray[m].string, pmix_attributes_lookup(tptr->attrs[m])); dptr = pmix_attributes_lookup_term(tptr->attrs[m]); if (NULL == dptr) { PMIX_RELEASE(ip); return; } regarray[m].type = dptr->type; regarray[m].description = PMIx_Argv_copy(dptr->description); } } pmix_list_append(lst, &ip->super); } PMIx_Argv_free(fns); } static void _get_fns(pmix_list_t *lst, char *key, pmix_list_t *attrs) { pmix_attribute_trk_t *tptr; pmix_infolist_t *ip; char **fns = NULL, *tmp; /* search the list for these functions */ PMIX_LIST_FOREACH (tptr, attrs, pmix_attribute_trk_t) { PMIx_Argv_append_nosize(&fns, tptr->function); } if (0 < PMIx_Argv_count(fns)) { ip = PMIX_NEW(pmix_infolist_t); tmp = PMIx_Argv_join(fns, ','); PMIX_INFO_LOAD(&ip->info, key, tmp, PMIX_STRING); pmix_list_append(lst, &ip->super); PMIx_Argv_free(fns); } } // called from within an event PMIX_EXPORT void pmix_attrs_query_support(pmix_query_caddy_t *cd, pmix_query_t *query, pmix_list_t *unresolved) { pmix_querylist_t *qry; pmix_list_t kyresults; pmix_infolist_t *info; size_t n, m, p; pmix_info_t *iptr; pmix_data_array_t *darray; pmix_status_t rc; pmix_kval_t *kv; char **cache = NULL; // this is called from within an event, so no need to lock // if the qualifiers are NULL, then they want it all if (NULL == query->qualifiers) { PMIX_CONSTRUCT(&kyresults, pmix_list_t); /* everyone has access to the client attrs */ _get_attrs(&kyresults, NULL, &client_attrs); /* everyone has access to the client functions */ _get_fns(&kyresults, PMIX_CLIENT_FUNCTIONS, &client_attrs); /* if I am a server... */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { // add in my attrs and fns _get_attrs(&kyresults, NULL, &server_attrs); _get_fns(&kyresults, PMIX_SERVER_FUNCTIONS, &server_attrs); // and add in my hosts _get_attrs(&kyresults, NULL, &host_attrs); _get_fns(&kyresults, PMIX_HOST_FUNCTIONS, &host_attrs); } else { PMIx_Argv_append_nosize(&cache, PMIX_SERVER_ATTRIBUTES); PMIx_Argv_append_nosize(&cache, PMIX_SERVER_FUNCTIONS); PMIx_Argv_append_nosize(&cache, PMIX_HOST_ATTRIBUTES); PMIx_Argv_append_nosize(&cache, PMIX_HOST_FUNCTIONS); } // if I am a tool... if (PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { // add in my attrs and fns _get_attrs(&kyresults, NULL, &tool_attrs); _get_fns(&kyresults, PMIX_TOOL_FUNCTIONS, &tool_attrs); } // collect the results if (0 < (p = pmix_list_get_size(&kyresults))) { PMIX_KVAL_NEW(kv, PMIX_QUERY_ATTRIBUTE_SUPPORT); kv->value->type = PMIX_DATA_ARRAY; /* create the data array to hold the results */ PMIX_DATA_ARRAY_CREATE(darray, p, PMIX_INFO); kv->value->data.darray = darray; iptr = (pmix_info_t *) darray->array; p = 0; PMIX_LIST_FOREACH (info, &kyresults, pmix_infolist_t) { PMIX_INFO_XFER(&iptr[p], &info->info); ++p; } pmix_list_append(&cd->results, &kv->super); } PMIX_LIST_DESTRUCT(&kyresults); if (NULL != cache) { goto request; } return; } // otherwise, search for the ones they want for (m = 0; m < query->nqual; m++) { PMIX_CONSTRUCT(&kyresults, pmix_list_t); if (PMIX_CHECK_KEY(&query->qualifiers[m], PMIX_CLIENT_ATTRIBUTES)) { /* everyone has access to the client attrs */ _get_attrs(&kyresults, &query->qualifiers[m], &client_attrs); } else if (PMIX_CHECK_KEY(&query->qualifiers[m], PMIX_CLIENT_FUNCTIONS)) { /* everyone has access to the client functions */ _get_fns(&kyresults, PMIX_CLIENT_FUNCTIONS, &client_attrs); } else if (PMIX_CHECK_KEY(&query->qualifiers[m], PMIX_SERVER_ATTRIBUTES)) { /* if I am a server, add in my attrs */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { _get_attrs(&kyresults, &query->qualifiers[m], &server_attrs); } else { PMIx_Argv_append_nosize(&cache, PMIX_SERVER_ATTRIBUTES); } } else if (PMIX_CHECK_KEY(&query->qualifiers[m], PMIX_SERVER_FUNCTIONS)) { /* if I am a server, add in my fns */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { _get_fns(&kyresults, PMIX_SERVER_FUNCTIONS, &server_attrs); } else { PMIx_Argv_append_nosize(&cache, PMIX_SERVER_FUNCTIONS); } } else if (PMIX_CHECK_KEY(&query->qualifiers[m], PMIX_TOOL_ATTRIBUTES)) { if (PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { _get_attrs(&kyresults, &query->qualifiers[m], &tool_attrs); } } else if (PMIX_CHECK_KEY(&query->qualifiers[m], PMIX_TOOL_FUNCTIONS)) { if (PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { _get_fns(&kyresults, PMIX_TOOL_FUNCTIONS, &tool_attrs); } } else if (PMIX_CHECK_KEY(&query->qualifiers[m], PMIX_HOST_ATTRIBUTES)) { /* if I am a server, add in the host's */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { _get_attrs(&kyresults, &query->qualifiers[m], &host_attrs); } else { PMIx_Argv_append_nosize(&cache, PMIX_HOST_ATTRIBUTES); } } else if (PMIX_CHECK_KEY(&query->qualifiers[m], PMIX_HOST_FUNCTIONS)) { /* if I am a server, add in the host's */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { _get_fns(&kyresults, PMIX_HOST_FUNCTIONS, &host_attrs); } else { PMIx_Argv_append_nosize(&cache, PMIX_HOST_FUNCTIONS); } } if (0 < (p = pmix_list_get_size(&kyresults))) { PMIX_KVAL_NEW(kv, PMIX_QUERY_ATTRIBUTE_SUPPORT); kv->value->type = PMIX_DATA_ARRAY; /* create the data array to hold the results */ PMIX_DATA_ARRAY_CREATE(darray, p, PMIX_INFO); kv->value->data.darray = darray; iptr = (pmix_info_t *) darray->array; p = 0; PMIX_LIST_FOREACH (info, &kyresults, pmix_infolist_t) { PMIX_INFO_XFER(&iptr[p], &info->info); ++p; } pmix_list_append(&cd->results, &kv->super); } PMIX_LIST_DESTRUCT(&kyresults); } request: // if we don't need help then we are done if (NULL == cache) { return; } qry = PMIX_NEW(pmix_querylist_t); PMIX_ARGV_APPEND(rc, qry->query.keys, PMIX_QUERY_ATTRIBUTE_SUPPORT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(qry); return; } qry->query.nqual = PMIx_Argv_count(cache); PMIX_INFO_CREATE(qry->query.qualifiers, qry->query.nqual); for (n=0; NULL != cache[n]; n++) { PMIX_INFO_LOAD(&qry->query.qualifiers[n], cache[n], NULL, PMIX_BOOL); } PMIx_Argv_free(cache); pmix_list_append(unresolved, &qry->super); return; } /***** LOCATE A GIVEN ATTRIBUTE *****/ PMIX_EXPORT const char *pmix_attributes_lookup(const char *attr) { pmix_keyindex_t *const kidx = &pmix_globals.keyindex; if (NULL == kidx->table) { // we haven't been initialized yet - just return the string return attr; } for (int i = 0; i < kidx->table->size; ++i) { pmix_regattr_input_t *ra = pmix_pointer_array_get_item(kidx->table, i); if (NULL == ra) break; if (0 == strcasecmp(ra->name, attr)) { return ra->string; } } return attr; } PMIX_EXPORT const char *pmix_attributes_reverse_lookup(const char *attrstring) { pmix_keyindex_t *const kidx = &pmix_globals.keyindex; if (NULL == kidx->table) { // we haven't been initialized yet - just return the string return attrstring; } for (int i = 0; i < kidx->table->size; ++i) { pmix_regattr_input_t *ra = pmix_pointer_array_get_item(kidx->table, i); if (NULL == ra) break; if (0 == strcasecmp(ra->string, attrstring)) { return ra->name; } } return attrstring; } PMIX_EXPORT const pmix_regattr_input_t *pmix_attributes_lookup_term(char *attr) { pmix_keyindex_t *const kidx = &pmix_globals.keyindex; if (NULL == kidx->table) { // we haven't been initialized yet - just return the string return NULL; } for (int i = 0; i < kidx->table->size; ++i) { pmix_regattr_input_t *ra = pmix_pointer_array_get_item(kidx->table, i); if (NULL == ra) break; if (0 == strcasecmp(ra->name, attr)) { return ra; } } return NULL; } /***** PRINT QUERY FUNCTIONS RESULTS *****/ PMIX_EXPORT char **pmix_attributes_print_functions(char *level) { char *title1 = "CLIENT SUPPORTED FUNCTIONS: "; char *title2 = "SERVER SUPPORTED FUNCTIONS: "; char *title3 = "HOST SUPPORTED FUNCTIONS: "; char *title4 = "TOOL SUPPORTED FUNCTIONS: "; char **ans = NULL; pmix_list_t *lst; pmix_attribute_trk_t *fnptr; /* select title */ if (0 == strcmp(level, PMIX_CLIENT_FUNCTIONS)) { PMIx_Argv_append_nosize(&ans, title1); lst = &client_attrs; } else if (0 == strcmp(level, PMIX_SERVER_FUNCTIONS)) { PMIx_Argv_append_nosize(&ans, title2); lst = &server_attrs; } else if (0 == strcmp(level, PMIX_HOST_FUNCTIONS)) { PMIx_Argv_append_nosize(&ans, title3); lst = &host_attrs; } else if (0 == strcmp(level, PMIX_TOOL_FUNCTIONS)) { PMIx_Argv_append_nosize(&ans, title4); lst = &tool_attrs; } else { return NULL; } PMIX_LIST_FOREACH (fnptr, lst, pmix_attribute_trk_t) { PMIx_Argv_append_nosize(&ans, fnptr->function); } return ans; } /***** PRINT QUERY ATTRS RESULTS *****/ #define PMIX_PRINT_NAME_COLUMN_WIDTH 35 #define PMIX_PRINT_STRING_COLUMN_WIDTH 25 #define PMIX_PRINT_TYPE_COLUMN_WIDTH 20 #define PMIX_PRINT_ATTR_COLUMN_WIDTH 141 void pmix_attributes_print_attrs(char ***ans, char *function, pmix_regattr_t *attrs, size_t nattrs) { char line[PMIX_PRINT_ATTR_COLUMN_WIDTH], *tmp; size_t n, m, len; /* print the function */ memset(line, ' ', PMIX_PRINT_ATTR_COLUMN_WIDTH); m = 0; for (n = 0; n < strlen(function); n++) { line[m] = function[n]; ++m; } line[m++] = ':'; line[m] = '\0'; PMIx_Argv_append_nosize(ans, line); for (n = 0; n < nattrs; n++) { memset(line, ' ', PMIX_PRINT_ATTR_COLUMN_WIDTH); line[PMIX_PRINT_ATTR_COLUMN_WIDTH - 1] = '\0'; len = strlen(attrs[n].name); if (PMIX_PRINT_NAME_COLUMN_WIDTH < len) { len = PMIX_PRINT_NAME_COLUMN_WIDTH; } memcpy(line, attrs[n].name, len); if (0 == strlen(attrs[n].string)) { line[PMIX_PRINT_ATTR_COLUMN_WIDTH - 1] = '\0'; // ensure NULL termination PMIx_Argv_append_nosize(ans, line); continue; } len = strlen(attrs[n].string); if (PMIX_PRINT_STRING_COLUMN_WIDTH < len) { len = PMIX_PRINT_STRING_COLUMN_WIDTH; } memcpy(&line[PMIX_PRINT_NAME_COLUMN_WIDTH + 2], attrs[n].string, len); tmp = (char *) PMIx_Data_type_string(attrs[n].type); len = strlen(tmp); if (PMIX_PRINT_STRING_COLUMN_WIDTH < len) { len = PMIX_PRINT_STRING_COLUMN_WIDTH; } memcpy(&line[PMIX_PRINT_NAME_COLUMN_WIDTH + PMIX_PRINT_STRING_COLUMN_WIDTH + 4], tmp, len); for (m = 0; NULL != attrs[n].description[m]; m++) { len = strlen(attrs[n].description[m]); memcpy(&line[PMIX_PRINT_NAME_COLUMN_WIDTH + PMIX_PRINT_STRING_COLUMN_WIDTH + PMIX_PRINT_TYPE_COLUMN_WIDTH + 6], attrs[n].description[m], len); line[PMIX_PRINT_ATTR_COLUMN_WIDTH - 1] = '\0'; // ensure NULL termination PMIx_Argv_append_nosize(ans, line); memset(line, ' ', PMIX_PRINT_ATTR_COLUMN_WIDTH); line[PMIX_PRINT_ATTR_COLUMN_WIDTH - 1] = '\0'; } } } void pmix_attributes_print_headers(char ***ans, char *level) { size_t n, m, left; char *title1 = "CLIENT SUPPORTED ATTRIBUTES: "; char *title2 = "SERVER SUPPORTED ATTRIBUTES: "; char *title3 = "HOST SUPPORTED ATTRIBUTES: "; char *title4 = "TOOL SUPPORTED ATTRIBUTES: "; char line[PMIX_PRINT_ATTR_COLUMN_WIDTH]; /* select title */ if (0 == strcmp(level, PMIX_CLIENT_ATTRIBUTES)) { PMIx_Argv_append_nosize(ans, title1); } else if (0 == strcmp(level, PMIX_SERVER_ATTRIBUTES)) { PMIx_Argv_append_nosize(ans, title2); } else if (0 == strcmp(level, PMIX_HOST_ATTRIBUTES)) { PMIx_Argv_append_nosize(ans, title3); } else if (0 == strcmp(level, PMIX_TOOL_ATTRIBUTES)) { PMIx_Argv_append_nosize(ans, title4); } else { return; } /* print the column headers */ memset(line, ' ', PMIX_PRINT_ATTR_COLUMN_WIDTH); line[PMIX_PRINT_ATTR_COLUMN_WIDTH - 1] = '\0'; left = PMIX_PRINT_NAME_COLUMN_WIDTH / 2 - 1; memcpy(&line[left], "NAME", 4); left = 3 + PMIX_PRINT_NAME_COLUMN_WIDTH + (PMIX_PRINT_STRING_COLUMN_WIDTH / 2) - 2; memcpy(&line[left], "STRING", 6); left = 3 + PMIX_PRINT_NAME_COLUMN_WIDTH + PMIX_PRINT_STRING_COLUMN_WIDTH + (PMIX_PRINT_TYPE_COLUMN_WIDTH / 2) - 2; memcpy(&line[left], "TYPE", 4); left = PMIX_PRINT_NAME_COLUMN_WIDTH + PMIX_PRINT_STRING_COLUMN_WIDTH + PMIX_PRINT_TYPE_COLUMN_WIDTH + ((PMIX_PRINT_ATTR_COLUMN_WIDTH - PMIX_PRINT_NAME_COLUMN_WIDTH - PMIX_PRINT_STRING_COLUMN_WIDTH - PMIX_PRINT_TYPE_COLUMN_WIDTH) / 2) - 3 - strlen("DESCRIPTION") / 2; memcpy(&line[left], "DESCRIPTION", strlen("DESCRIPTION")); left += strlen("DESCRIPTION") + 1; line[left] = '\0'; PMIx_Argv_append_nosize(ans, line); /* print the dashes under the column headers */ memset(line, ' ', PMIX_PRINT_ATTR_COLUMN_WIDTH); line[PMIX_PRINT_ATTR_COLUMN_WIDTH - 1] = '\0'; m = 0; for (n = 0; n < PMIX_PRINT_NAME_COLUMN_WIDTH; n++) { line[m] = '-'; ++m; } m += 2; // leave gap for (n = 0; n < PMIX_PRINT_STRING_COLUMN_WIDTH; n++) { line[m] = '-'; ++m; } m += 2; // leave gap for (n = 0; n < PMIX_PRINT_TYPE_COLUMN_WIDTH; n++) { line[m] = '-'; ++m; } m += 2; // leave gap while (m < PMIX_PRINT_ATTR_COLUMN_WIDTH - 1) { line[m] = '-'; ++m; } PMIx_Argv_append_nosize(ans, line); } PMIX_EXPORT char **pmix_attributes_print_attr(char *level, char *function) { size_t n, m, nattr; char **tmp, **ans = NULL; pmix_list_t *lst; pmix_attribute_trk_t *fnptr; char line[PMIX_PRINT_ATTR_COLUMN_WIDTH]; pmix_regattr_t *rptr; const pmix_regattr_input_t *dptr; /* select title */ if (0 == strcmp(level, PMIX_CLIENT_ATTRIBUTES)) { lst = &client_attrs; } else if (0 == strcmp(level, PMIX_SERVER_ATTRIBUTES)) { lst = &server_attrs; } else if (0 == strcmp(level, PMIX_HOST_ATTRIBUTES)) { lst = &host_attrs; } else if (0 == strcmp(level, PMIX_TOOL_ATTRIBUTES)) { lst = &tool_attrs; } else { return NULL; } /* print the column headers */ pmix_attributes_print_headers(&ans, level); memset(line, '=', PMIX_PRINT_ATTR_COLUMN_WIDTH); line[PMIX_PRINT_ATTR_COLUMN_WIDTH - 1] = '\0'; /* can be comma-delimited list of functions */ tmp = PMIx_Argv_split(function, ','); for (n = 0; NULL != tmp[n]; n++) { PMIX_LIST_FOREACH (fnptr, lst, pmix_attribute_trk_t) { if (0 == strcmp(tmp[n], "all") || 0 == strcmp(tmp[n], fnptr->function)) { /* create an array of pmix_regattr_t for this function's attributes */ nattr = PMIx_Argv_count(fnptr->attrs); if (0 == nattr || (1 == nattr && (0 == strcmp("N/A", fnptr->attrs[0]) || 0 == strcmp("NONE", fnptr->attrs[0])))) { nattr = 1; PMIX_REGATTR_CREATE(rptr, nattr); rptr[0].name = strdup("NONE"); } else { PMIX_REGATTR_CREATE(rptr, nattr); for (m = 0; m < nattr; m++) { rptr[m].name = strdup(fnptr->attrs[m]); PMIX_LOAD_KEY(rptr[m].string, pmix_attributes_lookup(fnptr->attrs[m])); dptr = pmix_attributes_lookup_term(fnptr->attrs[m]); if (NULL == dptr) { PMIx_Argv_free(tmp); PMIx_Argv_free(ans); PMIX_REGATTR_FREE(rptr, nattr); return NULL; } rptr[m].type = dptr->type; rptr[m].description = PMIx_Argv_copy(dptr->description); } } pmix_attributes_print_attrs(&ans, fnptr->function, rptr, nattr); PMIX_REGATTR_FREE(rptr, nattr); if (0 == strcmp(tmp[n], fnptr->function)) { break; } /* add a spacer between functions */ PMIx_Argv_append_nosize(&ans, " "); PMIx_Argv_append_nosize(&ans, line); PMIx_Argv_append_nosize(&ans, " "); } } } PMIx_Argv_free(tmp); return ans; } pmix-6.1.1~rc2/src/common/pfexec_linux.c0000664000175000017500000005303215203536752020414 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2022 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2007 Evergrid, Inc. All rights reserved. * Copyright (c) 2008-2017 Cisco Systems, Inc. All rights reserved * Copyright (c) 2010 IBM Corporation. All rights reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2017 Rutgers, The State University of New Jersey. * All rights reserved. * Copyright (c) 2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* * There is a complicated sequence of events that occurs when the * parent forks a child process that is intended to launch the target * executable. * * Before the child process exec's the target executable, it might tri * to set the affinity of that new child process according to a * complex series of rules. This binding may fail in a myriad of * different ways. A lot of this code deals with reporting that error * accurately to the end user. This is a complex task in itself * because the child process is not "really" an PMIX process -- all * error reporting must be proxied up to the parent who can use normal * PMIX error reporting mechanisms. * * Here's a high-level description of what is occurring in this file: * * - parent opens a pipe * - parent forks a child * - parent blocks reading on the pipe: the pipe will either close * (indicating that the child successfully exec'ed) or the child will * write some proxied error data up the pipe * * - the child tries to set affinity and do other housekeeping in * preparation of exec'ing the target executable * - if the child fails anywhere along the way, it sends a message up * the pipe to the parent indicating what happened -- including a * rendered error message detailing the problem (i.e., human-readable). * - it is important that the child renders the error message: there * are so many errors that are possible that the child is really the * only entity that has enough information to make an accuate error string * to report back to the user. * - the parent reads this message + rendered string in and uses PMIX * reporting mechanisms to display it to the user * - if the problem was only a warning, the child continues processing * (potentially eventually exec'ing the target executable). * - if the problem was an error, the child exits and the parent * handles the death of the child as appropriate (i.e., this PFEXEC * simply reports the error -- other things decide what to do). */ #include "pmix_config.h" #include "pmix.h" #include "src/include/pmix_types.h" #include #include #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_WAIT_H # include #endif #include #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #ifdef HAVE_NETDB_H # include #endif #include #ifdef HAVE_SYS_STAT_H # include #endif /* HAVE_SYS_STAT_H */ #include #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_DIRENT_H # include #endif #include #include "src/class/pmix_pointer_array.h" #include "src/util/pmix_error.h" #include "src/util/pmix_fd.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_show_help.h" #include "src/include/pmix_globals.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_name_fns.h" #include "src/mca/pfexec/base/base.h" #include "src/mca/pfexec/linux/pfexec_linux.h" /* * Module functions (function pointers used in a struct) */ static pmix_status_t spawn_job(pmix_pfexec_fork_caddy_t *fcd); static pmix_status_t kill_proc(pmix_proc_t *proc); static pmix_status_t signal_proc(pmix_proc_t *proc, int32_t signal); /* * Explicitly declared functions so that we can get the noreturn * attribute registered with the compiler. */ static void send_error_show_help(int fd, int exit_status, const char *file, const char *topic, ...) __pmix_attribute_noreturn__; static void do_child(pmix_app_t *cd, char **env, pmix_pfexec_child_t *child, int write_fd) __pmix_attribute_noreturn__; /* * Module */ pmix_pfexec_base_module_t pmix_pfexec_linux_module = { .spawn_job = spawn_job, .kill_proc = kill_proc, .signal_proc = signal_proc, }; /* deliver a signal to a specified pid. */ static pmix_status_t sigproc(pid_t pd, int signum) { pid_t pgrp; pid_t pid; pid = pd; #if HAVE_SETPGID pgrp = getpgid(pd); if (-1 != pgrp) { /* target the lead process of the process * group so we ensure that the signal is * seen by all members of that group. This * ensures that the signal is seen by any * child processes our child may have * started */ pid = -pgrp; } #endif if (0 != kill(pid, signum)) { if (ESRCH != errno) { pmix_output_verbose(2, pmix_pfexec_base_framework.framework_output, "%s pfexec:linux:SENT SIGNAL %d TO PID %d GOT ERRNO %d", PMIX_NAME_PRINT(&pmix_globals.myid), signum, (int) pid, errno); return errno; } } pmix_output_verbose(2, pmix_pfexec_base_framework.framework_output, "%s pfexec:linux:SENT SIGNAL %d TO PID %d SUCCESS", PMIX_NAME_PRINT(&pmix_globals.myid), signum, (int) pid); return 0; } static pmix_status_t kill_proc(pmix_proc_t *proc) { pmix_status_t rc; pmix_lock_t mylock; pmix_pfexec_signal_caddy_t *kcd; PMIX_CONSTRUCT_LOCK(&mylock); PMIX_PFEXEC_KILL(kcd, proc, sigproc, &mylock); PMIX_WAIT_THREAD(&mylock); rc = mylock.status; PMIX_DESTRUCT_LOCK(&mylock); PMIX_RELEASE(kcd); return rc; } static pmix_status_t signal_proc(pmix_proc_t *proc, int32_t signal) { pmix_status_t rc; pmix_lock_t mylock; pmix_pfexec_signal_caddy_t *scd; PMIX_CONSTRUCT_LOCK(&mylock); PMIX_PFEXEC_SIGNAL(scd, proc, signal, sigproc, &mylock); PMIX_WAIT_THREAD(&mylock); rc = mylock.status; PMIX_DESTRUCT_LOCK(&mylock); PMIX_RELEASE(scd); return rc; } static void set_handler_linux(int sig) { struct sigaction act; act.sa_handler = SIG_DFL; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(sig, &act, (struct sigaction *) 0); } /* * Internal function to write a rendered show_help message back up the * pipe to the waiting parent. */ static int write_help_msg(int fd, pmix_pfexec_pipe_err_msg_t *msg, const char *file, const char *topic, va_list ap) { int ret; char *str; if (NULL == file || NULL == topic) { return PMIX_ERR_BAD_PARAM; } str = pmix_show_help_vstring("pmix", file, topic, true, ap); msg->file_str_len = (int) strlen(file); if (msg->file_str_len > PMIX_PFEXEC_MAX_FILE_LEN) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } msg->topic_str_len = (int) strlen(topic); if (msg->topic_str_len > PMIX_PFEXEC_MAX_TOPIC_LEN) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } msg->msg_str_len = (int) strlen(str); /* Only keep writing if each write() succeeds */ if (PMIX_SUCCESS != (ret = pmix_fd_write(fd, sizeof(*msg), msg))) { goto out; } if (msg->file_str_len > 0 && PMIX_SUCCESS != (ret = pmix_fd_write(fd, msg->file_str_len, file))) { goto out; } if (msg->topic_str_len > 0 && PMIX_SUCCESS != (ret = pmix_fd_write(fd, msg->topic_str_len, topic))) { goto out; } if (msg->msg_str_len > 0 && PMIX_SUCCESS != (ret = pmix_fd_write(fd, msg->msg_str_len, str))) { goto out; } out: free(str); return ret; } /* Called from the child to send an error message up the pipe to the waiting parent. */ static void send_error_show_help(int fd, int exit_status, const char *file, const char *topic, ...) { va_list ap; pmix_pfexec_pipe_err_msg_t msg; msg.fatal = true; msg.exit_status = exit_status; /* Send it */ va_start(ap, topic); write_help_msg(fd, &msg, file, topic, ap); va_end(ap); exit(exit_status); } /* close all open file descriptors w/ exception of stdin/stdout/stderr the pipe up to the parent, and the keepalive pipe. */ static int close_open_file_descriptors(int write_fd, int keepalive) { #if defined(__OSX__) DIR *dir = opendir("/dev/fd"); #else /* Linux */ DIR *dir = opendir("/proc/self/fd"); #endif /* defined(__OSX__) */ if (NULL == dir) { return PMIX_ERR_FILE_OPEN_FAILURE; } struct dirent *files; /* grab the fd of the opendir above so we don't close in the * middle of the scan. */ int dir_scan_fd = dirfd(dir); if (dir_scan_fd < 0) { return PMIX_ERR_FILE_OPEN_FAILURE; } while (NULL != (files = readdir(dir))) { if (!isdigit(files->d_name[0])) { continue; } int fd = strtol(files->d_name, NULL, 10); if (errno == EINVAL || errno == ERANGE) { closedir(dir); return PMIX_ERR_TYPE_MISMATCH; } if (fd >= 3 && fd != write_fd && fd != dir_scan_fd && fd != keepalive) { close(fd); } } closedir(dir); return PMIX_SUCCESS; } static void do_child(pmix_app_t *app, char **env, pmix_pfexec_child_t *child, int write_fd) { int i, errval; sigset_t sigs; long fd, fdmax = sysconf(_SC_OPEN_MAX); char dir[MAXPATHLEN]; #if HAVE_SETPGID /* Set a new process group for this child, so that any * signals we send to it will reach any children it spawns */ setpgid(0, 0); #endif /* Setup the pipe to be close-on-exec */ pmix_fd_set_cloexec(write_fd); /* setup stdout/stderr so that any error messages that we may print out will get displayed back at pmixrun. NOTE: Definitely do this AFTER we check contexts so that any error message from those two functions doesn't come out to the user. IF we didn't do it in this order, THEN a user who gives us a bad executable name or working directory would get N error messages, where N=num_procs. This would be very annoying for large jobs, so instead we set things up so that pmixrun always outputs a nice, single message indicating what happened */ if (PMIX_SUCCESS != (i = pmix_pfexec_base_setup_child(child))) { PMIX_ERROR_LOG(i); send_error_show_help(write_fd, 1, "help-pfexec-base.txt", "iof setup failed", pmix_globals.hostname, app->cmd); /* Does not return */ } /* close all open file descriptors w/ exception of stdin/stdout/stderr, the pipe used for the IOF INTERNAL messages, and the pipe up to the parent. */ if (PMIX_SUCCESS != close_open_file_descriptors(write_fd, child->keepalive[1])) { // close *all* file descriptors -- slow for (fd = 3; fd < fdmax; fd++) { if (fd != write_fd && fd != child->keepalive[1]) { close(fd); } } } /* Set signal handlers back to the default. Do this close to the exev() because the event library may (and likely will) reset them. If we don't do this, the event library may have left some set that, at least on some OS's, don't get reset via fork() or exec(). Hence, the launched process could be unkillable (for example). */ set_handler_linux(SIGTERM); set_handler_linux(SIGINT); set_handler_linux(SIGHUP); set_handler_linux(SIGPIPE); set_handler_linux(SIGCHLD); /* Unblock all signals, for many of the same reasons that we set the default handlers, above. This is noticeable on Linux where the event library blocks SIGTERM, but we don't want that blocked by the launched process. */ sigprocmask(0, 0, &sigs); sigprocmask(SIG_UNBLOCK, &sigs, 0); /* take us to the correct wdir */ if (NULL != app->cwd) { if (0 != chdir(app->cwd)) { send_error_show_help(write_fd, 1, "help-pfexec-base.txt", "wdir-not-found", "pmixd", app->cwd, pmix_globals.hostname); /* Does not return */ } } /* Exec the new executable */ execve(app->cmd, app->argv, env); errval = errno; if (0 != getcwd(dir, sizeof(dir))) { pmix_strncpy(dir, "GETCWD-FAILED", sizeof(dir)); } send_error_show_help(write_fd, 1, "help-pfexec-base.txt", "execve error", pmix_globals.hostname, dir, app->cmd, strerror(errval)); /* Does not return */ } static pmix_status_t do_parent(pmix_app_t *app, pmix_pfexec_child_t *child, int read_fd) { pmix_status_t rc; pmix_pfexec_pipe_err_msg_t msg; char file[PMIX_PFEXEC_MAX_FILE_LEN + 1], topic[PMIX_PFEXEC_MAX_TOPIC_LEN + 1], *str = NULL; if (child->opts.connect_stdin && 0 <= child->opts.p_stdin[0]) { close(child->opts.p_stdin[0]); } if (0 <= child->opts.p_stdout[1]) { close(child->opts.p_stdout[1]); } if (0 <= child->opts.p_stderr[1]) close(child->opts.p_stderr[1]); if (0 <= child->keepalive[1]) { close(child->keepalive[1]); } /* Block reading a message from the pipe */ while (1) { rc = pmix_fd_read(read_fd, sizeof(msg), &msg); /* If the pipe closed, then the child successfully launched */ if (PMIX_ERR_TIMEOUT == rc) { break; } /* If Something Bad happened in the read, error out */ if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); close(read_fd); return rc; } /* Read in the strings; ensure to terminate them with \0 */ if (msg.file_str_len > 0) { rc = pmix_fd_read(read_fd, msg.file_str_len, file); if (PMIX_SUCCESS != rc) { pmix_show_help("help-pfexec-base.txt", "syscall fail", true, pmix_globals.hostname, app->cmd, "pmix_fd_read", __FILE__, __LINE__); return rc; } file[msg.file_str_len] = '\0'; } if (msg.topic_str_len > 0) { rc = pmix_fd_read(read_fd, msg.topic_str_len, topic); if (PMIX_SUCCESS != rc) { pmix_show_help("help-pfexec-base.txt", "syscall fail", true, pmix_globals.hostname, app->cmd, "pmix_fd_read", __FILE__, __LINE__); return rc; } topic[msg.topic_str_len] = '\0'; } if (msg.msg_str_len > 0) { str = calloc(1, msg.msg_str_len + 1); if (NULL == str) { pmix_show_help("help-pfexec-base.txt", "syscall fail", true, pmix_globals.hostname, app->cmd, "calloc", __FILE__, __LINE__); return PMIX_ERR_NOMEM; } rc = pmix_fd_read(read_fd, msg.msg_str_len, str); if (PMIX_SUCCESS != rc) { pmix_show_help("help-pfexec-base.txt", "syscall fail", true, pmix_globals.hostname, app->cmd, "pmix_fd_read", __FILE__, __LINE__); free(str); return rc; } str[msg.msg_str_len] = '\0'; // ensure NULL termination } /* Print out what we got. We already have a rendered string, so just print it. */ if (msg.msg_str_len > 0) { fprintf(stderr, "%s\n", str); free(str); str = NULL; } /* If msg.fatal is true, then the child exited with an error. Otherwise, whatever we just printed was a warning, so loop around and see what else is on the pipe (or if the pipe closed, indicating that the child launched successfully). */ if (msg.fatal) { close(read_fd); if (NULL != str) { free(str); } return PMIX_ERR_SYS_OTHER; } if (NULL != str) { free(str); str = NULL; } } /* If we got here, it means that the pipe closed without indication of a fatal error, meaning that the child process launched successfully. */ close(read_fd); return PMIX_SUCCESS; } /** * Fork/exec the specified processes */ static int fork_proc(pmix_app_t *app, pmix_pfexec_child_t *child, char **env) { int p[2]; /* A pipe is used to communicate between the parent and child to indicate whether the exec ultimately succeeded or failed. The child sets the pipe to be close-on-exec; the child only ever writes anything to the pipe if there is an error (e.g., executable not found, exec() fails, etc.). The parent does a blocking read on the pipe; if the pipe closed with no data, then the exec() succeeded. If the parent reads something from the pipe, then the child was letting us know why it failed. */ if (pipe(p) < 0) { PMIX_ERROR_LOG(PMIX_ERR_SYS_OTHER); return PMIX_ERR_SYS_OTHER; } /* Fork off the child */ child->pid = fork(); if (child->pid < 0) { PMIX_ERROR_LOG(PMIX_ERR_SYS_OTHER); return PMIX_ERR_SYS_OTHER; } if (child->pid == 0) { if (0 <= p[0]) { close(p[0]); } if (0 <= child->keepalive[0]) { close(child->keepalive[0]); child->keepalive[0] = -1; } do_child(app, env, child, p[1]); /* Does not return */ } close(p[1]); return do_parent(app, child, p[0]); } /* callback from the event library whenever a SIGCHLD is received */ static void wait_signal_callback(int fd, short event, void *arg) { (void) fd; (void) event; pmix_event_t *signal = (pmix_event_t *) arg; int status; pid_t pid; pmix_pfexec_child_t *child; PMIX_ACQUIRE_OBJECT(signal); if (SIGCHLD != PMIX_EVENT_SIGNAL(signal)) { return; } /* if we haven't spawned anyone, then ignore this */ if (0 == pmix_list_get_size(&pmix_pfexec_globals.children)) { return; } /* reap all queued waitpids until we * don't get anything valid back */ while (1) { pid = waitpid(-1, &status, WNOHANG); if (-1 == pid && EINTR == errno) { /* try it again */ continue; } /* if we got garbage, then nothing we can do */ if (pid <= 0) { return; } /* we are already in an event, so it is safe to access globals */ PMIX_LIST_FOREACH (child, &pmix_pfexec_globals.children, pmix_pfexec_child_t) { if (pid == child->pid) { /* record the exit status */ if (WIFEXITED(status)) { child->exitcode = WEXITSTATUS(status); } else { if (WIFSIGNALED(status)) { child->exitcode = WTERMSIG(status) + 128; } } /* mark the child as complete */ child->completed = true; if ((NULL == child->stdoutev || !child->stdoutev->active) && (NULL == child->stderrev || !child->stderrev->active)) { PMIX_PFEXEC_CHK_COMPLETE(child); } break; } } } } /** * Launch all processes allocated to the current node. */ static pmix_status_t spawn_job(pmix_pfexec_fork_caddy_t *fcd) { sigset_t unblock; pmix_output_verbose(5, pmix_pfexec_base_framework.framework_output, "%s pfexec:linux spawning child job", PMIX_NAME_PRINT(&pmix_globals.myid)); if (NULL == pmix_pfexec_globals.handler) { /* ensure that SIGCHLD is unblocked as we need to capture it */ if (0 != sigemptyset(&unblock)) { return PMIX_ERROR; } if (0 != sigaddset(&unblock, SIGCHLD)) { return PMIX_ERROR; } if (0 != sigprocmask(SIG_UNBLOCK, &unblock, NULL)) { return PMIX_ERR_NOT_SUPPORTED; } /* set to catch SIGCHLD events */ pmix_pfexec_globals.handler = (pmix_event_t *) malloc(sizeof(pmix_event_t)); pmix_event_set(pmix_globals.evauxbase, pmix_pfexec_globals.handler, SIGCHLD, PMIX_EV_SIGNAL | PMIX_EV_PERSIST, wait_signal_callback, pmix_pfexec_globals.handler); pmix_pfexec_globals.active = true; pmix_event_add(pmix_pfexec_globals.handler, NULL); } fcd->frkfn = fork_proc; PMIX_PFEXEC_SPAWN(fcd); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/common/pmix_iof.h0000664000175000017500000003374615203536752017554 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2017 IBM Corporation. All rights reserved. * Copyright (c) 2017 Mellanox Technologies. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * I/O Forwarding Service */ #ifndef PMIX_IOF_H #define PMIX_IOF_H #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_NET_UIO_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #include #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_fd.h" BEGIN_C_DECLS /* * Maximum size of single msg */ #define PMIX_IOF_BASE_MSG_MAX 8192 #define PMIX_IOF_BASE_TAG_MAX 1024 #define PMIX_IOF_MAX_INPUT_BUFFERS 50 #define PMIX_IOF_MAX_RETRIES 4 typedef struct { pmix_list_item_t super; bool pending; bool always_writable; int numtries; pmix_event_t *ev; struct timeval tv; int fd; pmix_list_t outputs; } pmix_iof_write_event_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_iof_write_event_t); #define PMIX_IOF_WRITE_EVENT_STATIC_INIT \ { \ .super = PMIX_LIST_ITEM_STATIC_INIT, \ .pending = false, \ .always_writable = false, \ .numtries = 0, \ .ev = NULL, \ .tv = {0, 0}, \ .fd = 0, \ .outputs = PMIX_LIST_STATIC_INIT \ } typedef struct { pmix_list_item_t super; pmix_proc_t name; pmix_iof_channel_t tag; pmix_iof_write_event_t wev; bool xoff; bool exclusive; bool closed; } pmix_iof_sink_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_iof_sink_t); #define PMIX_IOF_SINK_STATIC_INIT \ { \ .super = PMIX_LIST_ITEM_STATIC_INIT, \ .name = {{0}, 0}, \ .tag = PMIX_FWD_NO_CHANNELS, \ .wev = PMIX_IOF_WRITE_EVENT_STATIC_INIT, \ .xoff = false, \ .exclusive = false, \ .closed = false \ } typedef struct { pmix_list_item_t super; char *data; int numbytes; } pmix_iof_write_output_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_iof_write_output_t); typedef struct { pmix_object_t super; pmix_event_t ev; struct timeval tv; int fd; bool active; void *childproc; bool always_readable; pmix_proc_t name; pmix_iof_channel_t channel; pmix_proc_t *targets; size_t ntargets; pmix_info_t *directives; size_t ndirs; } pmix_iof_read_event_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_iof_read_event_t); typedef struct { pmix_list_item_t super; pmix_proc_t name; pmix_iof_write_event_t *channel; pmix_iof_flags_t flags; pmix_iof_channel_t stream; bool copystdout; bool copystderr; pmix_byte_object_t bo; } pmix_iof_residual_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_iof_residual_t); /* Write event macro's */ static inline bool pmix_iof_fd_always_ready(int fd) { return pmix_fd_is_regular(fd) || (pmix_fd_is_chardev(fd) && !isatty(fd)) || pmix_fd_is_blkdev(fd); } #define PMIX_IOF_SINK_BLOCKSIZE (1024) #define PMIX_IOF_SINK_ACTIVATE(w) \ do { \ struct timeval *tv = NULL; \ (w)->pending = true; \ PMIX_POST_OBJECT((w)); \ if ((w)->always_writable) { \ /* Regular is always write ready. Use timer to activate */ \ tv = &(w)->tv; \ } \ if (pmix_event_add((w)->ev, tv)) { \ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); \ } \ } while (0); /* define an output "sink", adding it to the provided * endpoint list for this proc */ #define PMIX_IOF_SINK_DEFINE(snk, nm, fid, tg, wrthndlr) \ do { \ pmix_output_verbose(1, pmix_client_globals.iof_output, \ "defining endpt: file %s line %d fd %d", __FILE__, __LINE__, (fid)); \ PMIX_CONSTRUCT((snk), pmix_iof_sink_t); \ pmix_strncpy((snk)->name.nspace, (nm)->nspace, PMIX_MAX_NSLEN); \ (snk)->name.rank = (nm)->rank; \ (snk)->tag = (tg); \ if (0 <= (fid)) { \ (snk)->wev.fd = (fid); \ (snk)->wev.always_writable = pmix_iof_fd_always_ready(fid); \ if ((snk)->wev.always_writable) { \ pmix_event_evtimer_set(pmix_globals.evbase, (snk)->wev.ev, wrthndlr, (snk)); \ } else { \ pmix_event_set(pmix_globals.evbase, (snk)->wev.ev, (snk)->wev.fd, PMIX_EV_WRITE, \ wrthndlr, (snk)); \ } \ } \ PMIX_POST_OBJECT(snk); \ } while (0); /* Read event macro's */ #define PMIX_IOF_READ_ADDEV(rev) \ do { \ struct timeval *tv = NULL; \ if ((rev)->always_readable) { \ tv = &(rev)->tv; \ } \ if (pmix_event_add(&(rev)->ev, tv)) { \ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); \ } \ } while (0); #define PMIX_IOF_READ_ACTIVATE(rev) \ do { \ (rev)->active = true; \ PMIX_POST_OBJECT(rev); \ PMIX_IOF_READ_ADDEV(rev); \ } while (0); #define PMIX_IOF_READ_EVENT(rv, p, np, d, nd, fid, cbfunc, actv) \ do { \ size_t _ii; \ pmix_iof_read_event_t *rev; \ pmix_output_verbose(1, pmix_client_globals.iof_output, "defining read event at: %s %d", \ __FILE__, __LINE__); \ rev = PMIX_NEW(pmix_iof_read_event_t); \ if (NULL != (p)) { \ (rev)->ntargets = (np); \ PMIX_PROC_CREATE((rev)->targets, (rev)->ntargets); \ memcpy((rev)->targets, (p), (np) * sizeof(pmix_proc_t)); \ } \ if (NULL != (d) && 0 < (nd)) { \ PMIX_INFO_CREATE((rev)->directives, (nd)); \ (rev)->ndirs = (nd); \ for (_ii = 0; _ii < (size_t) nd; _ii++) { \ PMIX_INFO_XFER(&((rev)->directives[_ii]), &((d)[_ii])); \ } \ } \ rev->fd = (fid); \ rev->always_readable = pmix_iof_fd_always_ready(fid); \ *(rv) = rev; \ if (rev->always_readable) { \ pmix_event_evtimer_set(pmix_globals.evbase, &rev->ev, (cbfunc), rev); \ } else { \ pmix_event_set(pmix_globals.evbase, &rev->ev, (fid), PMIX_EV_READ, (cbfunc), rev); \ } \ if ((actv)) { \ PMIX_IOF_READ_ACTIVATE(rev) \ } \ } while (0); #define PMIX_IOF_READ_EVENT_LOCAL(rv, fid, cbfunc, actv) \ do { \ pmix_iof_read_event_t *rev; \ pmix_output_verbose(1, pmix_client_globals.iof_output, "defining read event at: %s %d", \ __FILE__, __LINE__); \ rev = PMIX_NEW(pmix_iof_read_event_t); \ rev->fd = (fid); \ rev->always_readable = pmix_iof_fd_always_ready(fid); \ *(rv) = rev; \ if (rev->always_readable) { \ pmix_event_evtimer_set(pmix_globals.evbase, &rev->ev, (cbfunc), rev); \ } else { \ pmix_event_set(pmix_globals.evbase, &rev->ev, (fid), PMIX_EV_READ, (cbfunc), rev); \ } \ if ((actv)) { \ PMIX_IOF_READ_ACTIVATE(rev) \ } \ } while (0); PMIX_EXPORT pmix_status_t pmix_iof_flush(void); PMIX_EXPORT pmix_status_t pmix_iof_write_output(const pmix_proc_t *name, pmix_iof_channel_t stream, const pmix_byte_object_t *bo); PMIX_EXPORT void pmix_iof_static_dump_output(pmix_iof_sink_t *sink); PMIX_EXPORT void pmix_iof_write_handler(int fd, short event, void *cbdata); PMIX_EXPORT bool pmix_iof_stdin_check(int fd); PMIX_EXPORT void pmix_iof_read_local_handler(int unusedfd, short event, void *cbdata); PMIX_EXPORT void pmix_iof_stdin_cb(int fd, short event, void *cbdata); PMIX_EXPORT pmix_status_t pmix_iof_process_iof(pmix_iof_channel_t channels, const pmix_proc_t *source, const pmix_byte_object_t *bo, const pmix_info_t *info, size_t ninfo, pmix_iof_req_t *req); PMIX_EXPORT void pmix_iof_check_flags(pmix_info_t *info, pmix_iof_flags_t *flags); PMIX_EXPORT void pmix_iof_flush_residuals(void); PMIX_EXPORT pmix_byte_object_t* pmix_iof_prep_output(const pmix_proc_t *name, pmix_iof_flags_t *myflags, pmix_iof_channel_t stream, const pmix_byte_object_t *bo); END_C_DECLS #endif /* PMIX_IOF_H */ pmix-6.1.1~rc2/src/common/pmix_control.c0000664000175000017500000002373415203536752020446 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/pstat/pstat.h" #include "src/mca/ptl/ptl.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/server/pmix_server_ops.h" static void relcbfunc(void *cbdata) { pmix_cb_t *cd = (pmix_cb_t *) cbdata; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:job_ctrl release callback"); PMIX_RELEASE(cd); } static void query_cbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; pmix_status_t rc; pmix_cb_t *results; int cnt; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:job_ctrl cback from server with %d bytes", (int) buf->bytes_used); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { /* release the caller */ if (NULL != cd->cbfunc) { cd->cbfunc(PMIX_ERR_COMM_FAILURE, NULL, 0, cd->cbdata, NULL, NULL); } PMIX_RELEASE(cd); return; } results = PMIX_NEW(pmix_cb_t); /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &results->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS != results->status && PMIX_ERR_PARTIAL_SUCCESS != results->status) { goto complete; } /* unpack any returned data */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &results->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < results->ninfo) { results->infocopy = true; PMIX_INFO_CREATE(results->info, results->ninfo); cnt = results->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, results->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } complete: pmix_output_verbose(2, pmix_globals.debug_output, "pmix:job_ctrl cback from server releasing"); /* release the caller */ if (NULL != cd->cbfunc) { cd->cbfunc(results->status, results->info, results->ninfo, cd->cbdata, relcbfunc, results); } else { PMIX_RELEASE(results); } PMIX_RELEASE(cd); } static void acb(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; size_t n; cb->status = status; if (0 < ninfo) { // we ignore the info that was provided as that data belongs // to the original caller cb->infocopy = true; PMIX_INFO_CREATE(cb->info, ninfo); cb->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&cb->info[n], &info[n]); } } if (NULL != release_fn) { release_fn(release_cbdata); } if (NULL == cb->cbfunc.infofn) { PMIX_WAKEUP_THREAD(&cb->lock); } else { cb->cbfunc.infofn(cb->status, cb->info, cb->ninfo, cb->cbdata, relcbfunc, (void*)cb); } } PMIX_EXPORT pmix_status_t PMIx_Job_control(const pmix_proc_t targets[], size_t ntargets, const pmix_info_t directives[], size_t ndirs, pmix_info_t **results, size_t *nresults) { pmix_cb_t cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_globals.debug_output, "%s pmix:job_ctrl", PMIX_NAME_PRINT(&pmix_globals.myid)); /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ PMIX_CONSTRUCT(&cb, pmix_cb_t); if (PMIX_SUCCESS != (rc = PMIx_Job_control_nb(targets, ntargets, directives, ndirs, acb, &cb))) { PMIX_DESTRUCT(&cb); return rc; } /* wait for the operation to complete */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; if (0 < cb.ninfo) { if (NULL != results && NULL != nresults) { *results = cb.info; *nresults = cb.ninfo; cb.info = NULL; cb.ninfo = 0; } } PMIX_DESTRUCT(&cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:job_ctrl completed"); return rc; } static void _jctrlnb(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t*)cbdata; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); rc = pmix_host_server.job_control(&pmix_globals.myid, cb->procs, cb->nprocs, cb->info, cb->ninfo, acb, (void*)cb); if (PMIX_SUCCESS != rc) { if (NULL != cb->cbfunc.infofn) { cb->cbfunc.infofn(rc, NULL, 0, cb->cbdata, relcbfunc, (void*)cb); } else { PMIX_RELEASE(cb); } } } PMIX_EXPORT pmix_status_t PMIx_Job_control_nb(const pmix_proc_t targets[], size_t ntargets, const pmix_info_t directives[], size_t ndirs, pmix_info_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_JOB_CONTROL_CMD; pmix_status_t rc; pmix_query_caddy_t *qcd; pmix_cb_t *cb; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: job control called with %d directives", (int) ndirs); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* if we are the server, then we just issue the request and * return the response - must do it in our progress thread */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { if (NULL == pmix_host_server.job_control) { /* nothing we can do */ return PMIX_ERR_NOT_SUPPORTED; } pmix_output_verbose(2, pmix_globals.debug_output, "pmix:job_control handed to RM"); cb = PMIX_NEW(pmix_cb_t); cb->procs = (pmix_proc_t*)targets; cb->nprocs = ntargets; cb->info = (pmix_info_t*)directives; cb->ninfo = ndirs; cb->cbfunc.infofn = cbfunc; cb->cbdata = cbdata; PMIX_THREADSHIFT(cb, _jctrlnb); return PMIX_SUCCESS; } /* we need to send, so check for connection */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } /* if we are a client, then relay this request to the server */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the number of targets */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ntargets, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* remember, the targets can be NULL to indicate that the operation * is to be done against all members of our nspace */ if (NULL != targets && 0 < ntargets) { /* pack the targets */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, targets, ntargets, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* pack the directives */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (NULL != directives && 0 < ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, directives, ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ qcd = PMIX_NEW(pmix_query_caddy_t); qcd->cbfunc = cbfunc; qcd->cbdata = cbdata; /* threadshift the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, query_cbfunc, (void *) qcd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(qcd); } return rc; } pmix-6.1.1~rc2/src/common/pmix_pfexec.c0000664000175000017500000013331415203536752020234 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2011 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2011-2017 Cisco Systems, Inc. All rights reserved * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2017 Mellanox Technologies Ltd. All rights reserved. * Copyright (c) 2017 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022 Amazon.com, Inc. or its affiliates. * All Rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include #include #ifdef HAVE_SYS_WAIT_H # include #endif #include #ifdef HAVE_UTIL_H # include #endif #ifdef HAVE_PTY_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_TERMIOS_H # include # ifdef HAVE_TERMIO_H # include # endif #endif #ifdef HAVE_LIBUTIL_H # include #endif #ifdef HAVE_DIRENT_H # include #endif #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_stdint.h" #include "src/mca/gds/base/base.h" #include "src/mca/ptl/base/base.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_context_fns.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_os_dirpath.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_path.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_pty.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "src/client/pmix_client_ops.h" #include "src/common/pmix_pfexec.h" #include "src/server/pmix_server_ops.h" #ifndef MAXPATHLEN /* Hurd */ #define MAXPATHLEN 1024 #endif static pmix_status_t setup_prefork(pmix_pfexec_child_t *child); static pmix_status_t register_nspace(char *nspace, pmix_setup_caddy_t *fcd); static void wait_signal_callback(int fd, short event, void *arg); static int fork_proc(pmix_app_t *app, pmix_pfexec_child_t *child, char **env); pmix_pfexec_globals_t pmix_pfexec_globals = { .handler = NULL, .active = false, .children = PMIX_LIST_STATIC_INIT, .timeout_before_sigkill = 0, .nextid = 0, .selected = false }; int pmix_pfexec_base_close(void) { if (pmix_pfexec_globals.active) { pmix_event_del(pmix_pfexec_globals.handler); pmix_pfexec_globals.active = false; } PMIX_LIST_DESTRUCT(&pmix_pfexec_globals.children); free(pmix_pfexec_globals.handler); pmix_pfexec_globals.selected = false; return PMIX_SUCCESS; } static void _ntfy_done(pmix_status_t status, void *cbdata) { pmix_pfexec_cmpl_caddy_t *cd = (pmix_pfexec_cmpl_caddy_t*)cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_RELEASE(cd->child); PMIX_RELEASE(cd); } void pmix_pfexec_check_complete(int sd, short args, void *cbdata) { pmix_pfexec_cmpl_caddy_t *cd = (pmix_pfexec_cmpl_caddy_t *) cbdata; pmix_status_t rc; pmix_pfexec_child_t *child; bool stillalive = false; pmix_proc_t wildcard; PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_list_remove_item(&pmix_pfexec_globals.children, &cd->child->super); /* see if any more children from this nspace are alive */ PMIX_LIST_FOREACH (child, &pmix_pfexec_globals.children, pmix_pfexec_child_t) { if (PMIX_CHECK_NSPACE(child->proc.nspace, cd->child->proc.nspace)) { stillalive = true; } } if (!stillalive) { /* generate a local event indicating job terminated */ PMIX_INFO_LOAD(&cd->info[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); PMIX_LOAD_NSPACE(wildcard.nspace, cd->child->proc.nspace); PMIX_INFO_LOAD(&cd->info[1], PMIX_EVENT_AFFECTED_PROC, &wildcard, PMIX_PROC); rc = PMIx_Notify_event(PMIX_ERR_JOB_TERMINATED, &pmix_globals.myid, PMIX_RANGE_PROC_LOCAL, cd->info, 2, _ntfy_done, cd); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd->child); PMIX_RELEASE(cd); } } } int pmix_pfexec_register(void) { pmix_pfexec_globals.timeout_before_sigkill = 1; pmix_mca_base_var_register("pmix", "pfexec", "base", "sigkill_timeout", "Time to wait for a process to die after issuing a kill signal to it", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_pfexec_globals.timeout_before_sigkill); return PMIX_SUCCESS; } /** * Function for finding and opening either all MCA components, or the one * that was specifically requested via a MCA parameter. */ int pmix_pfexec_base_open(void) { memset(&pmix_pfexec_globals, 0, sizeof(pmix_pfexec_globals_t)); /* setup the list of children */ PMIX_CONSTRUCT(&pmix_pfexec_globals.children, pmix_list_t); pmix_pfexec_globals.nextid = 1; /* Open up all available components */ return PMIX_SUCCESS; } static pmix_status_t setup_path(pmix_app_t *app) { pmix_status_t rc; char dir[MAXPATHLEN]; /* see if the app specifies a working dir */ if (NULL != app->cwd) { /* Try to change to the app's cwd and check that the app exists and is executable The function will take care of outputting a pretty error message, if required */ if (PMIX_SUCCESS != (rc = pmix_util_check_context_cwd(&app->cwd, true, true))) { /* do not ERROR_LOG - it will be reported elsewhere */ return rc; } /* The prior function will have done a chdir() to jump us to * wherever the app is to be executed. It seems that chdir doesn't * adjust the $PWD enviro variable when it changes the directory. This * can cause a user to get a different response when doing getcwd vs * looking at the enviro variable. To keep this consistent, we explicitly * ensure that the PWD enviro variable matches the CWD we moved to. * * NOTE: if a user's program does a chdir(), then $PWD will once * again not match getcwd! This is beyond our control - we are only * ensuring they start out matching. */ if (NULL == getcwd(dir, sizeof(dir))) { return PMIX_ERR_OUT_OF_RESOURCE; } PMIx_Setenv("PWD", dir, true, &app->env); } /* ensure the app is pointing to a full path */ rc = pmix_util_check_context_app(&app->cmd, app->cwd, app->env); return rc; } pmix_status_t pmix_pfexec_base_spawn_job(pmix_setup_caddy_t *fcd) { sigset_t unblock; pmix_output_verbose(5, pmix_client_globals.spawn_output, "%s pfexec:linux spawning child job", PMIX_NAME_PRINT(&pmix_globals.myid)); if (NULL == pmix_pfexec_globals.handler) { /* ensure that SIGCHLD is unblocked as we need to capture it */ if (0 != sigemptyset(&unblock)) { return PMIX_ERROR; } if (0 != sigaddset(&unblock, SIGCHLD)) { return PMIX_ERROR; } if (0 != sigprocmask(SIG_UNBLOCK, &unblock, NULL)) { return PMIX_ERR_NOT_SUPPORTED; } /* set to catch SIGCHLD events */ pmix_pfexec_globals.handler = (pmix_event_t *) malloc(sizeof(pmix_event_t)); pmix_event_set(pmix_globals.evauxbase, pmix_pfexec_globals.handler, SIGCHLD, PMIX_EV_SIGNAL | PMIX_EV_PERSIST, wait_signal_callback, pmix_pfexec_globals.handler); pmix_pfexec_globals.active = true; pmix_event_add(pmix_pfexec_globals.handler, NULL); } PMIX_PFEXEC_SPAWN(fcd); return PMIX_SUCCESS; } void pmix_pfexec_base_spawn_proc(int sd, short args, void *cbdata) { pmix_setup_caddy_t *fcd = (pmix_setup_caddy_t *) cbdata; pmix_app_t *app; int i, n; size_t m, k; pmix_status_t rc; char **argv = NULL, **env = NULL; pmix_nspace_t nspace; char basedir[MAXPATHLEN], sock[10]; pmix_pfexec_child_t *child; pmix_rank_info_t *info; pmix_namespace_t *nptr; pmix_rank_t rank = 0; char tmp[2048]; bool nohup = false; char *security_mode; PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(5, pmix_client_globals.spawn_output, "%s pfexec:base spawn proc", PMIX_NAME_PRINT(&pmix_globals.myid)); /* establish our baseline working directory - we will be potentially * bouncing around as we execute various apps, but we will always return * to this place as our default directory */ if (NULL == getcwd(basedir, sizeof(basedir))) { rc = PMIX_ERROR; goto complete; } /* create a namespace for the new job */ memset(tmp, 0, 2048); (void) pmix_snprintf(tmp, 2047, "%s:%lu", pmix_globals.myid.nspace, (unsigned long) pmix_pfexec_globals.nextid); PMIX_LOAD_NSPACE(nspace, tmp); ++pmix_pfexec_globals.nextid; /* add the nspace to the server global list */ nptr = PMIX_NEW(pmix_namespace_t); nptr->nspace = strdup(nspace); pmix_list_append(&pmix_globals.nspaces, &nptr->super); /* locally cache any job info that will later need to * be communicated to the spawned job */ rc = register_nspace(nspace, fcd); if (PMIX_SUCCESS != rc) { pmix_list_remove_item(&pmix_globals.nspaces, &nptr->super); PMIX_RELEASE(nptr); goto complete; } for (k = 0; k < fcd->ninfo; k++) { if (PMIX_CHECK_KEY(&fcd->info[k], PMIX_SET_ENVAR)) { } else if (PMIX_CHECK_KEY(&fcd->info[k], PMIX_ADD_ENVAR)) { } else if (PMIX_CHECK_KEY(&fcd->info[k], PMIX_UNSET_ENVAR)) { } else if (PMIX_CHECK_KEY(&fcd->info[k], PMIX_PREPEND_ENVAR)) { } else if (PMIX_CHECK_KEY(&fcd->info[k], PMIX_APPEND_ENVAR)) { } else if (PMIX_CHECK_KEY(&fcd->info[k], PMIX_NOHUP)) { nohup = PMIX_INFO_TRUE(&fcd->info[k]); } } /* cycle across the apps to prep their environment and * launch their procs */ for (m = 0; m < fcd->napps; m++) { app = (pmix_app_t *) &fcd->apps[m]; /* merge our launch environment into the app's */ rc = pmix_environ_merge_inplace(&app->env, environ); if (PMIX_SUCCESS != rc) { goto complete; } /* check for a fork/exec agent we should use */ if (NULL != app->info) { for (k = 0; k < app->ninfo; k++) { if (PMIX_CHECK_KEY(&app->info[k], PMIX_FORKEXEC_AGENT)) { /* we were given a fork agent - use it. We have to put its * argv at the beginning of the app argv array */ argv = PMIx_Argv_split(app->info[k].value.data.string, ' '); /* add in the argv from the app */ for (i = 0; NULL != argv[i]; i++) { PMIx_Argv_prepend_nosize(&app->argv, argv[i]); } if (NULL != app->cmd) { free(app->cmd); } app->cmd = pmix_path_findv(argv[0], X_OK, app->env, NULL); if (NULL == app->cmd) { pmix_show_help("help-pfexec-base.txt", "fork-agent-not-found", true, pmix_globals.hostname, argv[0]); rc = PMIX_ERR_NOT_FOUND; PMIx_Argv_free(argv); goto complete; } PMIx_Argv_free(argv); } } } /* setup the path */ if (PMIX_SUCCESS != (rc = setup_path(app))) { goto complete; } for (n = 0; n < app->maxprocs; n++) { /* create a tracker for this child */ child = PMIX_NEW(pmix_pfexec_child_t); PMIX_LOAD_PROCID(&child->proc, nspace, rank); ++rank; pmix_list_append(&pmix_pfexec_globals.children, &child->super); /* setup any IOF */ child->opts.usepty = PMIX_ENABLE_PTY_SUPPORT; if (PMIX_SUCCESS != (rc = setup_prefork(child))) { PMIX_ERROR_LOG(rc); pmix_list_remove_item(&pmix_pfexec_globals.children, &child->super); PMIX_RELEASE(child); goto complete; } /* track some details about the child from our * perspective - note that the child may determine * its own nspace/rank, but that is irrelevant here * as we just need an ID for our own internal tracking */ info = PMIX_NEW(pmix_rank_info_t); if (NULL == info) { rc = PMIX_ERR_NOMEM; pmix_list_remove_item(&pmix_pfexec_globals.children, &child->super); PMIX_RELEASE(child); goto complete; } info->pname.nspace = strdup(child->proc.nspace); info->pname.rank = child->proc.rank; info->uid = pmix_globals.uid; info->gid = pmix_globals.gid; pmix_list_append(&nptr->ranks, &info->super); /* setup the environment */ env = PMIx_Argv_copy(app->env); /* we only support the start of tools and servers, not apps, * so we don't register this nspace or child. However, we do * still want to pass along our connection info and active * modules so the forked process can connect back to us */ /* pass the nspace */ PMIx_Setenv("PMIX_NAMESPACE", child->proc.nspace, true, &env); PMIx_Setenv("PMIX_SERVER_NSPACE", child->proc.nspace, true, &env); /* pass the rank */ memset(tmp, 0, 2048); (void) pmix_snprintf(tmp, 2047, "%u", child->proc.rank); PMIx_Setenv("PMIX_RANK", tmp, true, &env); PMIx_Setenv("PMIX_SERVER_RANK", tmp, true, &env); /* pass our active security modules */ security_mode = pmix_psec_base_get_available_modules(); PMIx_Setenv("PMIX_SECURITY_MODE", security_mode, true, &env); free(security_mode); /* pass the type of buffer we are using */ if (PMIX_BFROP_BUFFER_FULLY_DESC == pmix_globals.mypeer->nptr->compat.type) { PMIx_Setenv("PMIX_BFROP_BUFFER_TYPE", "PMIX_BFROP_BUFFER_FULLY_DESC", true, &env); } else { PMIx_Setenv("PMIX_BFROP_BUFFER_TYPE", "PMIX_BFROP_BUFFER_NON_DESC", true, &env); } /* get any PTL contribution such as tmpdir settings for session files */ if (PMIX_SUCCESS != (rc = pmix_ptl.setup_fork(&child->proc, &env))) { PMIX_ERROR_LOG(rc); pmix_list_remove_item(&pmix_pfexec_globals.children, &child->super); PMIX_RELEASE(child); goto complete; } /* ensure we agree on our hostname */ PMIx_Setenv("PMIX_HOSTNAME", pmix_globals.hostname, true, &env); /* communicate our version */ PMIx_Setenv("PMIX_VERSION", PMIX_VERSION, true, &env); /* setup a keepalive pipe unless "nohup" was given */ if (!nohup) { rc = pipe(child->keepalive); if (0 != rc) { PMIX_ERROR_LOG(PMIX_ERR_SYS_OTHER); pmix_list_remove_item(&pmix_pfexec_globals.children, &child->super); PMIX_RELEASE(child); goto complete; } pmix_snprintf(sock, 10, "%d", child->keepalive[1]); PMIx_Setenv("PMIX_KEEPALIVE_PIPE", sock, true, &env); } pmix_output_verbose(5, pmix_client_globals.spawn_output, "%s pfexec:base spawning child %s", PMIX_NAME_PRINT(&pmix_globals.myid), app->cmd); rc = fork_proc(app, child, env); PMIx_Argv_free(env); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); pmix_list_remove_item(&pmix_pfexec_globals.children, &child->super); PMIX_RELEASE(child); goto complete; } PMIX_IOF_READ_ACTIVATE(child->stdoutev); PMIX_IOF_READ_ACTIVATE(child->stderrev); } } rc = PMIX_SUCCESS; complete: /* ensure we reset our working directory back to our default location */ if (0 != chdir(basedir)) { PMIX_ERROR_LOG(PMIX_ERROR); } /* execute the callback */ fcd->spcbfunc(rc, nspace, fcd->cbdata); PMIX_RELEASE(fcd); return; } /* deliver a signal to a specified pid. */ static pmix_status_t sigproc(pid_t pd, int signum) { pid_t pgrp; pid_t pid; pid = pd; #if HAVE_SETPGID pgrp = getpgid(pd); if (-1 != pgrp) { /* target the lead process of the process * group so we ensure that the signal is * seen by all members of that group. This * ensures that the signal is seen by any * child processes our child may have * started */ pid = -pgrp; } #endif if (0 != kill(pid, signum)) { if (ESRCH != errno) { pmix_output_verbose(2, pmix_client_globals.spawn_output, "%s pfexec:linux:SENT SIGNAL %d TO PID %d GOT ERRNO %d", PMIX_NAME_PRINT(&pmix_globals.myid), signum, (int) pid, errno); return errno; } } pmix_output_verbose(2, pmix_client_globals.spawn_output, "%s pfexec:linux:SENT SIGNAL %d TO PID %d SUCCESS", PMIX_NAME_PRINT(&pmix_globals.myid), signum, (int) pid); return 0; } void pmix_pfexec_base_kill_proc(int sd, short args, void *cbdata) { pmix_pfexec_signal_caddy_t *scd = (pmix_pfexec_signal_caddy_t *) cbdata; pmix_pfexec_child_t *child, *cd; PMIX_HIDE_UNUSED_PARAMS(sd, args); /* find the process */ child = NULL; PMIX_LIST_FOREACH (cd, &pmix_pfexec_globals.children, pmix_pfexec_child_t) { if (PMIX_CHECK_PROCID(scd->proc, &cd->proc)) { child = cd; break; } } if (NULL == child) { scd->lock->status = PMIX_SUCCESS; PMIX_WAKEUP_THREAD(scd->lock); PMIX_RELEASE(scd); return; } /* remove the child from the list so waitpid callback won't * find it as this induces unmanageable race * conditions when we are deliberately killing the process */ pmix_list_remove_item(&pmix_pfexec_globals.children, &child->super); /* First send a SIGCONT in case the process is in stopped state. If it is in a stopped state and we do not first change it to running, then SIGTERM will not get delivered. Ignore return value. */ pmix_output_verbose(5, pmix_client_globals.spawn_output, "%s SENDING SIGCONT", PMIX_NAME_PRINT(&pmix_globals.myid)); sigproc(child->pid, SIGCONT); /* wait a little to give the proc a chance to wakeup */ sleep(pmix_pfexec_globals.timeout_before_sigkill); /* issue a SIGTERM */ pmix_output_verbose(5, pmix_client_globals.spawn_output, "%s SENDING SIGTERM", PMIX_NAME_PRINT(&pmix_globals.myid)); scd->lock->status = sigproc(child->pid, SIGTERM); if (0 != scd->lock->status) { /* wait a little again */ sleep(pmix_pfexec_globals.timeout_before_sigkill); /* issue a SIGKILL */ pmix_output_verbose(5, pmix_client_globals.spawn_output, "%s SENDING SIGKILL", PMIX_NAME_PRINT(&pmix_globals.myid)); scd->lock->status = sigproc(child->pid, SIGKILL); } /* cleanup */ PMIX_RELEASE(child); PMIX_WAKEUP_THREAD(scd->lock); PMIX_RELEASE(scd); return; } void pmix_pfexec_base_signal_proc(int sd, short args, void *cbdata) { pmix_pfexec_signal_caddy_t *scd = (pmix_pfexec_signal_caddy_t *) cbdata; pmix_pfexec_child_t *child, *cd; PMIX_HIDE_UNUSED_PARAMS(sd, args); /* find the process */ child = NULL; PMIX_LIST_FOREACH (cd, &pmix_pfexec_globals.children, pmix_pfexec_child_t) { if (PMIX_CHECK_PROCID(scd->proc, &cd->proc)) { child = cd; break; } } if (NULL == child) { scd->lock->status = PMIX_SUCCESS; PMIX_WAKEUP_THREAD(scd->lock); return; } pmix_output_verbose(5, pmix_client_globals.spawn_output, "%s SIGNALING %d", PMIX_NAME_PRINT(&pmix_globals.myid), scd->signal); scd->lock->status = sigproc(child->pid, scd->signal); PMIX_WAKEUP_THREAD(scd->lock); } static pmix_status_t setup_prefork(pmix_pfexec_child_t *child) { int ret = -1; pmix_pfexec_base_io_conf_t *opts = &child->opts; fflush(stdout); /* first check to make sure we can do ptys */ #if PMIX_ENABLE_PTY_SUPPORT if (opts->usepty) { ret = pmix_openpty(&(opts->p_stdout[0]), &(opts->p_stdout[1]), (char *) NULL, (struct termios *) NULL, (struct winsize *) NULL); } #else opts->usepty = 0; #endif if (ret < 0) { opts->usepty = 0; if (pipe(opts->p_stdout) < 0) { PMIX_ERROR_LOG(PMIX_ERR_SYS_OTHER); return PMIX_ERR_SYS_OTHER; } } /* always leave stdin available in case we forward to it */ if (pipe(opts->p_stdin) < 0) { PMIX_ERROR_LOG(PMIX_ERR_SYS_OTHER); return PMIX_ERR_SYS_OTHER; } if (pipe(opts->p_stderr) < 0) { PMIX_ERROR_LOG(PMIX_ERR_SYS_OTHER); return PMIX_ERR_SYS_OTHER; } /* connect read/write ends to IOF */ PMIX_IOF_SINK_DEFINE(&child->stdinsink, &child->proc, opts->p_stdin[1], PMIX_FWD_STDIN_CHANNEL, pmix_iof_write_handler); PMIX_IOF_READ_EVENT_LOCAL(&child->stdoutev, opts->p_stdout[0], pmix_iof_read_local_handler, false); PMIX_LOAD_PROCID(&child->stdoutev->name, child->proc.nspace, child->proc.rank); child->stdoutev->childproc = (void *) child; child->stdoutev->channel = PMIX_FWD_STDOUT_CHANNEL; PMIX_IOF_READ_EVENT_LOCAL(&child->stderrev, opts->p_stderr[0], pmix_iof_read_local_handler, false); PMIX_LOAD_PROCID(&child->stderrev->name, child->proc.nspace, child->proc.rank); child->stderrev->childproc = (void *) child; child->stderrev->channel = PMIX_FWD_STDERR_CHANNEL; return PMIX_SUCCESS; } pmix_status_t pmix_pfexec_base_setup_child(pmix_pfexec_child_t *child) { int ret; pmix_pfexec_base_io_conf_t *opts = &child->opts; if (0 <= opts->p_stdin[1]) { close(opts->p_stdin[1]); opts->p_stdin[1] = -1; } if (0 <= opts->p_stdout[0]) { close(opts->p_stdout[0]); opts->p_stdout[0] = -1; } if (0 <= opts->p_stderr[0]) { close(opts->p_stderr[0]); opts->p_stderr[0] = -1; } if (opts->usepty) { /* disable echo */ struct termios term_attrs; if (tcgetattr(opts->p_stdout[1], &term_attrs) < 0) { return PMIX_ERR_SYS_OTHER; } term_attrs.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | ECHONL); term_attrs.c_iflag &= ~(ICRNL | INLCR | ISTRIP | INPCK | IXON); term_attrs.c_oflag &= ~(OCRNL | ONLCR); if (tcsetattr(opts->p_stdout[1], TCSANOW, &term_attrs) == -1) { return PMIX_ERR_SYS_OTHER; } ret = dup2(opts->p_stdout[1], fileno(stdout)); if (ret < 0) { return PMIX_ERR_SYS_OTHER; } if (0 <= opts->p_stdout[1]) { close(opts->p_stdout[1]); opts->p_stdout[1] = -1; } } else { if (opts->p_stdout[1] != fileno(stdout)) { ret = dup2(opts->p_stdout[1], fileno(stdout)); if (ret < 0) { return PMIX_ERR_SYS_OTHER; } if (0 <= opts->p_stdout[1]) { close(opts->p_stdout[1]); opts->p_stdout[1] = -1; } } } if (opts->p_stdin[0] != fileno(stdin)) { ret = dup2(opts->p_stdin[0], fileno(stdin)); if (ret < 0) { return PMIX_ERR_SYS_OTHER; } if (0 <= opts->p_stdin[0]) { close(opts->p_stdin[0]); opts->p_stdin[0] = -1; } } if (opts->p_stderr[1] != fileno(stderr)) { ret = dup2(opts->p_stderr[1], fileno(stderr)); if (ret < 0) { return PMIX_ERR_SYS_OTHER; } if (0 <= opts->p_stderr[1]) { close(opts->p_stderr[1]); opts->p_stderr[1] = -1; } } return PMIX_SUCCESS; } static pmix_status_t register_nspace(char *nspace, pmix_setup_caddy_t *fcd) { pmix_status_t rc; size_t n, ninfo; int m; uint32_t nprocs, u32; uint16_t u16; pmix_proc_t proc; pmix_rank_t zero = 0, rk; pmix_info_t *info = NULL; pmix_namespace_t *nptr, *tmp; void *jinfo, *tmpinfo, *pinfo; pmix_data_array_t darray; char *str; /* quick compute the number of procs to be started */ nprocs = 0; for (n = 0; n < fcd->napps; n++) { nprocs += fcd->apps[n].maxprocs; } if (0 == nprocs) { return PMIX_ERR_BAD_PARAM; } /* see if we already have this nspace */ nptr = NULL; PMIX_LIST_FOREACH (tmp, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(tmp->nspace, nspace)) { nptr = tmp; break; } } if (NULL == nptr) { nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { return PMIX_ERR_NOMEM; } nptr->nspace = strdup(nspace); pmix_list_append(&pmix_globals.nspaces, &nptr->super); } nptr->nlocalprocs = nprocs; /* start assembling the list */ PMIX_INFO_LIST_START(jinfo); /* jobid */ PMIX_LOAD_PROCID(&proc, nspace, PMIX_RANK_UNDEF); PMIX_INFO_LIST_ADD(rc, jinfo, PMIX_JOBID, &proc, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_INFO_LIST_RELEASE(jinfo); return rc; } /* hostname */ PMIX_INFO_LIST_ADD(rc, jinfo, PMIX_HOSTNAME, pmix_globals.hostname, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_INFO_LIST_RELEASE(jinfo); return rc; } /* mark us as the parent */ PMIX_INFO_LIST_ADD(rc, jinfo, PMIX_PARENT_ID, &pmix_globals.myid, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_INFO_LIST_RELEASE(jinfo); return rc; } /* node size */ PMIX_INFO_LIST_ADD(rc, jinfo, PMIX_NODE_SIZE, &nprocs, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_INFO_LIST_RELEASE(jinfo); return rc; } /* local size */ PMIX_INFO_LIST_ADD(rc, jinfo, PMIX_LOCAL_SIZE, &nprocs, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_INFO_LIST_RELEASE(jinfo); return rc; } /* local leader */ PMIX_INFO_LIST_ADD(rc, jinfo, PMIX_LOCALLDR, &zero, PMIX_PROC_RANK); if (PMIX_SUCCESS != rc) { PMIX_INFO_LIST_RELEASE(jinfo); return rc; } /* add in any info provided by the caller */ for (n = 0; n < fcd->ninfo; n++) { if (PMIX_ENVAR == fcd->info[n].value.type) { continue; // take care of these elsewhere } PMIX_INFO_LIST_XFER(rc, jinfo, &fcd->info[n]); } /* for each app in the job, create an app-array */ proc.rank = 0; rk = 0; for (n = 0; n < fcd->napps; n++) { PMIX_INFO_LIST_START(tmpinfo); u32 = n; PMIX_INFO_LIST_ADD(rc, tmpinfo, PMIX_APPNUM, &u32, PMIX_UINT32); u32 = fcd->apps[n].maxprocs; PMIX_INFO_LIST_ADD(rc, tmpinfo, PMIX_APP_SIZE, &u32, PMIX_UINT32); PMIX_INFO_LIST_ADD(rc, tmpinfo, PMIX_APPLDR, &proc.rank, PMIX_PROC_RANK); proc.rank += fcd->apps[n].maxprocs; if (NULL != fcd->apps[n].cwd) { PMIX_INFO_LIST_ADD(rc, tmpinfo, PMIX_WDIR, fcd->apps[n].cwd, PMIX_STRING); } str = PMIx_Argv_join(fcd->apps[n].argv, ' '); PMIX_INFO_LIST_ADD(rc, tmpinfo, PMIX_APP_ARGV, str, PMIX_STRING); /* convert the list into an array */ PMIX_INFO_LIST_CONVERT(rc, tmpinfo, &darray); /* release the list */ PMIX_INFO_LIST_RELEASE(tmpinfo); /* add it to the job info array */ PMIX_INFO_LIST_ADD(rc, jinfo, PMIX_APP_INFO_ARRAY, &darray, PMIX_DATA_ARRAY); /* release the memory - the array was copied */ PMIX_DATA_ARRAY_DESTRUCT(&darray); /* for each proc in this app, create a proc-array */ for (m = 0; m < fcd->apps[n].maxprocs; m++) { PMIX_INFO_LIST_START(pinfo); /* must start with the rank */ PMIX_INFO_LIST_ADD(rc, pinfo, PMIX_RANK, &rk, PMIX_PROC_RANK); ++rk; /* app number for this proc */ u32 = n; PMIX_INFO_LIST_ADD(rc, pinfo, PMIX_APPNUM, &u32, PMIX_UINT32); /* local rank is the same as rank since we only fork locally */ u16 = rk; PMIX_INFO_LIST_ADD(rc, pinfo, PMIX_LOCAL_RANK, &u16, PMIX_UINT16); /* convert the list into an array */ PMIX_INFO_LIST_CONVERT(rc, pinfo, &darray); /* release the list */ PMIX_INFO_LIST_RELEASE(pinfo); /* add it to the job info array */ PMIX_INFO_LIST_ADD(rc, jinfo, PMIX_PROC_DATA, &darray, PMIX_DATA_ARRAY); /* release the memory - the array was copied */ PMIX_DATA_ARRAY_DESTRUCT(&darray); } } /* convert the full list of job info into an array */ PMIX_INFO_LIST_CONVERT(rc, jinfo, &darray); PMIX_INFO_LIST_RELEASE(jinfo); info = (pmix_info_t *) darray.array; ninfo = darray.size; /* register nspace for each activate components */ PMIX_GDS_ADD_NSPACE(rc, nptr->nspace, nprocs, info, ninfo); if (PMIX_SUCCESS == rc) { /* store this data in our own GDS module - we will retrieve * it later so it can be passed down to the launched procs * once they connect to us and we know what GDS module they * are using */ PMIX_GDS_CACHE_JOB_INFO(rc, pmix_globals.mypeer, nptr, info, ninfo); } PMIX_DATA_ARRAY_DESTRUCT(&darray); return rc; } static void set_handler_linux(int sig) { struct sigaction act; act.sa_handler = SIG_DFL; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(sig, &act, (struct sigaction *) 0); } /* * Internal function to write a rendered show_help message back up the * pipe to the waiting parent. */ static int write_help_msg(int fd, pmix_pfexec_pipe_err_msg_t *msg, const char *file, const char *topic, va_list ap) { int ret; char *str; if (NULL == file || NULL == topic) { return PMIX_ERR_BAD_PARAM; } str = pmix_show_help_vstring(file, topic, true, ap); msg->file_str_len = (int) strlen(file); if (msg->file_str_len > PMIX_PFEXEC_MAX_FILE_LEN) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } msg->topic_str_len = (int) strlen(topic); if (msg->topic_str_len > PMIX_PFEXEC_MAX_TOPIC_LEN) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } msg->msg_str_len = (int) strlen(str); /* Only keep writing if each write() succeeds */ if (PMIX_SUCCESS != (ret = pmix_fd_write(fd, sizeof(*msg), msg))) { goto out; } if (msg->file_str_len > 0 && PMIX_SUCCESS != (ret = pmix_fd_write(fd, msg->file_str_len, file))) { goto out; } if (msg->topic_str_len > 0 && PMIX_SUCCESS != (ret = pmix_fd_write(fd, msg->topic_str_len, topic))) { goto out; } if (msg->msg_str_len > 0 && PMIX_SUCCESS != (ret = pmix_fd_write(fd, msg->msg_str_len, str))) { goto out; } out: free(str); return ret; } /* Called from the child to send an error message up the pipe to the waiting parent. */ static void send_error_show_help(int fd, int exit_status, const char *file, const char *topic, ...) { va_list ap; pmix_pfexec_pipe_err_msg_t msg; msg.fatal = true; msg.exit_status = exit_status; /* Send it */ va_start(ap, topic); write_help_msg(fd, &msg, file, topic, ap); va_end(ap); exit(exit_status); } /* close all open file descriptors w/ exception of stdin/stdout/stderr the pipe up to the parent, and the keepalive pipe. */ static int close_open_file_descriptors(int write_fd, int keepalive) { #if defined(__OSX__) DIR *dir = opendir("/dev/fd"); #else /* Linux */ DIR *dir = opendir("/proc/self/fd"); #endif /* defined(__OSX__) */ if (NULL == dir) { return PMIX_ERR_FILE_OPEN_FAILURE; } struct dirent *files; /* grab the fd of the opendir above so we don't close in the * middle of the scan. */ int dir_scan_fd = dirfd(dir); if (dir_scan_fd < 0) { return PMIX_ERR_FILE_OPEN_FAILURE; } while (NULL != (files = readdir(dir))) { if (!isdigit(files->d_name[0])) { continue; } int fd = strtol(files->d_name, NULL, 10); if (errno == EINVAL || errno == ERANGE) { closedir(dir); return PMIX_ERR_TYPE_MISMATCH; } if (fd >= 3 && fd != write_fd && fd != dir_scan_fd && fd != keepalive) { close(fd); } } closedir(dir); return PMIX_SUCCESS; } static void do_child(pmix_app_t *app, char **env, pmix_pfexec_child_t *child, int write_fd) { int i, errval; sigset_t sigs; long fd, fdmax = sysconf(_SC_OPEN_MAX); char dir[MAXPATHLEN]; #if HAVE_SETPGID /* Set a new process group for this child, so that any * signals we send to it will reach any children it spawns */ setpgid(0, 0); #endif /* Setup the pipe to be close-on-exec */ pmix_fd_set_cloexec(write_fd); /* setup stdout/stderr so that any error messages that we may print out will get displayed back at pmixrun. NOTE: Definitely do this AFTER we check contexts so that any error message from those two functions doesn't come out to the user. IF we didn't do it in this order, THEN a user who gives us a bad executable name or working directory would get N error messages, where N=num_procs. This would be very annoying for large jobs, so instead we set things up so that pmixrun always outputs a nice, single message indicating what happened */ if (PMIX_SUCCESS != (i = pmix_pfexec_base_setup_child(child))) { PMIX_ERROR_LOG(i); send_error_show_help(write_fd, 1, "help-pfexec-base.txt", "iof setup failed", pmix_globals.hostname, app->cmd); /* Does not return */ } /* close all open file descriptors w/ exception of stdin/stdout/stderr, the pipe used for the IOF INTERNAL messages, and the pipe up to the parent. */ if (PMIX_SUCCESS != close_open_file_descriptors(write_fd, child->keepalive[1])) { // close *all* file descriptors -- slow for (fd = 3; fd < fdmax; fd++) { if (fd != write_fd && fd != child->keepalive[1]) { close(fd); } } } /* Set signal handlers back to the default. Do this close to the exev() because the event library may (and likely will) reset them. If we don't do this, the event library may have left some set that, at least on some OS's, don't get reset via fork() or exec(). Hence, the launched process could be unkillable (for example). */ set_handler_linux(SIGTERM); set_handler_linux(SIGINT); set_handler_linux(SIGHUP); set_handler_linux(SIGPIPE); set_handler_linux(SIGCHLD); /* Unblock all signals, for many of the same reasons that we set the default handlers, above. This is noticeable on Linux where the event library blocks SIGTERM, but we don't want that blocked by the launched process. */ sigprocmask(0, 0, &sigs); sigprocmask(SIG_UNBLOCK, &sigs, 0); /* take us to the correct wdir */ if (NULL != app->cwd) { if (0 != chdir(app->cwd)) { send_error_show_help(write_fd, 1, "help-pfexec-base.txt", "wdir-not-found", "pmixd", app->cwd, pmix_globals.hostname, child->proc.rank); /* Does not return */ } } /* Exec the new executable */ execve(app->cmd, app->argv, env); errval = errno; if (0 != getcwd(dir, sizeof(dir))) { pmix_strncpy(dir, "GETCWD-FAILED", sizeof(dir)); } send_error_show_help(write_fd, 1, "help-pfexec-base.txt", "execve error", pmix_globals.hostname, dir, app->cmd, strerror(errval)); /* Does not return */ } static pmix_status_t do_parent(pmix_app_t *app, pmix_pfexec_child_t *child, int read_fd) { pmix_status_t rc; pmix_pfexec_pipe_err_msg_t msg; char file[PMIX_PFEXEC_MAX_FILE_LEN + 1], topic[PMIX_PFEXEC_MAX_TOPIC_LEN + 1], *str = NULL; if (child->opts.connect_stdin && 0 <= child->opts.p_stdin[0]) { close(child->opts.p_stdin[0]); } if (0 <= child->opts.p_stdout[1]) { close(child->opts.p_stdout[1]); } if (0 <= child->opts.p_stderr[1]) close(child->opts.p_stderr[1]); if (0 <= child->keepalive[1]) { close(child->keepalive[1]); } /* Block reading a message from the pipe */ while (1) { rc = pmix_fd_read(read_fd, sizeof(msg), &msg); /* If the pipe closed, then the child successfully launched */ if (PMIX_ERR_TIMEOUT == rc) { break; } /* If Something Bad happened in the read, error out */ if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); close(read_fd); return rc; } // silence Coverity warnings if (msg.file_str_len > PMIX_PFEXEC_MAX_FILE_LEN || msg.topic_str_len > PMIX_PFEXEC_MAX_TOPIC_LEN || msg.msg_str_len > PMIX_TAINT_INT_LIMIT) { pmix_show_help("help-pfexec-base.txt", "msg-too-large", true, msg.msg_str_len, 8192); return PMIX_ERR_SYS_OTHER; } /* Read in the strings; ensure to terminate them with \0 */ if (msg.file_str_len > 0) { rc = pmix_fd_read(read_fd, msg.file_str_len, file); if (PMIX_SUCCESS != rc) { pmix_show_help("help-pfexec-base.txt", "syscall fail", true, pmix_globals.hostname, app->cmd, "pmix_fd_read", __FILE__, __LINE__); return rc; } file[msg.file_str_len] = '\0'; } if (msg.topic_str_len > 0) { rc = pmix_fd_read(read_fd, msg.topic_str_len, topic); if (PMIX_SUCCESS != rc) { pmix_show_help("help-pfexec-base.txt", "syscall fail", true, pmix_globals.hostname, app->cmd, "pmix_fd_read", __FILE__, __LINE__); return rc; } topic[msg.topic_str_len] = '\0'; } if (msg.msg_str_len > 0) { str = calloc(1, msg.msg_str_len + 1); if (NULL == str) { pmix_show_help("help-pfexec-base.txt", "syscall fail", true, pmix_globals.hostname, app->cmd, "calloc", __FILE__, __LINE__); return PMIX_ERR_NOMEM; } rc = pmix_fd_read(read_fd, msg.msg_str_len, str); if (PMIX_SUCCESS != rc) { pmix_show_help("help-pfexec-base.txt", "syscall fail", true, pmix_globals.hostname, app->cmd, "pmix_fd_read", __FILE__, __LINE__); free(str); return rc; } str[msg.msg_str_len] = '\0'; // ensure NULL termination } /* Print out what we got. We already have a rendered string, so just print it. */ if (msg.msg_str_len > 0) { fprintf(stderr, "%s\n", str); free(str); str = NULL; } /* If msg.fatal is true, then the child exited with an error. Otherwise, whatever we just printed was a warning, so loop around and see what else is on the pipe (or if the pipe closed, indicating that the child launched successfully). */ if (msg.fatal) { close(read_fd); if (NULL != str) { free(str); } return PMIX_ERR_SYS_OTHER; } if (NULL != str) { free(str); str = NULL; } } /* If we got here, it means that the pipe closed without indication of a fatal error, meaning that the child process launched successfully. */ close(read_fd); return PMIX_SUCCESS; } /** * Fork/exec the specified processes */ static int fork_proc(pmix_app_t *app, pmix_pfexec_child_t *child, char **env) { int p[2]; /* A pipe is used to communicate between the parent and child to indicate whether the exec ultimately succeeded or failed. The child sets the pipe to be close-on-exec; the child only ever writes anything to the pipe if there is an error (e.g., executable not found, exec() fails, etc.). The parent does a blocking read on the pipe; if the pipe closed with no data, then the exec() succeeded. If the parent reads something from the pipe, then the child was letting us know why it failed. */ if (pipe(p) < 0) { PMIX_ERROR_LOG(PMIX_ERR_SYS_OTHER); return PMIX_ERR_SYS_OTHER; } /* Fork off the child */ child->pid = fork(); if (child->pid < 0) { PMIX_ERROR_LOG(PMIX_ERR_SYS_OTHER); return PMIX_ERR_SYS_OTHER; } if (child->pid == 0) { if (0 <= p[0]) { close(p[0]); } if (0 <= child->keepalive[0]) { close(child->keepalive[0]); child->keepalive[0] = -1; } do_child(app, env, child, p[1]); /* Does not return */ } close(p[1]); return do_parent(app, child, p[0]); } /* callback from the event library whenever a SIGCHLD is received */ static void wait_signal_callback(int fd, short event, void *arg) { (void) fd; (void) event; pmix_event_t *signal = (pmix_event_t *) arg; int status; pid_t pid; pmix_pfexec_child_t *child; PMIX_ACQUIRE_OBJECT(signal); if (SIGCHLD != PMIX_EVENT_SIGNAL(signal)) { return; } /* if we haven't spawned anyone, then ignore this */ if (0 == pmix_list_get_size(&pmix_pfexec_globals.children)) { return; } /* reap all queued waitpids until we * don't get anything valid back */ while (1) { pid = waitpid(-1, &status, WNOHANG); if (-1 == pid && EINTR == errno) { /* try it again */ continue; } /* if we got garbage, then nothing we can do */ if (pid <= 0) { return; } /* we are already in an event, so it is safe to access globals */ PMIX_LIST_FOREACH (child, &pmix_pfexec_globals.children, pmix_pfexec_child_t) { if (pid == child->pid) { /* record the exit status */ if (WIFEXITED(status)) { child->exitcode = WEXITSTATUS(status); } else { if (WIFSIGNALED(status)) { child->exitcode = WTERMSIG(status) + 128; } } /* mark the child as complete */ child->completed = true; if ((NULL == child->stdoutev || !child->stdoutev->active) && (NULL == child->stderrev || !child->stderrev->active)) { PMIX_PFEXEC_CHK_COMPLETE(child); } break; } } } } /**** FRAMEWORK CLASS INSTANTIATIONS ****/ static void chcon(pmix_pfexec_child_t *p) { memset(&p->ev, 0, sizeof(pmix_event_t)); PMIX_LOAD_PROCID(&p->proc, NULL, PMIX_RANK_UNDEF); p->pid = 0; p->completed = false; p->keepalive[0] = -1; p->keepalive[1] = -1; memset(&p->opts, 0, sizeof(pmix_pfexec_base_io_conf_t)); p->opts.p_stdin[0] = -1; p->opts.p_stdin[1] = -1; p->opts.p_stdout[0] = -1; p->opts.p_stdout[1] = -1; p->opts.p_stderr[0] = -1; p->opts.p_stderr[1] = -1; PMIX_CONSTRUCT(&p->stdinsink, pmix_iof_sink_t); p->stdoutev = NULL; p->stderrev = NULL; } static void chdes(pmix_pfexec_child_t *p) { PMIX_DESTRUCT(&p->stdinsink); if (NULL != p->stdoutev) { PMIX_RELEASE(p->stdoutev); } if (NULL != p->stderrev) { PMIX_RELEASE(p->stderrev); } if (0 <= p->keepalive[0]) { close(p->keepalive[0]); } if (0 <= p->keepalive[1]) { close(p->keepalive[1]); } } PMIX_CLASS_INSTANCE(pmix_pfexec_child_t, pmix_list_item_t, chcon, chdes); PMIX_CLASS_INSTANCE(pmix_pfexec_signal_caddy_t, pmix_object_t, NULL, NULL); PMIX_CLASS_INSTANCE(pmix_pfexec_cmpl_caddy_t, pmix_object_t, NULL, NULL); pmix-6.1.1~rc2/src/common/Makefile.include0000664000175000017500000000153015203536752020635 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2015-2019 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2023-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # EXTRA_DIST += \ common/help-pfexec-base.txt sources += \ common/pmix_query.c \ common/pmix_strings.c \ common/pmix_log.c \ common/pmix_control.c \ common/pmix_data.c \ common/pmix_security.c \ common/pmix_iof.c \ common/pmix_attributes.c \ common/pmix_alloc.c \ common/pmix_session.c \ common/pmix_pfexec.c \ common/pmix_monitor.c headers += \ common/pmix_iof.h \ common/pmix_attributes.h \ common/pmix_pfexec.h \ common/pmix_monitor.h pmix-6.1.1~rc2/src/common/pmix_session.c0000664000175000017500000001741415203536752020447 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2022 IBM Corporation. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/common/pmix_attributes.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/ptl/base/base.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/server/pmix_server_ops.h" static void myinfocbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_lock_t *lock = (pmix_lock_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(info, ninfo, release_fn, release_cbdata); lock->status = status; PMIX_WAKEUP_THREAD(lock); } static void relcbfunc(void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:session_ctrl release callback"); if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } PMIX_RELEASE(cd); } static void ssnctrlcbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; pmix_status_t rc; pmix_shift_caddy_t *results; int cnt; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:session ctrl cback from server"); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { /* release the caller */ if (NULL != cd->cbfunc.infocbfunc) { cd->cbfunc.infocbfunc(PMIX_ERR_COMM_FAILURE, NULL, 0, cd->cbdata, NULL, NULL); } PMIX_RELEASE(cd); return; } results = PMIX_NEW(pmix_shift_caddy_t); /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &results->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS != results->status) { goto complete; } /* unpack any returned data */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &results->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < results->ninfo) { PMIX_INFO_CREATE(results->info, results->ninfo); cnt = results->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, results->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } complete: pmix_output_verbose(2, pmix_globals.debug_output, "pmix:session_ctrl cback from server releasing"); /* release the caller */ if (NULL != cd->cbfunc.infocbfunc) { cd->cbfunc.infocbfunc(results->status, results->info, results->ninfo, cd->cbdata, relcbfunc, results); } else { PMIX_RELEASE(results); } PMIX_RELEASE(cd); } static void _session_control(int sd, short args, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; pmix_cmd_t cmd = PMIX_SESSION_CTRL_CMD; pmix_buffer_t *msg; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); /* if we are the system controller but not connected * to the scheduler, then nothing we can do */ if (PMIX_PEER_IS_SYS_CTRLR(pmix_globals.mypeer)) { if (!PMIX_PEER_IS_SCHEDULER(pmix_client_globals.myserver)) { rc = PMIX_ERR_NOT_SUPPORTED; goto errorrpt; } // otherwise send it to the scheduler goto sendit; } sendit: /* for all other cases, we need to send this to someone * if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { rc = PMIX_ERR_UNREACH; goto errorrpt; } /* all other cases, relay this request to our server */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto errorrpt; } /* pack the sessionID */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cd->sessionid, 1, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto errorrpt; } /* pack the directives */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cd->ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto errorrpt; } if (0 < cd->ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cd->directives, cd->ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto errorrpt; } } /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, ssnctrlcbfunc, (void *) cd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); } return; errorrpt: /* release the caller */ if (NULL != cd->cbfunc.infocbfunc) { cd->cbfunc.infocbfunc(rc, NULL, 0, cd->cbdata, NULL, NULL); } PMIX_RELEASE(cd); return; } pmix_status_t PMIx_Session_control(uint32_t sessionID, const pmix_info_t directives[], size_t ndirs, pmix_info_cbfunc_t cbfunc, void *cbdata) { pmix_shift_caddy_t *cd; pmix_lock_t mylock; pmix_status_t rc; pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server session control"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } cd = PMIX_NEW(pmix_shift_caddy_t); cd->sessionid = sessionID; cd->directives = (pmix_info_t*)directives; cd->ndirs = ndirs; cd->cbfunc.infocbfunc = cbfunc; cd->cbdata = cbdata; /* if the provided callback is NULL, then substitute * our own internal cbfunc and block here */ if (NULL == cbfunc) { PMIX_CONSTRUCT_LOCK(&mylock); cd->cbfunc.infocbfunc = myinfocbfunc; cd->cbdata = &mylock; PMIX_THREADSHIFT(cd, _session_control); PMIX_WAIT_THREAD(&mylock); rc = mylock.status; if (PMIX_SUCCESS == rc) { rc = PMIX_OPERATION_SUCCEEDED; } PMIX_DESTRUCT_LOCK(&mylock); return rc; } /* we have to push this into our event library to avoid * potential threading issues */ PMIX_THREADSHIFT(cd, _session_control); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/common/pmix_iof.c0000664000175000017500000024123715203536752017543 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2021 IBM Corporation. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_FCNTL_H # include #else # ifdef HAVE_SYS_FCNTL_H # include # endif #endif #include #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/mca/bfrops/bfrops.h" #include "src/common/pmix_pfexec.h" #include "src/mca/ptl/ptl.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_os_dirpath.h" #include "src/util/pmix_printf.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/server/pmix_server_ops.h" static void myregcbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_iof_req_t *req = (pmix_iof_req_t *) cbdata; int32_t m; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(hdr); PMIX_ACQUIRE_OBJECT(req); /* unpack the return status */ m = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &req->status, &m, PMIX_STATUS); if (PMIX_SUCCESS != rc) { /* Ignore short buffer/premature connection disconnect */ if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { req->status = PMIX_SUCCESS; } else { req->status = rc; } } pmix_output_verbose(2, pmix_client_globals.iof_output, "pmix:iof_register returned status %s", PMIx_Error_string(req->status)); if (PMIX_SUCCESS == req->status) { /* get the reference ID */ m = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &req->remote_id, &m, PMIX_SIZE); if (PMIX_SUCCESS != rc) { req->status = rc; } } if (NULL == req->regcbfunc) { PMIX_WAKEUP_THREAD(&req->lock); } else { req->regcbfunc(req->status, req->local_id, req->cbdata); } return; } static void process_cache(int sd, short args, void *cbdata) { pmix_iof_req_t *req = (pmix_iof_req_t *) cbdata; pmix_iof_cache_t *iof, *ionext; bool found; size_t n; pmix_status_t rc; pmix_buffer_t *msg; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_LIST_FOREACH_SAFE (iof, ionext, &pmix_server_globals.iof, pmix_iof_cache_t) { /* if the channels don't match, then ignore it */ if (!(iof->channel & req->channels)) { continue; } /* never forward back to the source! This can happen if the source * is a launcher */ if (PMIX_CHECK_NAMES(&iof->source, &req->requestor->info->pname)) { continue; } /* never forward to myself */ if (PMIX_CHECK_NAMES(&req->requestor->info->pname, &pmix_globals.myid)) { continue; } /* if the source does not match the request, then ignore it */ found = false; for (n = 0; n < req->nprocs; n++) { if (PMIX_CHECK_PROCID(&iof->source, &req->procs[n])) { found = true; break; } } if (found) { /* setup the msg */ if (NULL == (msg = PMIX_NEW(pmix_buffer_t))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return; } /* provide the source */ PMIX_BFROPS_PACK(rc, req->requestor, msg, &iof->source, 1, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } /* provide the channel */ PMIX_BFROPS_PACK(rc, req->requestor, msg, &iof->channel, 1, PMIX_IOF_CHANNEL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } /* provide the local handler ID */ PMIX_BFROPS_PACK(rc, req->requestor, msg, &req->local_id, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } /* pack the number of info's provided */ PMIX_BFROPS_PACK(rc, req->requestor, msg, &iof->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } /* if some were provided, then pack them too */ if (0 < iof->ninfo) { PMIX_BFROPS_PACK(rc, req->requestor, msg, iof->info, iof->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } } /* pack the data */ PMIX_BFROPS_PACK(rc, req->requestor, msg, iof->bo, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } /* send it to the requestor */ PMIX_PTL_SEND_ONEWAY(rc, req->requestor, msg, PMIX_PTL_TAG_IOF); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); } } } } static void myreg(int sd, short args, void *cbdata) { pmix_iof_req_t *req = (pmix_iof_req_t *) cbdata; pmix_cmd_t cmd = PMIX_IOF_PULL_CMD; pmix_buffer_t *msg = NULL; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); // store the request req->local_id = pmix_pointer_array_add(&pmix_globals.iof_requests, req); req->status = PMIX_SUCCESS; if (NULL != req->requestor) { // local request as we are a server /* if there is a regsitration callback function, call it */ if (NULL != req->regcbfunc) { req->regcbfunc(req->status, req->local_id, req->cbdata); // process any cached IO process_cache(0, 0, req); } else { PMIX_WAKEUP_THREAD(&req->lock); } return; } /* setup the registration cmd for the server */ msg = PMIX_NEW(pmix_buffer_t); if (NULL == msg) { pmix_pointer_array_set_item(&pmix_globals.iof_requests, req->local_id, NULL); req->status = PMIX_ERR_NOMEM; if (NULL != req->regcbfunc) { req->regcbfunc(req->status, req->local_id, req->cbdata); PMIX_RELEASE(req); } else { PMIX_WAKEUP_THREAD(&req->lock); } return; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &req->nprocs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } if (0 < req->nprocs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, req->procs, req->nprocs, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &req->ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } if (0 < req->ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, req->directives, req->ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &req->channels, 1, PMIX_IOF_CHANNEL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &req->local_id, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } pmix_output_verbose(2, pmix_client_globals.iof_output, "pmix:iof:PULL sending request to server"); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, myregcbfunc, (void *) req); if (PMIX_SUCCESS == rc) { return; } cleanup: // handle an error if (NULL != msg) { PMIX_RELEASE(msg); } pmix_pointer_array_set_item(&pmix_globals.iof_requests, req->local_id, NULL); req->status = rc; if (NULL != req->regcbfunc) { req->regcbfunc(req->status, req->local_id, req->cbdata); PMIX_RELEASE(req); } else { PMIX_WAKEUP_THREAD(&req->lock); } return; } PMIX_EXPORT pmix_status_t PMIx_IOF_pull(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t directives[], size_t ndirs, pmix_iof_channel_t channel, pmix_iof_cbfunc_t cbfunc, pmix_hdlr_reg_cbfunc_t regcbfunc, void *regcbdata) { pmix_iof_req_t *req; pmix_output_verbose(2, pmix_client_globals.iof_output, "pmix:iof:PULL"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* we don't allow stdin to flow thru this path */ if (PMIX_FWD_STDIN_CHANNEL & channel) { return PMIX_ERR_NOT_SUPPORTED; } req = PMIX_NEW(pmix_iof_req_t); if (NULL == req) { return PMIX_ERR_NOMEM; } /* if I am my own active server, then just register * the request */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && pmix_client_globals.myserver == pmix_globals.mypeer) { // identify ourselves as the requestor PMIX_RETAIN(pmix_globals.mypeer); req->requestor = pmix_globals.mypeer; } else { // this is going to have to be sent to the server - // if we aren't connected, don't attempt to send if (!pmix_atomic_check_bool(&pmix_globals.connected)) { PMIX_RELEASE(req); return PMIX_ERR_UNREACH; } } // need to threadshift this for processing req->nprocs = nprocs; PMIX_PROC_CREATE(req->procs, req->nprocs); memcpy(req->procs, procs, nprocs * sizeof(pmix_proc_t)); req->channels = channel; req->directives = (pmix_info_t*)directives; req->ndirs = ndirs; req->cbfunc = cbfunc; req->regcbfunc = regcbfunc; req->cbdata = regcbdata; PMIX_THREADSHIFT(req, myreg); if (NULL == regcbfunc) { // blocking call, so wait here PMIX_WAIT_THREAD(&req->lock); if (PMIX_SUCCESS == req->status) { // we don't want the IO to arrive before we return from // this call, so delay it a little PMIX_THREADSHIFT_DELAY(req, process_cache, 1.0); return PMIX_OPERATION_SUCCEEDED; } else { return req->status; } } return PMIX_SUCCESS; } static void deregcbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t*)cbdata; int32_t m; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(hdr); PMIX_ACQUIRE_OBJECT(req); /* unpack the return status */ m = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->status, &m, PMIX_STATUS); if (PMIX_SUCCESS != rc) { /* Ignore short buffer/premature connection disconnect */ if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { cd->status = PMIX_SUCCESS; } else { cd->status = rc; } } pmix_output_verbose(2, pmix_client_globals.iof_output, "pmix:iof_deregister returned status %s", PMIx_Error_string(cd->status)); if (NULL == cd->cbfunc.opcbfn) { // release the blocking call PMIX_WAKEUP_THREAD(&cd->lock); return; } // give them their callback cd->cbfunc.opcbfn(cd->status, cd->cbdata); PMIX_RELEASE(cd); } static void mydereg(int sd, short args, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t*)cbdata; pmix_cmd_t cmd = PMIX_IOF_DEREG_CMD; pmix_buffer_t *msg = NULL; pmix_status_t rc; pmix_iof_req_t *req; size_t remote_id; PMIX_HIDE_UNUSED_PARAMS(sd, args); req = (pmix_iof_req_t *) pmix_pointer_array_get_item(&pmix_globals.iof_requests, cd->ncodes); if (NULL == req) { /* bad value */ rc = PMIX_ERR_BAD_PARAM; goto cleanup; } remote_id = req->remote_id; pmix_pointer_array_set_item(&pmix_globals.iof_requests, cd->ncodes, NULL); PMIX_RELEASE(req); /* setup the deregistration cmd */ msg = PMIX_NEW(pmix_buffer_t); if (NULL == msg) { rc = PMIX_ERR_NOMEM; goto cleanup; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cd->ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } if (0 < cd->ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cd->directives, cd->ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } /* pack the remote handler ID */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &remote_id, 1, PMIX_SIZE); pmix_output_verbose(2, pmix_client_globals.iof_output, "pmix:iof_dereg sending to server"); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, deregcbfunc, (void *) cd); if (PMIX_SUCCESS == rc) { return; } cleanup: // handle an error if (NULL != msg) { PMIX_RELEASE(msg); } if (NULL != cd->cbfunc.opcbfn) { cd->cbfunc.opcbfn(rc, cd->cbdata); PMIX_RELEASE(cd); } else { cd->status = rc; PMIX_WAIT_THREAD(&cd->lock); } } PMIX_EXPORT pmix_status_t PMIx_IOF_deregister(size_t iofhdlr, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_shift_caddy_t *cd; pmix_status_t rc = PMIX_SUCCESS; pmix_output_verbose(2, pmix_client_globals.iof_output, "pmix:iof_deregister"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* if we are a server, we cannot do this */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { return PMIX_ERR_NOT_SUPPORTED; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } // need to threadshift to access global data cd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->ncodes = iofhdlr; cd->directives = (pmix_info_t*)directives; cd->ndirs = ndirs; cd->cbfunc.opcbfn = cbfunc; cd->cbdata = cbdata; PMIX_THREADSHIFT(cd, mydereg); if (NULL == cbfunc) { // blocking call PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; PMIX_RELEASE(cd); } return rc; } static pmix_event_t stdinsig_ev; static pmix_iof_read_event_t *stdinev_global = NULL; static void stdincbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; int cnt; pmix_status_t rc, status; PMIX_HIDE_UNUSED_PARAMS(hdr); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { /* release the caller */ if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(PMIX_ERR_COMM_FAILURE, cb->cbdata); PMIX_RELEASE(cb); } else { PMIX_WAKEUP_THREAD(&cb->lock); } return; } /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { status = rc; } if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(PMIX_ERR_COMM_FAILURE, cb->cbdata); PMIX_RELEASE(cb); } else { PMIX_WAKEUP_THREAD(&cb->lock); } } static void mysrvrcbfunc(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(status, cb->cbdata); PMIX_RELEASE(cb); } else { cb->status = status; PMIX_WAKEUP_THREAD(&cb->lock); } } static void exec_push(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t*)cbdata; pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_IOF_PUSH_CMD; pmix_status_t rc = PMIX_SUCCESS; size_t n; bool begincollecting, stopcollecting; int flags, fd = fileno(stdin); PMIX_HIDE_UNUSED_PARAMS(sd, args); if (NULL == cb->bo) { /* check the directives */ for (n = 0; n < cb->ndirs; n++) { if (PMIX_CHECK_KEY(&cb->directives[n], PMIX_IOF_PUSH_STDIN)) { /* we are to start collecting our stdin and pushing * it to the specified targets */ begincollecting = PMIX_INFO_TRUE(&cb->directives[n]); if (begincollecting) { /* add these targets to our list */ if (!pmix_globals.pushstdin) { /* not already collecting, so start */ pmix_globals.pushstdin = true; /* We don't want to set nonblocking on our * stdio stream. If we do so, we set the file descriptor to * non-blocking for everyone that has that file descriptor, which * includes everyone else in our shell pipeline chain. (See * http://lists.freebsd.org/pipermail/freebsd-hackers/2005-January/009742.html). * This causes things like "prun -np 1 big_app | cat" to lose * output, because cat's stdout is then ALSO non-blocking and cat * isn't built to deal with that case (same with almost all other * unix text utils). */ if (0 != fd) { if ((flags = fcntl(fd, F_GETFL, 0)) < 0) { pmix_output(pmix_client_globals.iof_output, "[%s:%d]: fcntl(F_GETFL) failed with errno=%d\n", __FILE__, __LINE__, errno); } else { flags |= O_NONBLOCK; if (0 != fcntl(fd, F_SETFL, flags)) { pmix_output(pmix_client_globals.iof_output, "[%s:%d]: fcntl(F_SETFL) failed with errno=%d\n", __FILE__, __LINE__, errno); } } } if (isatty(fd)) { /* We should avoid trying to read from stdin if we * have a terminal, but are backgrounded. Catch the * signals that are commonly used when we switch * between being backgrounded and not. If the * filedescriptor is not a tty, don't worry about it * and always stay connected. */ pmix_event_signal_set(pmix_globals.evauxbase, &stdinsig_ev, SIGCONT, pmix_iof_stdin_cb, NULL); /* setup a read event to read stdin, but don't activate it yet. The * dst_name indicates who should receive the stdin. If that recipient * doesn't do a corresponding pull, however, then the stdin will * be dropped upon receipt at the local daemon */ PMIX_IOF_READ_EVENT(&stdinev_global, cb->procs, cb->nprocs, cb->directives, cb->ndirs, fd, pmix_iof_read_local_handler, false); /* check to see if we want the stdin read event to be * active - we will always at least define the event, * but may delay its activation */ if (pmix_iof_stdin_check(fd)) { PMIX_IOF_READ_ACTIVATE(stdinev_global); } } else { /* if we are not looking at a tty, just setup a read event * and activate it */ PMIX_IOF_READ_EVENT(&stdinev_global, cb->procs, cb->nprocs, cb->directives, cb->ndirs, fd, pmix_iof_read_local_handler, true); } } } else { if (pmix_globals.pushstdin) { /* remove these targets from the list of * recipients - if the list is then empty, * stop collecting. If the targets param * is NULL, then remove all targets and stop. * Flush any cached input before calling * the cbfunc */ } } } else if (PMIX_CHECK_KEY(&cb->directives[n], PMIX_IOF_COMPLETE)) { /* if we are collecting our stdin for the specified * targets, then stop - a NULL for targets indicates * stop for everyone. Flush any remaining cached input * before calling the cbfunc */ stopcollecting = PMIX_INFO_TRUE(&cb->directives[n]); if (stopcollecting) { if (pmix_globals.pushstdin) { /* remove these targets from the list of * recipients - if the list is then empty, * stop collecting */ } } } } if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(PMIX_SUCCESS, cb->cbdata); PMIX_RELEASE(cb); } else { cb->status = PMIX_SUCCESS; PMIX_WAKEUP_THREAD(&cb->lock); } return; } /* if we are a server and not a launcher, just pass the data up to our host */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { if (NULL == pmix_host_server.push_stdin) { rc = PMIX_ERR_NOT_SUPPORTED; } else { rc = pmix_host_server.push_stdin(&pmix_globals.myid, cb->procs, cb->nprocs, cb->directives, cb->ndirs, cb->bo, mysrvrcbfunc, cb); } if (PMIX_SUCCESS != rc) { if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(rc, cb->cbdata); PMIX_RELEASE(cb); } else { cb->status = rc; PMIX_WAKEUP_THREAD(&cb->lock); } } return; } /* if we are not a server, then we send the provided * data to our server for processing */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { rc = PMIX_ERR_UNREACH; goto reply; } msg = PMIX_NEW(pmix_buffer_t); if (NULL == msg) { rc = PMIX_ERR_NOMEM; goto reply; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto reply; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cb->nprocs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto reply; } if (0 < cb->nprocs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cb->procs, cb->nprocs, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto reply; } } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cb->ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto reply; } if (0 < cb->ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cb->directives, cb->ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto reply; } } if (NULL != cb->bo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cb->bo, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto reply; } } PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, stdincbfunc, cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto reply; } return; reply: if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(rc, cb->cbdata); } else { cb->status = rc; PMIX_WAKEUP_THREAD(&cb->lock); return; } PMIX_RELEASE(cb); return; } pmix_status_t PMIx_IOF_push(const pmix_proc_t targets[], size_t ntargets, pmix_byte_object_t *bo, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_cb_t *cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } // need to threadshift this request to process it since it accesses // global structures cb = PMIX_NEW(pmix_cb_t); cb->procs = (pmix_proc_t*)targets; cb->nprocs = ntargets; cb->bo = bo; cb->directives = (pmix_info_t*)directives; cb->ndirs = ndirs; cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; PMIX_THREADSHIFT(cb, exec_push); if (NULL == cbfunc) { PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; PMIX_RELEASE(cb); return rc; } else { // the implementation will callback the cbfunc with the answer return PMIX_SUCCESS; } } static pmix_iof_write_event_t* pmix_iof_setup(pmix_namespace_t *nptr, pmix_rank_t rank, pmix_iof_channel_t stream) { int rc; char *outdir, *outfile; int np, numdigs, fdout; pmix_iof_sink_t *snk; pmix_proc_t src; pmix_output_verbose(5, pmix_server_globals.iof_output, "IOF SETUP %s %u", nptr->nspace, rank); PMIX_LOAD_PROCID(&src, nptr->nspace, rank); np = nptr->nprocs / 10; /* determine the number of digits required for max vpid */ numdigs = 1; while (np > 0) { numdigs++; np = np / 10; } /* see if we are to output to a directory */ if (NULL != nptr->iof_flags.directory) { /* construct the directory where the output files will go */ pmix_asprintf(&outdir, "%s/%s/rank.%0*u", nptr->iof_flags.directory, nptr->nspace, numdigs, rank); /* ensure the directory exists */ rc = pmix_os_dirpath_create(outdir, S_IRWXU | S_IRGRP | S_IXGRP); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); free(outdir); return NULL; } if (PMIX_FWD_STDOUT_CHANNEL & stream || nptr->iof_flags.merge) { /* setup the stdout sink */ pmix_asprintf(&outfile, "%s/stdout", outdir); fdout = open(outfile, O_CREAT | O_RDWR | O_TRUNC, 0644); free(outfile); if (fdout < 0) { /* couldn't be opened */ PMIX_ERROR_LOG(PMIX_ERR_FILE_OPEN_FAILURE); free(outdir); return NULL; } /* define a sink to that file descriptor */ snk = PMIX_NEW(pmix_iof_sink_t); if (nptr->iof_flags.merge) { PMIX_IOF_SINK_DEFINE(snk, &src, fdout, PMIX_FWD_ALL_CHANNELS, pmix_iof_write_handler); } else { PMIX_IOF_SINK_DEFINE(snk, &src, fdout, PMIX_FWD_STDOUT_CHANNEL, pmix_iof_write_handler); } pmix_list_append(&nptr->sinks, &snk->super); free(outdir); return &snk->wev; } else { /* setup the stderr sink */ pmix_asprintf(&outfile, "%s/stderr", outdir); fdout = open(outfile, O_CREAT | O_RDWR | O_TRUNC, 0644); free(outfile); if (fdout < 0) { /* couldn't be opened */ PMIX_ERROR_LOG(PMIX_ERR_FILE_OPEN_FAILURE); free(outdir); return NULL; } /* define a sink to that file descriptor */ snk = PMIX_NEW(pmix_iof_sink_t); PMIX_IOF_SINK_DEFINE(snk, &src, fdout, PMIX_FWD_STDERR_CHANNEL, pmix_iof_write_handler); pmix_list_append(&nptr->sinks, &snk->super); free(outdir); return &snk->wev; } } /* see if we are to output to a file */ if (NULL != nptr->iof_flags.file) { /* construct the directory where the output files will go */ outdir = pmix_dirname(nptr->iof_flags.file); /* ensure the directory exists */ rc = pmix_os_dirpath_create(outdir, S_IRWXU | S_IRGRP | S_IXGRP); free(outdir); if (PMIX_SUCCESS != rc && PMIX_ERR_EXISTS != rc) { PMIX_ERROR_LOG(rc); return NULL; } if (PMIX_FWD_STDOUT_CHANNEL & stream || nptr->iof_flags.merge) { /* setup the stdout sink */ if (nptr->iof_flags.pattern) { /* if there are no '%' signs in the pattern, then it is just a literal string */ if (NULL == strchr(nptr->iof_flags.file, '%')) { /* setup the file */ pmix_asprintf(&outfile, "%s.out", nptr->iof_flags.file); } else { /* must process the pattern - for now, just take it literally */ pmix_asprintf(&outfile, "%s.pattern.out", nptr->iof_flags.file); } } else { /* setup the file */ pmix_asprintf(&outfile, "%s.%s.%0*u.out", nptr->iof_flags.file, nptr->nspace, numdigs, rank); } fdout = open(outfile, O_CREAT | O_RDWR | O_TRUNC, 0644); free(outfile); if (fdout < 0) { /* couldn't be opened */ PMIX_ERROR_LOG(PMIX_ERR_FILE_OPEN_FAILURE); return NULL; } /* define a sink to that file descriptor */ snk = PMIX_NEW(pmix_iof_sink_t); if (nptr->iof_flags.merge) { PMIX_IOF_SINK_DEFINE(snk, &src, fdout, PMIX_FWD_ALL_CHANNELS, pmix_iof_write_handler); } else { PMIX_IOF_SINK_DEFINE(snk, &src, fdout, PMIX_FWD_STDOUT_CHANNEL, pmix_iof_write_handler); } pmix_list_append(&nptr->sinks, &snk->super); return &snk->wev; } else { /* setup the stderr sink */ if (nptr->iof_flags.pattern) { /* if there are no '%' signs in the pattern, then it is just a literal string */ if (NULL == strchr(nptr->iof_flags.file, '%')) { /* setup the file */ pmix_asprintf(&outfile, "%s.err", nptr->iof_flags.file); } else { /* must process the pattern - for now, just take it literally */ pmix_asprintf(&outfile, "%s.pattern.err", nptr->iof_flags.file); } } else { /* setup the file */ pmix_asprintf(&outfile, "%s.%s.%0*u.err", nptr->iof_flags.file, nptr->nspace, numdigs, rank); } fdout = open(outfile, O_CREAT | O_RDWR | O_TRUNC, 0644); free(outfile); if (fdout < 0) { /* couldn't be opened */ PMIX_ERROR_LOG(PMIX_ERR_FILE_OPEN_FAILURE); return NULL; } /* define a sink to that file descriptor */ snk = PMIX_NEW(pmix_iof_sink_t); PMIX_IOF_SINK_DEFINE(snk, &src, fdout, PMIX_FWD_STDERR_CHANNEL, pmix_iof_write_handler); pmix_list_append(&nptr->sinks, &snk->super); return &snk->wev; } } return NULL; } void pmix_iof_check_flags(pmix_info_t *info, pmix_iof_flags_t *flags) { if (PMIX_CHECK_KEY(info, PMIX_IOF_TAG_OUTPUT) || PMIX_CHECK_KEY(info, PMIX_TAG_OUTPUT)) { flags->tag = PMIX_INFO_TRUE(info); flags->set = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_TAG_DETAILED_OUTPUT)) { flags->tag_detailed = PMIX_INFO_TRUE(info); flags->set = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_TAG_FULLNAME_OUTPUT)) { flags->tag_fullname = PMIX_INFO_TRUE(info); flags->set = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_RANK_OUTPUT)) { flags->rank = PMIX_INFO_TRUE(info); flags->set = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_TIMESTAMP_OUTPUT) || PMIX_CHECK_KEY(info, PMIX_TIMESTAMP_OUTPUT)) { flags->timestamp = PMIX_INFO_TRUE(info); flags->set = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_XML_OUTPUT)) { flags->xml = PMIX_INFO_TRUE(info); flags->set = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_OUTPUT_TO_FILE) || PMIX_CHECK_KEY(info, PMIX_OUTPUT_TO_FILE)) { flags->file = strdup(info->value.data.string); flags->set = true; flags->local_output = true; flags->local_output_given = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_OUTPUT_TO_DIRECTORY) || PMIX_CHECK_KEY(info, PMIX_OUTPUT_TO_DIRECTORY)) { flags->directory = strdup(info->value.data.string); flags->set = true; flags->local_output = true; flags->local_output_given = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_FILE_ONLY) || PMIX_CHECK_KEY(info, PMIX_OUTPUT_NOCOPY)) { flags->nocopy = PMIX_INFO_TRUE(info); flags->set = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_MERGE_STDERR_STDOUT) || PMIX_CHECK_KEY(info, PMIX_MERGE_STDERR_STDOUT)) { flags->merge = PMIX_INFO_TRUE(info); flags->set = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_LOCAL_OUTPUT)) { flags->local_output = PMIX_INFO_TRUE(info); flags->set = true; flags->local_output_given = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_OUTPUT_RAW)) { flags->raw = PMIX_INFO_TRUE(info); flags->set = true; } else if (PMIX_CHECK_KEY(info, PMIX_IOF_FILE_PATTERN)) { flags->pattern = PMIX_INFO_TRUE(info); /* don't mark as set here as this is just a qualifier */ } } pmix_status_t pmix_iof_process_iof(pmix_iof_channel_t channels, const pmix_proc_t *source, const pmix_byte_object_t *bo, const pmix_info_t *info, size_t ninfo, pmix_iof_req_t *req) { bool match; size_t m; pmix_buffer_t *msg; pmix_status_t rc; /* if the channel wasn't included, then ignore it */ if (!(channels & req->channels)) { return PMIX_SUCCESS; } /* see if the source matches the request */ match = false; for (m = 0; m < req->nprocs; m++) { if (PMIX_CHECK_PROCID(source, &req->procs[m])) { match = true; break; } } if (!match) { return PMIX_SUCCESS; } /* never forward back to the source! This can happen if the source * is a launcher - also, never forward to a peer that is no * longer with us */ if (NULL == req->requestor->info || req->requestor->finalized) { return PMIX_SUCCESS; } if (PMIX_CHECK_NAMES(source, &req->requestor->info->pname)) { return PMIX_SUCCESS; } /* never forward to myself */ if (PMIX_CHECK_NAMES(&req->requestor->info->pname, &pmix_globals.myid)) { return PMIX_SUCCESS; } /* setup the msg */ if (NULL == (msg = PMIX_NEW(pmix_buffer_t))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return PMIX_ERR_OUT_OF_RESOURCE; } /* provide the source */ PMIX_BFROPS_PACK(rc, req->requestor, msg, source, 1, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* provide the channel */ PMIX_BFROPS_PACK(rc, req->requestor, msg, &channels, 1, PMIX_IOF_CHANNEL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* provide their local handler ID so they know which cbfunc to use */ PMIX_BFROPS_PACK(rc, req->requestor, msg, &req->remote_id, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the number of info's provided */ PMIX_BFROPS_PACK(rc, req->requestor, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* if some were provided, then pack them too */ if (0 < ninfo) { PMIX_BFROPS_PACK(rc, req->requestor, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* pack the data */ PMIX_BFROPS_PACK(rc, req->requestor, msg, bo, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* send it to the requestor */ PMIX_PTL_SEND_ONEWAY(rc, req->requestor, msg, PMIX_PTL_TAG_IOF); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); } return PMIX_OPERATION_SUCCEEDED; } pmix_byte_object_t* pmix_iof_prep_output(const pmix_proc_t *name, pmix_iof_flags_t *myflags, pmix_iof_channel_t stream, const pmix_byte_object_t *bo) { char starttag[PMIX_IOF_BASE_TAG_MAX], endtag[PMIX_IOF_BASE_TAG_MAX], *suffix; char timestamp[PMIX_IOF_BASE_TAG_MAX], outtag[PMIX_IOF_BASE_TAG_MAX]; char begintag[PMIX_IOF_BASE_TAG_MAX]; char **segments = NULL; pmix_byte_object_t *output; size_t offset, j, n, m, bufsize; char *buffer, qprint[15], *cptr; const char *usestring; bool bufcopy; pmix_cb_t cb2; pmix_info_t optional; pmix_kval_t *kv; pid_t pid; char *pidstring; pmix_status_t rc; /* setup output object */ output = PMIx_Byte_object_create(1); /* if 0 bytes, then just pass it so the fd can be closed * after it writes everything out */ if (0 == bo->size) { // the byte object was initialized to empty return output; } memset(begintag, 0, PMIX_IOF_BASE_TAG_MAX); memset(starttag, 0, PMIX_IOF_BASE_TAG_MAX); memset(endtag, 0, PMIX_IOF_BASE_TAG_MAX); memset(timestamp, 0, PMIX_IOF_BASE_TAG_MAX); memset(outtag, 0, PMIX_IOF_BASE_TAG_MAX); PMIX_INFO_LOAD(&optional, PMIX_OPTIONAL, NULL, PMIX_BOOL); if (PMIX_FWD_STDOUT_CHANNEL & stream) { /* write the bytes to stdout */ suffix = "stdout"; } else if (PMIX_FWD_STDERR_CHANNEL & stream) { /* write the bytes to stderr */ suffix = "stderr"; } else if (PMIX_FWD_STDDIAG_CHANNEL & stream) { /* write the bytes to stderr */ suffix = "stddiag"; } else { /* error - this should never happen */ PMIX_ERROR_LOG(PMIX_ERR_VALUE_OUT_OF_BOUNDS); pmix_output_verbose(1, pmix_client_globals.iof_output, "%s stream %0x", PMIX_NAME_PRINT(&pmix_globals.myid), stream); PMIx_Byte_object_free(output, 1); return NULL; } if (!myflags->set) { /* the data is not to be tagged - just copy it * and move on to processing */ output->bytes = (char*)malloc(bo->size); memcpy(output->bytes, bo->bytes, bo->size); output->size = bo->size; return output; } /* if this is to be xml tagged, create a tag with the correct syntax - we do not allow * timestamping of xml output */ if (myflags->xml) { if (myflags->tag) { /* find the '@' delimiter in the nspace */ cptr = strrchr(name->nspace, '@'); if (NULL == cptr) { usestring = name->nspace; // just use the whole thing } else { ++cptr; usestring = cptr; // use the jobid portion } pmix_snprintf(begintag, PMIX_IOF_BASE_TAG_MAX, "<%s %s=\"%s\" rank=\"%s\"", suffix, (usestring == name->nspace) ? "nspace" : "jobid", usestring, PMIX_RANK_PRINT(name->rank)); } else if (myflags->tag_fullname) { pmix_snprintf(begintag, PMIX_IOF_BASE_TAG_MAX, "<%s nspace=\"%s\" rank=\"%s\"", suffix, name->nspace, PMIX_RANK_PRINT(name->rank)); } else if (myflags->tag_detailed) { /* we need the hostname and pid of the source */ PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = (pmix_proc_t*)name; cb2.key = PMIX_HOSTNAME; cb2.info = &optional; cb2.ninfo = 1; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs); if (NULL != kv) { // should never be NULL cptr = strdup(kv->value->data.string); PMIX_RELEASE(kv); } else { cptr = strdup("unknown"); } } else { cptr = strdup("unknown"); } PMIX_DESTRUCT(&cb2); /* get the pid */ PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = (pmix_proc_t*)name; cb2.key = PMIX_PROC_PID; cb2.info = &optional; cb2.ninfo = 1; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs); if (NULL != kv) { // should never be NULL rc = PMIx_Value_get_number(kv->value, &pid, PMIX_PID); PMIX_RELEASE(kv); if (PMIX_SUCCESS != rc) { pidstring = strdup("unknown"); } else { pmix_asprintf(&pidstring, "%u", pid); } } else { pidstring = strdup("unknown"); } } else { pidstring = strdup("unknown"); } PMIX_DESTRUCT(&cb2); pmix_snprintf(begintag, PMIX_IOF_BASE_TAG_MAX, "<%s nspace=\"%s\" rank=\"%s\"[\"%s\":\"%s\"", suffix, name->nspace, PMIX_RANK_PRINT(name->rank), cptr, pidstring); free(cptr); free(pidstring); } else if (myflags->rank) { pmix_snprintf(begintag, PMIX_IOF_BASE_TAG_MAX, "<%s rank=\"%s\"", suffix, PMIX_RANK_PRINT(name->rank)); } else if (myflags->timestamp) { pmix_snprintf(begintag, PMIX_IOF_BASE_TAG_MAX, "<%s rank=\"%s\"", suffix, PMIX_RANK_PRINT(name->rank)); } else { pmix_snprintf(begintag, PMIX_IOF_BASE_TAG_MAX, "<%s rank=\"%s\"", suffix, PMIX_RANK_PRINT(name->rank)); } pmix_snprintf(endtag, PMIX_IOF_BASE_TAG_MAX, "", suffix); } else { if (myflags->tag) { /* find the '@' delimiter in the nspace */ cptr = strrchr(name->nspace, '@'); if (NULL == cptr) { usestring = name->nspace; // just use the whole thing } else { ++cptr; usestring = cptr; // use the jobid portion } pmix_snprintf(outtag, PMIX_IOF_BASE_TAG_MAX, "[%s,%s]<%s>: ", usestring, PMIX_RANK_PRINT(name->rank), suffix); } else if (myflags->tag_detailed) { if (myflags->tag_fullname) { usestring = name->nspace; } else { /* find the '@' delimiter in the nspace */ cptr = strrchr(name->nspace, '@'); if (NULL == cptr) { usestring = name->nspace; // just use the whole thing } else { ++cptr; usestring = cptr; // use the jobid portion } } /* we need the hostname and pid of the source */ PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = (pmix_proc_t*)name; cb2.key = PMIX_HOSTNAME; cb2.info = &optional; cb2.ninfo = 1; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs); cptr = strdup(kv->value->data.string); PMIX_RELEASE(kv); } else { cptr = strdup("unknown"); } PMIX_DESTRUCT(&cb2); /* get the pid */ PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = (pmix_proc_t*)name; cb2.key = PMIX_PROC_PID; cb2.info = &optional; cb2.ninfo = 1; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs); rc = PMIx_Value_get_number(kv->value, &pid, PMIX_PID); PMIX_RELEASE(kv); if (PMIX_SUCCESS != rc) { pidstring = strdup("unknown"); } else { pmix_asprintf(&pidstring, "%u", pid); } } else { pidstring = strdup("unknown"); } PMIX_DESTRUCT(&cb2); pmix_snprintf(outtag, PMIX_IOF_BASE_TAG_MAX, "[%s,%s][%s:%s]<%s>: ", usestring, PMIX_RANK_PRINT(name->rank), cptr, pidstring, suffix); free(cptr); free(pidstring); } else if (myflags->tag_fullname) { pmix_snprintf(outtag, PMIX_IOF_BASE_TAG_MAX, "[%s,%s]<%s>: ", name->nspace, PMIX_RANK_PRINT(name->rank), suffix); } else if (myflags->rank) { pmix_snprintf(outtag, PMIX_IOF_BASE_TAG_MAX, "[%s]<%s>: ", PMIX_RANK_PRINT(name->rank), suffix); } } /* if we are to timestamp output, start the tag with that */ if (myflags->timestamp) { time_t mytime; /* get the timestamp */ time(&mytime); cptr = ctime(&mytime); cptr[strlen(cptr) - 1] = '\0'; /* remove trailing newline */ if (myflags->xml && !myflags->tag && !myflags->rank) { pmix_snprintf(timestamp, PMIX_IOF_BASE_TAG_MAX, " timestamp=\"%s\"", cptr); } else if (myflags->xml && (myflags->tag || myflags->rank)) { pmix_snprintf(timestamp, PMIX_IOF_BASE_TAG_MAX, " timestamp=\"%s\"", cptr); } else if (myflags->tag || myflags->rank) { pmix_snprintf(timestamp, PMIX_IOF_BASE_TAG_MAX, "[%s]", cptr); } else { pmix_snprintf(timestamp, PMIX_IOF_BASE_TAG_MAX, "[%s]<%s>: ", cptr, suffix); } } /* start with the starttag */ if (0 < strlen(begintag)) { PMIx_Argv_append_nosize(&segments, begintag); } /* add the timestamp */ if (0 < strlen(timestamp)) { PMIx_Argv_append_nosize(&segments, timestamp); } /* add the output tag */ if (0 < strlen(outtag)) { PMIx_Argv_append_nosize(&segments, outtag); } /* if xml, end the starttag with a '>' */ if (myflags->xml) { PMIx_Argv_append_nosize(&segments, ">"); } /* if we are doing XML, then we need to replace key characters */ if (myflags->xml) { bufsize = bo->size; for (n = 0; n < bo->size; n++) { if ('&' == bo->bytes[n]) { bufsize += 5; } else if ('<' == bo->bytes[n] || '>' == bo->bytes[n]) { bufsize += 4; } else if (!isprint(bo->bytes[n])) { pmix_snprintf(qprint, 10, "&#%03d;", (int) bo->bytes[n]); bufsize += strlen(qprint); } } if (bo->size < bufsize) { /* we need to increase the size of our buffer to handle the * extra characters we need to add to represent these special * cases */ buffer = malloc(bufsize); memset(buffer, 0, bufsize); bufcopy = true; m = 0; for (n = 0; n < bo->size; n++) { if ('&' == bo->bytes[n]) { buffer[m++] = '&'; buffer[m++] = 'a'; buffer[m++] = 'p'; buffer[m++] = ';'; } else if ('<' == bo->bytes[n]) { buffer[m++] = '&'; buffer[m++] = 'l'; buffer[m++] = 't'; buffer[m++] = ';'; } else if ('>' == bo->bytes[n]) { buffer[m++] = '&'; buffer[m++] = 'g'; buffer[m++] = 't'; buffer[m++] = ';'; } else if (!isprint(bo->bytes[n])) { pmix_snprintf(qprint, 10, "&#%03d;", (int) bo->bytes[n]); for (j = 0; j < strlen(qprint); j++) { buffer[m++] = qprint[j]; } } else { buffer[m++] = bo->bytes[n]; } } } else { buffer = bo->bytes; bufsize = bo->size; bufcopy = false; } } else { buffer = bo->bytes; bufsize = bo->size; bufcopy = false; } /* assemble the output line */ if (NULL != segments) { for (n=0; NULL != segments[n]; n++) { output->size += strlen(segments[n]); } } output->size += bufsize; output->size += strlen(endtag); if (myflags->xml) { // add a spot for a trailing newline output->size++; } output->bytes = (char*)malloc(output->size); offset = 0; if (NULL != segments) { for (n=0; NULL != segments[n]; n++) { memcpy(&output->bytes[offset], segments[n], strlen(segments[n])); offset += strlen(segments[n]); } } memcpy(&output->bytes[offset], buffer, bufsize); offset += bufsize; if (0 < strlen(endtag)) { memcpy(&output->bytes[offset], endtag, strlen(endtag)); } if (myflags->xml) { output->bytes[output->size-1] = '\n'; } if (bufcopy) { free(buffer); } return output; } static pmix_status_t write_output_line(const pmix_proc_t *name, pmix_iof_write_event_t *channel, pmix_iof_flags_t *myflags, pmix_iof_channel_t stream, bool copystdout, bool copystderr, const pmix_byte_object_t *bo) { pmix_byte_object_t *wbo; pmix_iof_write_output_t *copy; pmix_iof_write_output_t *output; /* write output data to the corresponding tag */ if (PMIX_FWD_STDIN_CHANNEL & stream) { output = PMIX_NEW(pmix_iof_write_output_t); /* copy over the data to be written */ if (0 < bo->size) { /* don't copy 0 bytes - we just need to pass * the zero bytes so the fd can be closed * after it writes everything out */ output->data = (char*)malloc(bo->size); memcpy(output->data, bo->bytes, bo->size); } output->numbytes = bo->size; goto process; } // process the stream for output formatting wbo = pmix_iof_prep_output(name, myflags, stream, bo); if (NULL == wbo) { return PMIX_ERR_NOT_SUPPORTED; } output = PMIX_NEW(pmix_iof_write_output_t); output->data = wbo->bytes; output->numbytes = wbo->size; // protect returned data region wbo->bytes = NULL; wbo->size = 0; PMIx_Byte_object_free(wbo, 1); process: /* add this data to the write list for this fd */ pmix_list_append(&channel->outputs, &output->super); if (copystdout){ copy = PMIX_NEW(pmix_iof_write_output_t); copy->data = (char *) malloc(output->numbytes); memcpy(copy->data, output->data, output->numbytes); copy->numbytes = output->numbytes; pmix_list_append(&pmix_client_globals.iof_stdout.wev.outputs, ©->super); if (!pmix_client_globals.iof_stdout.wev.pending) { PMIX_IOF_SINK_ACTIVATE(&pmix_client_globals.iof_stdout.wev); } } if (copystderr){ copy = PMIX_NEW(pmix_iof_write_output_t); copy->data = (char *) malloc(output->numbytes); memcpy(copy->data, output->data, output->numbytes); copy->numbytes = output->numbytes; pmix_list_append(&pmix_client_globals.iof_stderr.wev.outputs, ©->super); if (!pmix_client_globals.iof_stderr.wev.pending) { PMIX_IOF_SINK_ACTIVATE(&pmix_client_globals.iof_stderr.wev); } } /* is the write event issued? */ if (!channel->pending) { /* issue it */ pmix_output_verbose(1, pmix_client_globals.iof_output, "%s write:output adding write event", PMIX_NAME_PRINT(&pmix_globals.myid)); PMIX_IOF_SINK_ACTIVATE(channel); } return PMIX_SUCCESS; } pmix_status_t pmix_iof_write_output(const pmix_proc_t *name, pmix_iof_channel_t stream, const pmix_byte_object_t *bo) { pmix_status_t rc; size_t n, start; pmix_byte_object_t bopass; pmix_iof_write_event_t *channel; pmix_iof_flags_t myflags; pmix_namespace_t *nptr, *ns; bool outputio; bool copystdout = false; bool copystderr = false; pmix_iof_sink_t *sink; pmix_iof_residual_t *res; char *inputdata; size_t inputsize; bool copied; /* stdin doesn't come thru here*/ if (PMIX_FWD_STDIN_CHANNEL & stream) { return PMIX_ERR_BAD_PARAM; } /* find the nspace for this source */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(ns->nspace, name->nspace)) { nptr = ns; break; } } channel = NULL; /* default outputio to our flag */ outputio = pmix_globals.iof_flags.local_output; if (NULL != nptr) { if (nptr->iof_flags.set) { if (nptr->iof_flags.local_output_given) { outputio = nptr->iof_flags.local_output; } if (!outputio) { return PMIX_SUCCESS; } /* do we need an IOF channel for this source? */ if (NULL != nptr->iof_flags.directory) { /* see if we already have one */ PMIX_LIST_FOREACH(sink, &nptr->sinks, pmix_iof_sink_t) { if (sink->name.rank == name->rank && ((stream & sink->tag) || nptr->iof_flags.merge)) { channel = &sink->wev; break; } } if (NULL == channel) { /* need to set this one up */ channel = pmix_iof_setup(nptr, name->rank, stream); if (NULL == channel) { return PMIX_ERR_IOF_FAILURE; } } if (!nptr->iof_flags.nocopy && pmix_globals.iof_flags.local_output) { if (PMIX_FWD_STDOUT_CHANNEL & stream) { copystdout = true; } else { copystderr = true; } } } else if (NULL != nptr->iof_flags.file) { /* see if we already have one - we reuse the same sink for * all streams */ PMIX_LIST_FOREACH(sink, &nptr->sinks, pmix_iof_sink_t) { if (sink->name.rank == name->rank && ((stream & sink->tag) || nptr->iof_flags.merge)) { channel = &sink->wev; break; } } if (NULL == channel) { /* need to set this one up */ channel = pmix_iof_setup(nptr, name->rank, stream); if (NULL == channel) { return PMIX_ERR_IOF_FAILURE; } } if (!nptr->iof_flags.nocopy && pmix_globals.iof_flags.local_output) { if (PMIX_FWD_STDOUT_CHANNEL & stream) { copystdout = true; } else { copystderr = true; } } } myflags = nptr->iof_flags; } else { myflags = pmix_globals.iof_flags; } } else { myflags = pmix_globals.iof_flags; } if (!outputio) { return PMIX_SUCCESS; } if (NULL == channel) { if (PMIX_FWD_STDOUT_CHANNEL & stream) { channel = &pmix_client_globals.iof_stdout.wev; } else { if(!myflags.merge) { channel = &pmix_client_globals.iof_stderr.wev; } else { channel = &pmix_client_globals.iof_stdout.wev; } } } pmix_output_verbose(1, pmix_client_globals.iof_output, "%s write:output setting up to write %lu bytes to %s for %s on fd %d", PMIX_NAME_PRINT(&pmix_globals.myid), (unsigned long) bo->size, PMIx_IOF_channel_string(stream), PMIX_NAME_PRINT(name), (NULL == channel) ? -1 : channel->fd); /* zero bytes can just be passed along */ if (0 == bo->size) { rc = write_output_line(name, channel, &myflags, stream, false, false, bo); return rc; } if (myflags.raw) { rc = write_output_line(name, channel, &myflags, stream, copystdout, copystderr, bo); return rc; } else { /* see if we have some residual for this name/stream */ inputdata = bo->bytes; inputsize = bo->size; copied = false; PMIX_LIST_FOREACH(res, &pmix_server_globals.iof_residuals, pmix_iof_residual_t) { if (PMIX_CHECK_PROCID(name, &res->name) && (stream & res->stream)) { /* we need to pre-pend the residual data to the new * data so any lines can be completed */ inputdata = (char*)malloc(inputsize + res->bo.size); memcpy(inputdata, res->bo.bytes, res->bo.size); memcpy(&inputdata[res->bo.size], bo->bytes, bo->size); inputsize += res->bo.size; copied = true; pmix_list_remove_item(&pmix_server_globals.iof_residuals, &res->super); PMIX_RELEASE(res); break; } } /* search the input data stream for '\n' */ start = 0; for (n=0; n < inputsize; n++) { if ('\n' == inputdata[n]) { bopass.bytes = &inputdata[start]; bopass.size = n - start + 1; rc = write_output_line(name, channel, &myflags, stream, copystdout, copystderr, &bopass); if (PMIX_SUCCESS != rc) { if (copied) { free(inputdata); } return rc; } start = n + 1; } } if (start < inputsize) { /* we have some residual that needs to be cached until * the rest of the line is seen */ res = PMIX_NEW(pmix_iof_residual_t); PMIX_XFER_PROCID(&res->name, name); res->channel = channel; memcpy(&res->flags, &myflags, sizeof(pmix_iof_flags_t)); res->stream = stream; res->copystdout = copystdout; res->copystderr = copystderr; res->bo.bytes = (char*)malloc(inputsize - start); memcpy(res->bo.bytes, &inputdata[start], inputsize - start); res->bo.size = inputsize - start; pmix_list_append(&pmix_server_globals.iof_residuals, &res->super); } } if (copied) { free(inputdata); } return PMIX_SUCCESS; } void pmix_iof_flush_residuals(void) { pmix_status_t rc; pmix_iof_residual_t *res; PMIX_LIST_FOREACH(res, &pmix_server_globals.iof_residuals, pmix_iof_residual_t) { rc = write_output_line(&res->name, res->channel, &res->flags, res->stream, res->copystdout, res->copystderr, &res->bo); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } } } static void flush_sink_residuals(pmix_iof_sink_t *sink) { pmix_status_t rc = PMIX_SUCCESS; pmix_iof_residual_t *res, *next; pmix_list_t *residuals = &pmix_server_globals.iof_residuals; PMIX_LIST_FOREACH_SAFE(res, next, residuals, pmix_iof_residual_t) { if(res->channel != &sink->wev){ continue; } if(PMIX_SUCCESS == rc){ rc = write_output_line(&res->name, res->channel, &res->flags, res->stream, res->copystdout, res->copystderr, &res->bo); if(PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } pmix_list_remove_item(residuals, &res->super); PMIX_RELEASE(res); } } void pmix_iof_static_dump_output(pmix_iof_sink_t *sink) { bool dump; int num_written; pmix_iof_write_event_t *wev = &sink->wev; pmix_iof_write_output_t *output; if (!pmix_list_is_empty(&wev->outputs)) { dump = false; /* make one last attempt to write this out */ while (NULL != (output = (pmix_iof_write_output_t *) pmix_list_remove_first(&wev->outputs))) { if (!dump && 0 < output->numbytes) { num_written = write(wev->fd, output->data, output->numbytes); if (num_written < output->numbytes) { /* don't retry - just cleanout the list and dump it */ dump = true; } } PMIX_RELEASE(output); } } } void pmix_iof_write_handler(int sd, short args, void *cbdata) { pmix_iof_sink_t *sink = (pmix_iof_sink_t *) cbdata; pmix_iof_write_event_t *wev = &sink->wev; pmix_list_item_t *item; pmix_iof_write_output_t *output; int num_written, total_written = 0; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(sink); pmix_output_verbose(1, pmix_client_globals.iof_output, "%s write:handler writing data to %d", PMIX_NAME_PRINT(&pmix_globals.myid), wev->fd); while (NULL != (item = pmix_list_remove_first(&wev->outputs))) { output = (pmix_iof_write_output_t *) item; if (0 == output->numbytes) { /* don't reactivate the event */ PMIX_RELEASE(output); if (2 < wev->fd) { // close the channel close(wev->fd); wev->fd = -1; } return; } num_written = write(wev->fd, output->data, output->numbytes); if (num_written < 0) { if (EAGAIN == errno || EINTR == errno) { /* push this item back on the front of the list */ pmix_list_prepend(&wev->outputs, item); /* if the list is getting too large, abort */ if (pmix_globals.output_limit < pmix_list_get_size(&wev->outputs)) { pmix_output(0, "IO Forwarding is running too far behind - something is " "blocking us from writing"); goto ABORT; } /* leave the write event running so it will call us again * when the fd is ready. */ wev->numtries++; if (PMIX_IOF_MAX_RETRIES < wev->numtries) { /* give up */ pmix_output(0, "IO Forwarding is unable to output - something is " "blocking us from writing"); goto ABORT; } goto NEXT_CALL; } /* otherwise, something bad happened so all we can do is abort * this attempt */ PMIX_RELEASE(output); goto ABORT; } else if (num_written < output->numbytes) { /* incomplete write - adjust data to avoid duplicate output */ memmove(output->data, &output->data[num_written], output->numbytes - num_written); /* adjust the number of bytes remaining to be written */ output->numbytes -= num_written; /* push this item back on the front of the list */ pmix_list_prepend(&wev->outputs, item); /* if the list is getting too large, abort */ if (pmix_globals.output_limit < pmix_list_get_size(&wev->outputs)) { pmix_output(0, "IO Forwarding is running too far behind - something is blocking us " "from writing"); goto ABORT; } /* leave the write event running so it will call us again * when the fd is ready */ wev->numtries = 0; goto NEXT_CALL; } PMIX_RELEASE(output); wev->numtries = 0; total_written += num_written; if (wev->always_writable && (PMIX_IOF_SINK_BLOCKSIZE <= total_written)) { /* If this is a regular file it will never tell us it will block * Write no more than PMIX_IOF_SINK_BLOCKSIZE at a time to allow * other fds to progress */ goto NEXT_CALL; } } ABORT: wev->pending = false; PMIX_POST_OBJECT(wev); return; NEXT_CALL: PMIX_IOF_SINK_ACTIVATE(wev); } /* return true if we should read stdin from fd, false otherwise */ bool pmix_iof_stdin_check(int fd) { #if defined(HAVE_TCGETPGRP) if (isatty(fd) && (getpgrp() != tcgetpgrp(fd))) { return false; } #endif return true; } void pmix_iof_stdin_cb(int sd, short args, void *cbdata) { bool should_process; pmix_iof_read_event_t *stdinev = (pmix_iof_read_event_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(stdinev); should_process = pmix_iof_stdin_check(0); if (should_process) { PMIX_IOF_READ_ACTIVATE(stdinev); } else { pmix_event_del(&stdinev->ev); stdinev->active = false; PMIX_POST_OBJECT(stdinev); } } static void iof_stdin_cbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_iof_read_event_t *stdinev = (pmix_iof_read_event_t *) cbdata; int cnt; pmix_status_t rc, ret; PMIX_HIDE_UNUSED_PARAMS(hdr); PMIX_ACQUIRE_OBJECT(stdinev); /* check the return status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { pmix_event_del(&stdinev->ev); stdinev->active = false; PMIX_POST_OBJECT(stdinev); return; } /* if the status wasn't success, then terminate the forward */ if (PMIX_SUCCESS != ret) { pmix_event_del(&stdinev->ev); stdinev->active = false; PMIX_POST_OBJECT(stdinev); if (PMIX_ERR_IOF_COMPLETE != ret) { /* generate an IOF-failed event so the tool knows */ PMIx_Notify_event(PMIX_ERR_IOF_FAILURE, &pmix_globals.myid, PMIX_RANGE_PROC_LOCAL, NULL, 0, NULL, NULL); } return; } pmix_iof_stdin_cb(0, 0, stdinev); } static void opcbfn(pmix_status_t status, void *cbdata) { pmix_byte_object_t *boptr = (pmix_byte_object_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_ACQUIRE_OBJECT(boptr); PMIX_BYTE_OBJECT_FREE(boptr, 1); } /* this is the read handler for stdin */ void pmix_iof_read_local_handler(int sd, short args, void *cbdata) { pmix_iof_read_event_t *rev = (pmix_iof_read_event_t *) cbdata; unsigned char data[PMIX_IOF_BASE_MSG_MAX]; int32_t numbytes; pmix_status_t rc; pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_IOF_PUSH_CMD; pmix_byte_object_t bo, *boptr; int fd; pmix_pfexec_child_t *child = (pmix_pfexec_child_t *) rev->childproc; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(rev); if (0 > rev->fd) { fd = fileno(stdin); } else { fd = rev->fd; } /* read up to the fragment size */ memset(data, 0, PMIX_IOF_BASE_MSG_MAX); numbytes = read(fd, data, sizeof(data)); /* The event has fired, so it's no longer active until we re-add it */ rev->active = false; if (numbytes < 0) { /* either we have a connection error or it was a non-blocking read */ /* non-blocking, retry */ if (EAGAIN == errno || EINTR == errno) { PMIX_IOF_READ_ACTIVATE(rev); return; } pmix_output_verbose(1, pmix_client_globals.iof_output, "%s iof:read handler Error on %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIx_IOF_channel_string(rev->channel)); /* Un-recoverable error */ bo.bytes = NULL; bo.size = 0; numbytes = 0; } else { bo.bytes = (char *) data; bo.size = numbytes; } /* if this is stdout or stderr of a child, then just output it */ if (NULL != child && (PMIX_FWD_STDOUT_CHANNEL == rev->channel || PMIX_FWD_STDERR_CHANNEL == rev->channel)) { if (PMIX_FWD_STDOUT_CHANNEL == rev->channel) { rc = pmix_iof_write_output(&child->stdoutev->name, PMIX_FWD_STDOUT_CHANNEL, &bo); } else if (PMIX_FWD_STDERR_CHANNEL == rev->channel) { rc = pmix_iof_write_output(&child->stderrev->name, PMIX_FWD_STDERR_CHANNEL, &bo); } else { rc = PMIX_ERR_BAD_PARAM; } if (0 > rc) { PMIX_ERROR_LOG(rc); } /* if the number of bytes is zero, then we just delete the event - there * is no need to pass it upstream as WE are the ones holding the event * and associated file descriptor */ if (0 == numbytes) { if (NULL != child && child->completed && (NULL == child->stdoutev || !child->stdoutev->active) && (NULL == child->stderrev || !child->stderrev->active)) { PMIX_PFEXEC_CHK_COMPLETE(child); } return; } goto reactivate; } /* if it is stdin that was read, then see if we have a sink * for a child of ours that matches this target - this has precedence over * anything else */ if (PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { if (rev == stdinev_global && NULL != rev->targets) { PMIX_LIST_FOREACH(child, &pmix_pfexec_globals.children, pmix_pfexec_child_t) { if (PMIX_CHECK_PROCID(&child->proc, &rev->targets[0])) { /* send the input to that target */ rc = write_output_line(&child->proc, &child->stdinsink.wev, NULL, PMIX_FWD_STDIN_CHANNEL, false, false, &bo); goto reactivate; } } } } /* if I am a launcher or a tool and connected to a server, then * we want to send things to our server for relay */ if ((PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) || PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) && pmix_atomic_check_bool(&pmix_globals.connected)) { goto forward; } /* if I am a server, then push this up to my host */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { if (NULL == pmix_host_server.push_stdin) { /* nothing we can do with this info - no point in reactivating it */ return; } if (0 == bo.size) { // our stdin fd has closed - nothing to do, and // we don't reactivate the event return; } PMIX_BYTE_OBJECT_CREATE(boptr, 1); if (0 < bo.size) { boptr->bytes = (char*)malloc(bo.size); memcpy(boptr->bytes, bo.bytes, bo.size); boptr->size = bo.size; } rc = pmix_host_server.push_stdin(&pmix_globals.myid, rev->targets, rev->ntargets, rev->directives, rev->ndirs, boptr, opcbfn, (void*)boptr); goto reactivate; } forward: /* pass the data to our PMIx server so it can relay it * to the host RM for distribution */ msg = PMIX_NEW(pmix_buffer_t); if (NULL == msg) { /* don't restart the event - just return */ return; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } /* pack the number of targets */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &rev->ntargets, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } /* and the targets */ if (0 < rev->ntargets) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, rev->targets, rev->ntargets, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } } /* pack the number of directives */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &rev->ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } /* and the directives */ if (0 < rev->ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, rev->directives, rev->ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } } /* pack the data */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &bo, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return; } /* send it to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, iof_stdin_cbfunc, rev); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); } reactivate: if (0 < numbytes) { PMIX_IOF_READ_ACTIVATE(rev); } /* nothing more to do */ return; } /* class instances */ static void iof_sink_construct(pmix_iof_sink_t *ptr) { PMIX_CONSTRUCT(&ptr->wev, pmix_iof_write_event_t); ptr->xoff = false; ptr->exclusive = false; ptr->closed = false; } static void iof_sink_destruct(pmix_iof_sink_t *ptr) { // flush any residuals on this namespace's sinks, and dump their output if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { flush_sink_residuals(ptr); } pmix_iof_static_dump_output(ptr); // close the sink if (0 <= ptr->wev.fd) { pmix_output_verbose(20, pmix_client_globals.iof_output, "%s iof: closing sink for process %s on fd %d", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_NAME_PRINT(&ptr->name), ptr->wev.fd); PMIX_DESTRUCT(&ptr->wev); } } PMIX_CLASS_INSTANCE(pmix_iof_sink_t, pmix_list_item_t, iof_sink_construct, iof_sink_destruct); static void iof_read_event_construct(pmix_iof_read_event_t *rev) { rev->tv.tv_sec = 0; rev->tv.tv_usec = 0; rev->fd = -1; rev->channel = PMIX_FWD_NO_CHANNELS; rev->active = false; rev->childproc = NULL; rev->always_readable = false; rev->targets = NULL; rev->ntargets = 0; rev->directives = NULL; rev->ndirs = 0; } static void iof_read_event_destruct(pmix_iof_read_event_t *rev) { if (rev->active) { pmix_event_del(&rev->ev); } if (0 <= rev->fd) { pmix_output_verbose(20, pmix_client_globals.iof_output, "%s iof: closing fd %d", PMIX_NAME_PRINT(&pmix_globals.myid), rev->fd); close(rev->fd); rev->fd = -1; } if (NULL != rev->targets) { PMIX_PROC_FREE(rev->targets, rev->ntargets); } if (NULL != rev->directives) { PMIX_INFO_FREE(rev->directives, rev->ndirs); } } PMIX_CLASS_INSTANCE(pmix_iof_read_event_t, pmix_object_t, iof_read_event_construct, iof_read_event_destruct); static void iof_write_event_construct(pmix_iof_write_event_t *wev) { wev->pending = false; wev->always_writable = false; wev->numtries = 0; wev->ev = (pmix_event_t*)malloc(sizeof(pmix_event_t)); wev->fd = -1; PMIX_CONSTRUCT(&wev->outputs, pmix_list_t); wev->tv.tv_sec = 0; wev->tv.tv_usec = 0; } static void iof_write_event_destruct(pmix_iof_write_event_t *wev) { if (wev->pending) { pmix_event_del(wev->ev); } free(wev->ev); if (2 < wev->fd) { pmix_output_verbose(20, pmix_client_globals.iof_output, "%s iof: closing fd %d for write event", PMIX_NAME_PRINT(&pmix_globals.myid), wev->fd); close(wev->fd); } PMIX_LIST_DESTRUCT(&wev->outputs); } PMIX_CLASS_INSTANCE(pmix_iof_write_event_t, pmix_list_item_t, iof_write_event_construct, iof_write_event_destruct); static void wocon(pmix_iof_write_output_t *p) { p->data = NULL; p->numbytes = 0; } static void wodes(pmix_iof_write_output_t *p) { if (NULL != p->data) { free(p->data); } } PMIX_CLASS_INSTANCE(pmix_iof_write_output_t, pmix_list_item_t, wocon, wodes); static void iofrescon(pmix_iof_residual_t *p) { PMIX_BYTE_OBJECT_CONSTRUCT(&p->bo); } static void iofresdes(pmix_iof_residual_t *p) { if (NULL != p->bo.bytes) { free(p->bo.bytes); } } PMIX_CLASS_INSTANCE(pmix_iof_residual_t, pmix_list_item_t, iofrescon, iofresdes); pmix-6.1.1~rc2/src/common/pmix_attributes.h0000664000175000017500000000546615203536752021163 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2017 IBM Corporation. All rights reserved. * Copyright (c) 2017 Mellanox Technologies. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * I/O Forwarding Service */ #ifndef PMIX_ATTRIBUTES_H #define PMIX_ATTRIBUTES_H #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_NET_UIO_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" BEGIN_C_DECLS PMIX_EXPORT void pmix_init_registered_attrs(void); PMIX_EXPORT void pmix_release_registered_attrs(void); PMIX_EXPORT pmix_status_t pmix_register_tool_attrs(void); PMIX_EXPORT pmix_status_t pmix_register_client_attrs(void); PMIX_EXPORT pmix_status_t pmix_register_server_attrs(void); PMIX_EXPORT char **pmix_attributes_print_functions(char *level); PMIX_EXPORT char **pmix_attributes_print_attr(char *level, char *function); PMIX_EXPORT void pmix_attributes_print_attrs(char ***ans, char *function, pmix_regattr_t *attrs, size_t nattrs); PMIX_EXPORT void pmix_attributes_print_headers(char ***ans, char *level); PMIX_EXPORT void pmix_attrs_query_support(pmix_query_caddy_t *cd, pmix_query_t *qry, pmix_list_t *unresolved); PMIX_EXPORT const char *pmix_attributes_lookup(const char *name); PMIX_EXPORT const char *pmix_attributes_reverse_lookup(const char *name); PMIX_EXPORT const pmix_regattr_input_t *pmix_attributes_lookup_term(char *attr); END_C_DECLS #endif /* PMIX_IOF_H */ pmix-6.1.1~rc2/src/event/0000775000175000017500000000000015203536752015405 5ustar alastairalastairpmix-6.1.1~rc2/src/event/pmix_event_notification.c0000664000175000017500000020076215203536752022504 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2017-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2017 IBM Corporation. All rights reserved. * * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/bfrops.h" #include "src/server/pmix_server_ops.h" static void progress_local_event_hdlr(pmix_status_t status, pmix_info_t *results, size_t nresults, pmix_op_cbfunc_t cbfunc, void *thiscbdata, void *notification_cbdata); static void _ntfy_done(pmix_status_t status, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; if (NULL != scd->cbfunc.opcbfn) { scd->cbfunc.opcbfn(status, scd->cbdata); PMIX_RELEASE(scd); } else { scd->status = status; PMIX_WAKEUP_THREAD(&scd->lock); } } void pmix_internal_notify_event(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; int rc; pmix_proc_t *source = scd->proc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { pmix_output_verbose(2, pmix_server_globals.event_output, "pmix_server_notify_event source = %s:%d event_status = %s", (NULL == source) ? "UNKNOWN" : source->nspace, (NULL == source) ? PMIX_RANK_WILDCARD : source->rank, PMIx_Error_string(scd->status)); rc = pmix_server_notify_client_of_event(scd->status, source, scd->range, scd->info, scd->ninfo, _ntfy_done, scd); if (PMIX_SUCCESS != rc && PMIX_OPERATION_SUCCEEDED != rc) { PMIX_ERROR_LOG(rc); _ntfy_done(rc, scd); return; } if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { // let the completion function cleanup return; } return; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected) && PMIX_RANGE_PROC_LOCAL != scd->range) { _ntfy_done(PMIX_ERR_UNREACH, scd); return; } pmix_output_verbose(2, pmix_client_globals.event_output, "pmix_client_notify_event source = %s:%d event_status =%d", (NULL == source) ? pmix_globals.myid.nspace : source->nspace, (NULL == source) ? pmix_globals.myid.rank : source->rank, scd->status); rc = pmix_notify_server_of_event(scd->status, source, scd->range, scd->info, scd->ninfo, _ntfy_done, scd, true); if (PMIX_SUCCESS != rc) { _ntfy_done(rc, scd); } return; } /* if we are a client, we call this function to notify the server of * an event. If we are a server, our host RM will call this function * to notify us of an event */ PMIX_EXPORT pmix_status_t PMIx_Notify_event(pmix_status_t status, const pmix_proc_t *source, pmix_data_range_t range, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_shift_caddy_t *scd; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } scd->status = status; scd->proc = (pmix_proc_t*)source; scd->range = range; scd->info = (pmix_info_t*)info; scd->ninfo = ninfo; scd->cbfunc.opcbfn = cbfunc; scd->cbdata = cbdata; PMIX_THREADSHIFT(scd, pmix_internal_notify_event); if (NULL == cbfunc) { PMIX_WAIT_THREAD(&scd->lock); rc = scd->status; PMIX_RELEASE(scd); return rc; } return PMIX_SUCCESS; } static void notify_event_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { (void) hdr; pmix_status_t rc, ret = PMIX_ERR_LOST_CONNECTION; int32_t cnt = 1; pmix_cb_t *cb = (pmix_cb_t *) cbdata; if (0 < buf->bytes_used) { /* unpack the status */ PMIX_BFROPS_UNPACK(rc, pr, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; } } /* do the cback */ if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(ret, cb->cbdata); } PMIX_RELEASE(cb); } pmix_status_t pmix_notify_event_cache(pmix_notify_caddy_t *cd) { pmix_status_t rc; int j; pmix_notify_caddy_t *pk; int idx; time_t etime; /* add to our cache */ rc = pmix_hotel_checkin(&pmix_globals.notifications, cd, &cd->room); /* if there wasn't room, then search for the longest tenured * occupant and evict them */ if (PMIX_SUCCESS != rc) { etime = 0; idx = -1; for (j = 0; j < pmix_globals.max_events; j++) { pmix_hotel_knock(&pmix_globals.notifications, j, (void **) &pk); if (NULL == pk) { /* hey, there is room! */ pmix_hotel_checkin_with_res(&pmix_globals.notifications, cd, &cd->room); return PMIX_SUCCESS; } /* check the age */ if (0 == j) { etime = pk->ts; idx = j; } else { if (difftime(pk->ts, etime) < 0) { etime = pk->ts; idx = j; } } } if (0 <= idx) { /* we found the oldest occupant - evict it */ pmix_hotel_checkout_and_return_occupant(&pmix_globals.notifications, idx, (void **) &pk); PMIX_RELEASE(pk); rc = pmix_hotel_checkin(&pmix_globals.notifications, cd, &cd->room); } } return rc; } /* as a client, we pass the notification to our server */ pmix_status_t pmix_notify_server_of_event(pmix_status_t status, const pmix_proc_t *source, pmix_data_range_t range, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata, bool dolocal) { pmix_status_t rc; pmix_buffer_t *msg = NULL; pmix_cmd_t cmd = PMIX_NOTIFY_CMD; pmix_cb_t *cb; pmix_event_chain_t *chain = NULL; size_t n; bool holdcd; pmix_notify_caddy_t *cd; pmix_output_verbose(2, pmix_client_globals.event_output, "[%s:%d] client: notifying server %s:%d of status %s for range %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, pmix_client_globals.myserver->info->pname.nspace, pmix_client_globals.myserver->info->pname.rank, PMIx_Error_string(status), PMIx_Data_range_string(range)); holdcd = true; if (0 < ninfo) { /* check for caching instructions */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_EVENT_DO_NOT_CACHE)) { if (PMIX_INFO_TRUE(&info[n])) { holdcd = false; } break; } } } if (PMIX_RANGE_PROC_LOCAL != range) { /* create the msg object */ msg = PMIX_NEW(pmix_buffer_t); if (NULL == msg) { return PMIX_ERR_NOMEM; } /* pack the command */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* pack the status */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* no need to pack the source as it is us */ /* pack the range */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &range, 1, PMIX_DATA_RANGE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* pack the info */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } if (0 < ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } } if (dolocal) { /* setup for our own local callbacks */ chain = PMIX_NEW(pmix_event_chain_t); chain->status = status; chain->range = range; if (NULL == source) { PMIX_LOAD_PROCID(&chain->source, pmix_globals.myid.nspace, pmix_globals.myid.rank); } else { PMIX_LOAD_PROCID(&chain->source, source->nspace, source->rank); } /* we always leave space for event hdlr name and a callback object */ chain->nallocated = ninfo + 2; PMIX_INFO_CREATE(chain->info, chain->nallocated); /* prep the chain for processing */ pmix_prep_event_chain(chain, info, ninfo, true); if (PMIX_RANGE_PROC_LOCAL == range && holdcd) { /* we need to cache this event so we can pass it into * ourselves should someone later register for it */ cd = PMIX_NEW(pmix_notify_caddy_t); cd->status = status; PMIX_LOAD_PROCID(&cd->source, chain->source.nspace, chain->source.rank); cd->range = chain->range; if (0 < chain->ninfo) { cd->ninfo = chain->ninfo; PMIX_INFO_CREATE(cd->info, cd->ninfo); cd->nondefault = chain->nondefault; /* need to copy the info */ for (n = 0; n < cd->ninfo; n++) { PMIX_INFO_XFER(&cd->info[n], &chain->info[n]); } } if (NULL != chain->targets) { cd->ntargets = chain->ntargets; PMIX_PROC_CREATE(cd->targets, cd->ntargets); memcpy(cd->targets, chain->targets, cd->ntargets * sizeof(pmix_proc_t)); } if (NULL != chain->affected) { cd->naffected = chain->naffected; PMIX_PROC_CREATE(cd->affected, cd->naffected); if (NULL == cd->affected) { cd->naffected = 0; rc = PMIX_ERR_NOMEM; goto cleanup; } memcpy(cd->affected, chain->affected, cd->naffected * sizeof(pmix_proc_t)); } rc = pmix_notify_event_cache(cd); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd); goto cleanup; } chain->cached = true; } } if (PMIX_RANGE_PROC_LOCAL != range && NULL != msg) { /* if this is a "lost-connection" event, then there is no * server to pass it to! Likewise, we don't pass it to * ourselves */ if (PMIX_ERR_LOST_CONNECTION == status || pmix_globals.mypeer == pmix_client_globals.myserver) { PMIX_RELEASE(msg); goto local; } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the server acks/nacks the register events request. The * server will _not_ send this notification back to us, * so we handle it locally */ cb = PMIX_NEW(pmix_cb_t); cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; /* send to the server */ pmix_output_verbose(2, pmix_client_globals.event_output, "[%s:%d] client: notifying server %s:%d - sending", pmix_globals.myid.nspace, pmix_globals.myid.rank, pmix_client_globals.myserver->info->pname.nspace, pmix_client_globals.myserver->info->pname.rank); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, notify_event_cbfunc, cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cb); goto cleanup; } } else if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } local: if (dolocal) { /* now notify any matching registered callbacks we have */ pmix_invoke_local_event_hdlr(chain); } return PMIX_SUCCESS; cleanup: pmix_output_verbose(2, pmix_client_globals.event_output, "client: notifying server - unable to send"); if (NULL != msg) { PMIX_RELEASE(msg); } /* we were unable to send anything, so we just return the error */ return rc; } static void cycle_events(int sd, short args, void *cbdata) { pmix_event_chain_t *chain = (pmix_event_chain_t *) cbdata; size_t n, nsave, cnt; pmix_list_item_t *item; pmix_event_hdlr_t *nxt; pmix_info_t *newinfo; pmix_output_verbose(2, pmix_client_globals.event_output, "%s progressing local event with status %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIx_Error_string(chain->interim_status)); PMIX_HIDE_UNUSED_PARAMS(sd, args); /* aggregate the results per RFC0018 - first search the * prior chained results to see if any keys have been NULL'd * as this indicates that info struct should be removed */ nsave = 0; for (n = 0; n < chain->nresults; n++) { if (0 < strlen(chain->results[n].key)) { ++nsave; } } /* we have to at least record the status returned by each * stage of the event handler chain, so we have to reallocate * the array to make space */ /* add in any new results plus space for the returned status */ nsave += chain->ninterim + 1; /* create the new space */ PMIX_INFO_CREATE(newinfo, nsave); /* transfer over the prior data */ cnt = 0; for (n = 0; n < chain->nresults; n++) { if (0 < strlen(chain->results[n].key)) { PMIX_INFO_XFER(&newinfo[cnt], &chain->results[n]); ++cnt; } } /* save this handler's returned status */ if (NULL != chain->evhdlr && NULL != chain->evhdlr->name) { pmix_strncpy(newinfo[cnt].key, chain->evhdlr->name, PMIX_MAX_KEYLEN); } else { pmix_strncpy(newinfo[cnt].key, "UNKNOWN", PMIX_MAX_KEYLEN); } newinfo[cnt].value.type = PMIX_STATUS; newinfo[cnt].value.data.status = chain->status; ++cnt; /* transfer across the new results */ for (n = 0; n < chain->ninterim; n++) { PMIX_INFO_XFER(&newinfo[cnt], &chain->interim[n]); ++cnt; } /* release the prior results */ if (0 < chain->nresults) { PMIX_INFO_FREE(chain->results, chain->nresults); } /* pass along the new ones */ chain->results = newinfo; chain->nresults = cnt; /* clear any loaded name and object */ if (chain->nallocated > chain->ninfo) { chain->ninfo = chain->nallocated - 2; PMIX_INFO_DESTRUCT(&chain->info[chain->nallocated - 2]); PMIX_INFO_DESTRUCT(&chain->info[chain->nallocated - 1]); } // call their interim cbfunc if (NULL != chain->opcbfunc) { chain->opcbfunc(chain->interim_status, chain->cbdata); } /* if the caller indicates that the chain is completed, * or we completed the "last" event */ if (PMIX_EVENT_ACTION_COMPLETE == chain->interim_status || PMIX_EVENT_ORDER_LAST_OVERALL == chain->evhdlr->precedence || chain->endchain) { if (PMIX_EVENT_ACTION_COMPLETE == chain->interim_status) { chain->interim_status = PMIX_SUCCESS; } if (chain->evhdlr->oneshot) { /* remove this handler */ pmix_deregister_event_hdlr(chain->evhdlr->index, NULL); } goto complete; } item = NULL; /* see if we need to continue, starting with the single code events */ if (1 == chain->evhdlr->ncodes) { /* the last handler was for a single code - see if there are * any others that match this event */ if (PMIX_EVENT_ORDER_FIRST_OVERALL == chain->evhdlr->precedence) { item = pmix_list_get_begin(&pmix_globals.events.single_events); } else { item = &chain->evhdlr->super; } while (pmix_list_get_end(&pmix_globals.events.single_events) != (item = pmix_list_get_next(item))) { nxt = (pmix_event_hdlr_t *) item; if (nxt->codes[0] == chain->status && pmix_notify_check_range(&nxt->rng, &chain->source) && pmix_notify_check_affected(nxt->affected, nxt->naffected, chain->affected, chain->naffected)) { chain->evhdlr = nxt; /* reset our count to the info provided by the caller */ chain->ninfo = chain->nallocated - 2; /* if the handler has a name, then provide it */ if (NULL != chain->evhdlr->name) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_HDLR_NAME, chain->evhdlr->name, PMIX_STRING); chain->ninfo++; } /* if there is an evhdlr cbobject, provide it */ if (NULL != chain->evhdlr->cbobject) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_RETURN_OBJECT, chain->evhdlr->cbobject, PMIX_POINTER); chain->ninfo++; } nxt->evhdlr(nxt->index, chain->status, &chain->source, chain->info, chain->ninfo, chain->results, chain->nresults, progress_local_event_hdlr, (void *) chain); return; } } /* if we get here, then there are no more single code * events that match */ item = pmix_list_get_begin(&pmix_globals.events.multi_events); } /* see if we need to continue with the multi code events */ if (NULL != chain->evhdlr->codes || NULL != item) { /* the last handler was for a multi-code event, or we exhausted * all the single code events */ if (PMIX_EVENT_ORDER_FIRST_OVERALL == chain->evhdlr->precedence) { item = pmix_list_get_begin(&pmix_globals.events.multi_events); } else if (NULL == item) { /* if the last handler was multi-code, then start from that point */ item = &chain->evhdlr->super; } while (pmix_list_get_end(&pmix_globals.events.multi_events) != (item = pmix_list_get_next(item))) { nxt = (pmix_event_hdlr_t *) item; if (!pmix_notify_check_range(&nxt->rng, &chain->source) || !pmix_notify_check_affected(nxt->affected, nxt->naffected, chain->affected, chain->naffected)) { continue; } for (n = 0; n < nxt->ncodes; n++) { /* if this event handler provided a range, check to see if * the source fits within it */ if (nxt->codes[n] == chain->status) { chain->evhdlr = nxt; /* reset our count to the info provided by the caller */ chain->ninfo = chain->nallocated - 2; /* if the handler has a name, then provide it */ if (NULL != chain->evhdlr->name) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_HDLR_NAME, chain->evhdlr->name, PMIX_STRING); chain->ninfo++; } /* if there is an evhdlr cbobject, provide it */ if (NULL != chain->evhdlr->cbobject) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_RETURN_OBJECT, chain->evhdlr->cbobject, PMIX_POINTER); chain->ninfo++; } nxt->evhdlr(nxt->index, chain->status, &chain->source, chain->info, chain->ninfo, chain->results, chain->nresults, progress_local_event_hdlr, (void *) chain); return; } } } /* if we get here, then there are no more multi-mode * events that match */ item = pmix_list_get_begin(&pmix_globals.events.default_events); } /* if they didn't want it to go to a default handler, then ignore them */ if (!chain->nondefault) { if (PMIX_EVENT_ORDER_FIRST_OVERALL == chain->evhdlr->precedence) { item = pmix_list_get_begin(&pmix_globals.events.default_events); } else if (NULL == item) { item = &chain->evhdlr->super; } if (pmix_list_get_end(&pmix_globals.events.default_events) != (item = pmix_list_get_next(item))) { nxt = (pmix_event_hdlr_t *) item; /* if this event handler provided a range, check to see if * the source fits within it */ if (pmix_notify_check_range(&nxt->rng, &chain->source) && pmix_notify_check_affected(nxt->affected, nxt->naffected, chain->affected, chain->naffected)) { chain->evhdlr = nxt; /* reset our count to the info provided by the caller */ chain->ninfo = chain->nallocated - 2; /* if the handler has a name, then provide it */ if (NULL != chain->evhdlr->name) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_HDLR_NAME, chain->evhdlr->name, PMIX_STRING); chain->ninfo++; } /* if there is an evhdlr cbobject, provide it */ if (NULL != chain->evhdlr->cbobject) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_RETURN_OBJECT, chain->evhdlr->cbobject, PMIX_POINTER); chain->ninfo++; } nxt->evhdlr(nxt->index, chain->status, &chain->source, chain->info, chain->ninfo, chain->results, chain->nresults, progress_local_event_hdlr, (void *) chain); return; } } } /* if we registered a "last" handler, and it fits the given range * and code, then invoke it now */ if (NULL != pmix_globals.events.last && pmix_notify_check_range(&pmix_globals.events.last->rng, &chain->source) && pmix_notify_check_affected(pmix_globals.events.last->affected, pmix_globals.events.last->naffected, chain->affected, chain->naffected)) { chain->endchain = true; // ensure we don't do this again if (1 == pmix_globals.events.last->ncodes && pmix_globals.events.last->codes[0] == chain->status) { chain->evhdlr = pmix_globals.events.last; /* reset our count to the info provided by the caller */ chain->ninfo = chain->nallocated - 2; /* if the handler has a name, then provide it */ if (NULL != chain->evhdlr->name) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_HDLR_NAME, chain->evhdlr->name, PMIX_STRING); chain->ninfo++; } /* if there is an evhdlr cbobject, provide it */ if (NULL != chain->evhdlr->cbobject) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_RETURN_OBJECT, chain->evhdlr->cbobject, PMIX_POINTER); chain->ninfo++; } chain->evhdlr->evhdlr(chain->evhdlr->index, chain->status, &chain->source, chain->info, chain->ninfo, chain->results, chain->nresults, progress_local_event_hdlr, (void *) chain); return; } else if (NULL != pmix_globals.events.last->codes) { /* need to check if this code is included in the array */ for (n = 0; n < pmix_globals.events.last->ncodes; n++) { if (pmix_globals.events.last->codes[n] == chain->status) { chain->evhdlr = pmix_globals.events.last; /* reset our count to the info provided by the caller */ chain->ninfo = chain->nallocated - 2; /* if the handler has a name, then provide it */ if (NULL != chain->evhdlr->name) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_HDLR_NAME, chain->evhdlr->name, PMIX_STRING); chain->ninfo++; } /* if there is an evhdlr cbobject, provide it */ if (NULL != chain->evhdlr->cbobject) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_RETURN_OBJECT, chain->evhdlr->cbobject, PMIX_POINTER); chain->ninfo++; } chain->evhdlr->evhdlr(chain->evhdlr->index, chain->status, &chain->source, chain->info, chain->ninfo, chain->results, chain->nresults, progress_local_event_hdlr, (void *) chain); return; } } } else { /* gets run for all codes */ chain->evhdlr = pmix_globals.events.last; /* reset our count to the info provided by the caller */ chain->ninfo = chain->nallocated - 2; /* if the handler has a name, then provide it */ if (NULL != chain->evhdlr->name) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_HDLR_NAME, chain->evhdlr->name, PMIX_STRING); chain->ninfo++; } /* if there is an evhdlr cbobject, provide it */ if (NULL != chain->evhdlr->cbobject) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_RETURN_OBJECT, chain->evhdlr->cbobject, PMIX_POINTER); chain->ninfo++; } chain->evhdlr->evhdlr(chain->evhdlr->index, chain->status, &chain->source, chain->info, chain->ninfo, chain->results, chain->nresults, progress_local_event_hdlr, (void *) chain); return; } } complete: /* if we get here, there was nothing more to do, but * we still have to call their final callback */ if (NULL != chain->final_cbfunc) { chain->final_cbfunc(chain->interim_status, chain->final_cbdata); return; } /* maintain acctng */ PMIX_RELEASE(chain); } static void progress_local_event_hdlr(pmix_status_t status, pmix_info_t *results, size_t nresults, pmix_op_cbfunc_t cbfunc, void *thiscbdata, void *notification_cbdata) { /* this may be in the host's thread, so we need to threadshift it * before accessing our internal data */ pmix_event_chain_t *chain = (pmix_event_chain_t *) notification_cbdata; chain->interim_status = status; chain->interim = results; chain->ninterim = nresults; chain->opcbfunc = cbfunc; chain->cbdata = thiscbdata; PMIX_THREADSHIFT(chain, cycle_events); } /* given notification of an event, cycle thru our list of * registered callbacks and invoke the matching ones. Note * that we will invoke the callbacks in order from single * to multi-event to default, keeping a log of any returned * info and passing it down to the next invoked event handler. * Thus, each handler is given the opportunity to see what * prior handlers did, and decide if anything further needs * to be done. */ void pmix_invoke_local_event_hdlr(pmix_event_chain_t *chain) { /* We need to parse thru each registered handler and determine * which one(s) to call for the specific error */ size_t i; pmix_event_hdlr_t *evhdlr; pmix_status_t rc = PMIX_SUCCESS; bool found; pmix_group_t *grp, *gp; pmix_proc_t *members = NULL; size_t n, nmembers = 0; char *grpid = NULL; size_t ctxid = SIZE_MAX; pmix_output_verbose(2, pmix_client_globals.event_output, "%s invoke_local_event_hdlr for status %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIx_Error_string(chain->status)); /* sanity check */ if (NULL == chain->info) { /* should never happen as space must always be * reserved for handler name and callback object*/ rc = PMIX_ERR_BAD_PARAM; pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto complete; } /* if we are not a target, then we can simply ignore this event */ if (NULL != chain->targets) { found = false; for (i = 0; i < chain->ntargets; i++) { pmix_output_verbose(8, pmix_client_globals.event_output, "%s CHECKING TARGET %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_NAME_PRINT(&chain->targets[i])); if (PMIX_CHECK_PROCID(&chain->targets[i], &pmix_globals.myid)) { found = true; break; } } if (!found) { pmix_output_verbose(8, pmix_client_globals.event_output, "%s Ignoring event %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto complete; } } pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); /* if this is the "group_complete" event, then we need to add * the group definition to our list of known groups */ if (PMIX_GROUP_CONSTRUCT_COMPLETE == chain->status) { // find the group ID and membership for (n = 0; n < chain->ninfo; n++) { if (PMIX_CHECK_KEY(&chain->info[n], PMIX_GROUP_MEMBERSHIP)) { members = (pmix_proc_t*)chain->info[n].value.data.darray->array; nmembers = chain->info[n].value.data.darray->size; } else if (PMIX_CHECK_KEY(&chain->info[n], PMIX_GROUP_ID)) { grpid = chain->info[n].value.data.string; } else if (PMIX_CHECK_KEY(&chain->info[n], PMIX_GROUP_CONTEXT_ID)) { rc = PMIx_Value_get_number(&chain->info[n].value, &ctxid, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } } if (NULL != members && NULL != grpid) { // see if we already know this group grp = NULL; PMIX_LIST_FOREACH(gp, &pmix_client_globals.groups, pmix_group_t) { if (0 == strcmp(grpid, gp->grpid)) { grp = gp; break; } } if (NULL == grp) { // add the group grp = PMIX_NEW(pmix_group_t); PMIX_PROC_CREATE(grp->members, nmembers); memcpy(grp->members, members, nmembers * sizeof(pmix_proc_t)); qsort(grp->members, nmembers, sizeof(pmix_proc_t), pmix_util_compare_proc); grp->nmbrs = nmembers; grp->grpid = strdup(grpid); grp->ctxid = ctxid; pmix_list_append(&pmix_client_globals.groups, &grp->super); } } } /* if we registered a "first" handler, and it fits the given range, * then invoke it first */ if (NULL != pmix_globals.events.first) { if (1 == pmix_globals.events.first->ncodes && pmix_globals.events.first->codes[0] == chain->status && pmix_notify_check_range(&pmix_globals.events.first->rng, &chain->source) && pmix_notify_check_affected(pmix_globals.events.first->affected, pmix_globals.events.first->naffected, chain->affected, chain->naffected)) { /* invoke the handler */ chain->evhdlr = pmix_globals.events.first; pmix_output_verbose(8, pmix_client_globals.event_output, "%s INVOKING FIRST %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto invk; } else if (NULL != pmix_globals.events.first->codes) { /* need to check if this code is included in the array */ found = false; for (i = 0; i < pmix_globals.events.first->ncodes; i++) { if (pmix_globals.events.first->codes[i] == chain->status) { found = true; break; } } /* if this event handler provided a range, check to see if * the source fits within it */ if (found && pmix_notify_check_range(&pmix_globals.events.first->rng, &chain->source)) { /* invoke the handler */ chain->evhdlr = pmix_globals.events.first; pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto invk; } } else { /* take all codes for a default handler */ if (pmix_notify_check_range(&pmix_globals.events.first->rng, &chain->source)) { /* invoke the handler */ chain->evhdlr = pmix_globals.events.first; pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto invk; } } /* get here if there is no match, so fall thru */ } pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); /* cycle thru the single-event registrations first */ PMIX_LIST_FOREACH (evhdlr, &pmix_globals.events.single_events, pmix_event_hdlr_t) { if (evhdlr->codes[0] == chain->status) { if (pmix_notify_check_range(&evhdlr->rng, &chain->source) && pmix_notify_check_affected(evhdlr->affected, evhdlr->naffected, chain->affected, chain->naffected)) { /* invoke the handler */ chain->evhdlr = evhdlr; pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto invk; } } } /* if we didn't find any match in the single-event registrations, * then cycle thru the multi-event registrations next */ PMIX_LIST_FOREACH (evhdlr, &pmix_globals.events.multi_events, pmix_event_hdlr_t) { for (i = 0; i < evhdlr->ncodes; i++) { if (evhdlr->codes[i] == chain->status) { if (pmix_notify_check_range(&evhdlr->rng, &chain->source) && pmix_notify_check_affected(evhdlr->affected, evhdlr->naffected, chain->affected, chain->naffected)) { /* invoke the handler */ chain->evhdlr = evhdlr; pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto invk; } } } } pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); /* if they didn't want it to go to a default handler, then ignore them */ if (!chain->nondefault) { /* pass it to any default handlers */ PMIX_LIST_FOREACH (evhdlr, &pmix_globals.events.default_events, pmix_event_hdlr_t) { if (pmix_notify_check_range(&evhdlr->rng, &chain->source) && pmix_notify_check_affected(evhdlr->affected, evhdlr->naffected, chain->affected, chain->naffected)) { /* invoke the handler */ chain->evhdlr = evhdlr; pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto invk; } } } /* if we registered a "last" handler, and it fits the given range * and code, then invoke it now */ if (NULL != pmix_globals.events.last && pmix_notify_check_range(&pmix_globals.events.last->rng, &chain->source) && pmix_notify_check_affected(pmix_globals.events.last->affected, pmix_globals.events.last->naffected, chain->affected, chain->naffected)) { chain->endchain = true; // ensure we don't do this again if (1 == pmix_globals.events.last->ncodes && pmix_globals.events.last->codes[0] == chain->status) { chain->evhdlr = pmix_globals.events.last; pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto invk; } else if (NULL != pmix_globals.events.last->codes) { /* need to check if this code is included in the array */ for (i = 0; i < pmix_globals.events.last->ncodes; i++) { if (pmix_globals.events.last->codes[i] == chain->status) { chain->evhdlr = pmix_globals.events.last; pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto invk; } } } else { /* gets run for all codes */ chain->evhdlr = pmix_globals.events.last; pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); goto invk; } } pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); /* if we got here, then nothing was found */ rc = PMIX_ERR_NOT_FOUND; complete: /* we still have to call their final callback */ if (NULL != chain->final_cbfunc) { chain->final_cbfunc(rc, chain->final_cbdata); } else { PMIX_RELEASE(chain); } return; invk: pmix_output_verbose(8, pmix_client_globals.event_output, "%s %s:%d", PMIX_NAME_PRINT(&pmix_globals.myid), __FILE__, __LINE__); /* start with the chain holding only the given info */ chain->ninfo = chain->nallocated - 2; /* if the handler has a name, then provide it */ if (NULL != chain->evhdlr->name) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_HDLR_NAME, chain->evhdlr->name, PMIX_STRING); chain->ninfo++; } /* if there is an evhdlr cbobject, provide it */ if (NULL != chain->evhdlr->cbobject) { PMIX_INFO_LOAD(&chain->info[chain->ninfo], PMIX_EVENT_RETURN_OBJECT, chain->evhdlr->cbobject, PMIX_POINTER); chain->ninfo++; } /* invoke the handler */ pmix_output_verbose(2, pmix_client_globals.event_output, "[%s:%d] INVOKING EVHDLR %s", __FILE__, __LINE__, (NULL == chain->evhdlr->name) ? "NULL" : chain->evhdlr->name); chain->evhdlr->evhdlr(chain->evhdlr->index, chain->status, &chain->source, chain->info, chain->ninfo, NULL, 0, progress_local_event_hdlr, (void *) chain); return; } static void local_cbfunc(pmix_status_t status, void *cbdata) { pmix_notify_caddy_t *cd = (pmix_notify_caddy_t *) cbdata; if (NULL != cd->cbfunc) { cd->cbfunc(status, cd->cbdata); } PMIX_RELEASE(cd); } static void _notify_client_event(int sd, short args, void *cbdata) { (void) sd; (void) args; pmix_notify_caddy_t *cd = (pmix_notify_caddy_t *) cbdata; pmix_regevents_info_t *reginfoptr; pmix_peer_events_info_t *pr; pmix_event_chain_t *chain; size_t n, nleft; bool matched, holdcd; pmix_buffer_t *bfr; pmix_cmd_t cmd = PMIX_NOTIFY_CMD; pmix_status_t rc; pmix_list_t trk; pmix_namelist_t *nm; pmix_namespace_t *nptr, *tmp; pmix_range_trkr_t rngtrk; pmix_proc_t proc; /* need to acquire the object from its originating thread */ PMIX_ACQUIRE_OBJECT(cd); pmix_output_verbose(2, pmix_server_globals.event_output, "pmix_server: _notify_client_event notifying clients of event %s range %s", PMIx_Error_string(cd->status), PMIx_Data_range_string(cd->range)); /* check for caching instructions */ holdcd = true; if (0 < cd->ninfo) { /* check for caching instructions */ for (n = 0; n < cd->ninfo; n++) { if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_DO_NOT_CACHE)) { holdcd = !PMIX_INFO_TRUE(&cd->info[n]); } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_STAYS_LOCAL)) { cd->staylocal = PMIX_INFO_TRUE(&cd->info[n]); } } } if (holdcd) { /* we cannot know if everyone who wants this notice has had a chance * to register for it - the notice may be coming too early. So cache * the message until all local procs have received it, or it ages to * the point where it gets pushed out by more recent events */ PMIX_RETAIN(cd); rc = pmix_notify_event_cache(cd); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } /* we may also have registered for events, so setup to check this * against our registrations */ chain = PMIX_NEW(pmix_event_chain_t); chain->status = cd->status; if (holdcd) { chain->cached = true; } PMIX_LOAD_PROCID(&chain->source, cd->source.nspace, cd->source.rank); /* we always leave space for a callback object and * the evhandler name. */ chain->nallocated = cd->ninfo + 2; PMIX_INFO_CREATE(chain->info, chain->nallocated); /* prep the chain for processing */ pmix_prep_event_chain(chain, cd->info, cd->ninfo, true); cd->nondefault = chain->nondefault; /* if the range is PMIX_RANGE_RM, then we only process this * event ourselves - the PMIx server may aggregate the * events from a namespace prior to passing it to the host */ if (PMIX_RANGE_RM == cd->range) { goto local; } /* if we are a tool, we send it to our clients regardless * of the range - we assume that if we are in range, then * so are any clients attached to us * * if we are a server but not a tool, then check the range * before sending it to our client */ if (PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { /* remove the target designations */ if (NULL != chain->targets) { free(chain->targets); chain->targets = NULL; chain->ntargets = 0; } } /* copy setup to the cd object */ cd->nondefault = chain->nondefault; if (NULL != chain->targets) { cd->ntargets = chain->ntargets; PMIX_PROC_CREATE(cd->targets, cd->ntargets); memcpy(cd->targets, chain->targets, cd->ntargets * sizeof(pmix_proc_t)); /* compute the number of targets that need to be notified */ nleft = 0; for (n = 0; n < cd->ntargets; n++) { /* if this is a single proc, then increment by one */ if (PMIX_RANK_VALID >= cd->targets[n].rank) { ++nleft; } else { /* look up the nspace for this proc */ nptr = NULL; PMIX_LIST_FOREACH (tmp, &pmix_globals.nspaces, pmix_namespace_t) { if (PMIX_CHECK_NSPACE(tmp->nspace, cd->targets[n].nspace)) { nptr = tmp; break; } } /* if we don't yet know it, then nothing to do */ if (NULL == nptr) { nleft = SIZE_MAX; break; } /* might notify all local members */ nleft += nptr->nlocalprocs; } } cd->nleft = nleft; } if (NULL != chain->affected) { cd->naffected = chain->naffected; PMIX_PROC_CREATE(cd->affected, cd->naffected); if (NULL == cd->affected) { cd->naffected = 0; /* notify the caller */ if (NULL != cd->cbfunc) { cd->cbfunc(PMIX_ERR_NOMEM, cd->cbdata); } PMIX_RELEASE(cd); PMIX_RELEASE(chain); return; } memcpy(cd->affected, chain->affected, cd->naffected * sizeof(pmix_proc_t)); } /* if they provided a PMIX_EVENT_CUSTOM_RANGE info object but * specified a range other than PMIX_RANGE_CUSTOM, then this * is an error */ if (PMIX_RANGE_CUSTOM != cd->range && NULL != cd->targets) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); /* notify the caller */ if (NULL != cd->cbfunc) { cd->cbfunc(PMIX_ERR_BAD_PARAM, cd->cbdata); } PMIX_RELEASE(cd); PMIX_RELEASE(chain); return; } holdcd = false; if (PMIX_RANGE_PROC_LOCAL != cd->range) { PMIX_CONSTRUCT(&trk, pmix_list_t); rngtrk.procs = NULL; rngtrk.nprocs = 0; /* cycle across our registered events and send the message to * any client who registered for it */ PMIX_LIST_FOREACH (reginfoptr, &pmix_server_globals.events, pmix_regevents_info_t) { if ((PMIX_MAX_ERR_CONSTANT == reginfoptr->code && !cd->nondefault) || cd->status == reginfoptr->code) { PMIX_LIST_FOREACH (pr, ®infoptr->peers, pmix_peer_events_info_t) { /* if this client was the source of the event, then * don't send it back as they will have processed it * when they generated it */ if (PMIX_CHECK_NAMES(&cd->source, &pr->peer->info->pname)) { continue; } /* don't notify ourselves - we handle this internally */ if (PMIX_CHECK_NAMES(&pmix_globals.myid, &pr->peer->info->pname)) { continue; } /* if we have already notified this client, then don't do it again */ matched = false; PMIX_LIST_FOREACH (nm, &trk, pmix_namelist_t) { if (nm->pname == &pr->peer->info->pname) { matched = true; break; } } if (matched) { continue; } /* check if the affected procs (if given) match those they * wanted to know about */ if (!pmix_notify_check_affected(cd->affected, cd->naffected, pr->affected, pr->naffected)) { continue; } if (!PMIX_PEER_IS_TOOL(pmix_globals.mypeer) && NULL != cd->targets) { rngtrk.procs = cd->targets; rngtrk.nprocs = cd->ntargets; rngtrk.range = cd->range; PMIX_LOAD_PROCID(&proc, pr->peer->info->pname.nspace, pr->peer->info->pname.rank); if (!pmix_notify_check_range(&rngtrk, &proc)) { continue; } } pmix_output_verbose(2, pmix_server_globals.event_output, "pmix_server: notifying client %s:%u on status %s", pr->peer->info->pname.nspace, pr->peer->info->pname.rank, PMIx_Error_string(cd->status)); /* record that we notified this client */ nm = PMIX_NEW(pmix_namelist_t); nm->pname = &pr->peer->info->pname; pmix_list_append(&trk, &nm->super); bfr = PMIX_NEW(pmix_buffer_t); if (NULL == bfr) { continue; } /* pack the command */ PMIX_BFROPS_PACK(rc, pr->peer, bfr, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); continue; } /* pack the status */ PMIX_BFROPS_PACK(rc, pr->peer, bfr, &cd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); continue; } /* pack the source */ PMIX_BFROPS_PACK(rc, pr->peer, bfr, &cd->source, 1, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); continue; } /* pack any info */ PMIX_BFROPS_PACK(rc, pr->peer, bfr, &cd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); continue; } if (0 < cd->ninfo) { PMIX_BFROPS_PACK(rc, pr->peer, bfr, cd->info, cd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); continue; } } /* pack the range in case they need to relay */ PMIX_BFROPS_PACK(rc, pr->peer, bfr, &cd->range, 1, PMIX_DATA_RANGE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); continue; } PMIX_SERVER_QUEUE_REPLY(rc, pr->peer, 0, bfr); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(bfr); } if (NULL != cd->targets && 0 < cd->nleft) { /* track the number of targets we have left to notify */ --cd->nleft; /* if the event was cached and this is the last one, * then evict this event from the cache */ if (0 == cd->nleft) { pmix_hotel_checkout(&pmix_globals.notifications, cd->room); holdcd = false; break; } } } } } PMIX_LIST_DESTRUCT(&trk); if (PMIX_RANGE_LOCAL != cd->range && !cd->staylocal && PMIX_CHECK_PROCID(&cd->source, &pmix_globals.myid)) { /* if we are the source, then we need to post this upwards as * well so the host RM can broadcast it as necessary */ if (NULL != pmix_host_server.notify_event) { /* mark that we sent it upstairs so we don't release * the caddy until we return from the host RM */ rc = pmix_host_server.notify_event(cd->status, &cd->source, cd->range, cd->info, cd->ninfo, local_cbfunc, cd); if (PMIX_SUCCESS == rc) { holdcd = true; } } } } local: /* process it ourselves */ pmix_invoke_local_event_hdlr(chain); if (!holdcd) { /* notify the caller */ if (NULL != cd->cbfunc) { cd->cbfunc(PMIX_SUCCESS, cd->cbdata); } PMIX_RELEASE(cd); } } /* as a server, we must do two things: * * (a) notify all clients that have registered for this event * * (b) callback any of our own functions that have registered * for this event */ pmix_status_t pmix_server_notify_client_of_event(pmix_status_t status, const pmix_proc_t *source, pmix_data_range_t range, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_notify_caddy_t *cd; size_t n; pmix_output_verbose(2, pmix_server_globals.event_output, "pmix_server: notify client of event %s range %s", PMIx_Error_string(status), PMIx_Data_range_string(range)); cd = PMIX_NEW(pmix_notify_caddy_t); cd->status = status; if (NULL == source) { PMIX_LOAD_PROCID(&cd->source, "UNDEF", PMIX_RANK_UNDEF); } else { PMIX_LOAD_PROCID(&cd->source, source->nspace, source->rank); } cd->range = range; /* have to copy the info to preserve it for future when cached */ if (0 < ninfo && NULL != info) { cd->ninfo = ninfo; PMIX_INFO_CREATE(cd->info, cd->ninfo); /* need to copy the info */ for (n = 0; n < cd->ninfo; n++) { PMIX_INFO_XFER(&cd->info[n], &info[n]); } } /* track the eventual callback info */ cd->cbfunc = cbfunc; cd->cbdata = cbdata; pmix_output_verbose(2, pmix_server_globals.event_output, "pmix_server_notify_event status =%d, source = %s:%d, ninfo =%lu", status, cd->source.nspace, cd->source.rank, ninfo); /* we have to push this into our event library to avoid * potential threading issues */ PMIX_THREADSHIFT(cd, _notify_client_event); return PMIX_SUCCESS; } bool pmix_notify_check_range(pmix_range_trkr_t *rng, const pmix_proc_t *proc) { size_t n; if (PMIX_RANGE_UNDEF == rng->range || PMIX_RANGE_GLOBAL == rng->range || PMIX_RANGE_SESSION == rng->range || PMIX_RANGE_LOCAL == rng->range) { // assume RM took care of session & local for now return true; } if (PMIX_RANGE_NAMESPACE == rng->range) { for (n = 0; n < rng->nprocs; n++) { if (PMIX_CHECK_NSPACE(rng->procs[n].nspace, proc->nspace)) { return true; } } return false; } if (PMIX_RANGE_PROC_LOCAL == rng->range) { for (n = 0; n < rng->nprocs; n++) { if (PMIX_CHECK_PROCID(&rng->procs[n], &pmix_globals.myid)) { return true; } } return false; } if (PMIX_RANGE_CUSTOM == rng->range) { /* see if this proc was included */ for (n = 0; n < rng->nprocs; n++) { if (0 != strncmp(rng->procs[n].nspace, proc->nspace, PMIX_MAX_NSLEN)) { continue; } if (PMIX_RANK_WILDCARD == rng->procs[n].rank || rng->procs[n].rank == proc->rank) { return true; } } /* if we get here, then this proc isn't in range */ return false; } /* if it is anything else, then reject it */ return false; } bool pmix_notify_check_affected(pmix_proc_t *interested, size_t ninterested, pmix_proc_t *affected, size_t naffected) { size_t m, n; /* if they didn't restrict their interests, then accept it */ if (NULL == interested) { return true; } /* if we weren't given the affected procs, then accept it */ if (NULL == affected) { return true; } /* check if the two overlap */ for (n = 0; n < naffected; n++) { for (m = 0; m < ninterested; m++) { if (PMIX_CHECK_PROCID(&affected[n], &interested[m])) { return true; } } } /* if we get here, then this proc isn't in range */ return false; } void pmix_event_timeout_cb(int fd, short flags, void *arg) { (void) fd; (void) flags; pmix_event_chain_t *ch = (pmix_event_chain_t *) arg; /* need to acquire the object from its originating thread */ PMIX_ACQUIRE_OBJECT(ch); ch->timer_active = false; /* remove it from the list */ pmix_list_remove_item(&pmix_globals.cached_events, &ch->super); /* process this event thru the regular channels */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { pmix_server_notify_client_of_event(ch->status, &ch->source, ch->range, ch->info, ch->ninfo, ch->final_cbfunc, ch->final_cbdata); } else { pmix_invoke_local_event_hdlr(ch); } } pmix_status_t pmix_prep_event_chain(pmix_event_chain_t *chain, const pmix_info_t *info, size_t ninfo, bool xfer) { size_t n; if (NULL != info && 0 < ninfo) { chain->ninfo = ninfo; if (NULL == chain->info) { PMIX_INFO_CREATE(chain->info, chain->ninfo); } /* need to copy the info */ for (n = 0; n < ninfo; n++) { if (xfer) { /* chain doesn't already have a copy of the info */ PMIX_INFO_XFER(&chain->info[n], &info[n]); } /* look for specific directives */ if (0 == strncmp(info[n].key, PMIX_EVENT_NON_DEFAULT, PMIX_MAX_KEYLEN)) { chain->nondefault = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_EVENT_CUSTOM_RANGE)) { /* provides an array of pmix_proc_t identifying the procs * that are to receive this notification, or a single pmix_proc_t */ if (PMIX_DATA_ARRAY == info[n].value.type && NULL != info[n].value.data.darray && NULL != info[n].value.data.darray->array) { chain->ntargets = info[n].value.data.darray->size; PMIX_PROC_CREATE(chain->targets, chain->ntargets); memcpy(chain->targets, info[n].value.data.darray->array, chain->ntargets * sizeof(pmix_proc_t)); } else if (PMIX_PROC == info[n].value.type) { chain->ntargets = 1; PMIX_PROC_CREATE(chain->targets, chain->ntargets); memcpy(chain->targets, info[n].value.data.proc, sizeof(pmix_proc_t)); } else { /* this is an error */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_EVENT_AFFECTED_PROC)) { PMIX_PROC_CREATE(chain->affected, 1); if (NULL == chain->affected) { return PMIX_ERR_NOMEM; } chain->naffected = 1; memcpy(chain->affected, info[n].value.data.proc, sizeof(pmix_proc_t)); } else if (PMIX_CHECK_KEY(&info[n], PMIX_EVENT_AFFECTED_PROCS)) { chain->naffected = info[n].value.data.darray->size; PMIX_PROC_CREATE(chain->affected, chain->naffected); if (NULL == chain->affected) { chain->naffected = 0; return PMIX_ERR_NOMEM; } memcpy(chain->affected, info[n].value.data.darray->array, chain->naffected * sizeof(pmix_proc_t)); } } } return PMIX_SUCCESS; } /**** CLASS INSTANTIATIONS ****/ static void sevcon(pmix_event_hdlr_t *p) { p->name = NULL; p->index = UINT_MAX; p->precedence = PMIX_EVENT_ORDER_NONE; p->oneshot = false; p->locator = NULL; p->rng.range = PMIX_RANGE_UNDEF; p->rng.procs = NULL; p->rng.nprocs = 0; p->affected = NULL; p->naffected = 0; p->evhdlr = NULL; p->cbobject = NULL; p->codes = NULL; p->ncodes = 0; } static void sevdes(pmix_event_hdlr_t *p) { if (NULL != p->name) { free(p->name); } if (NULL != p->locator) { free(p->locator); } if (NULL != p->rng.procs) { free(p->rng.procs); } if (NULL != p->affected) { PMIX_PROC_FREE(p->affected, p->naffected); } if (NULL != p->codes) { free(p->codes); } } PMIX_CLASS_INSTANCE(pmix_event_hdlr_t, pmix_list_item_t, sevcon, sevdes); static void accon(pmix_active_code_t *p) { p->nregs = 0; p->peer = NULL; } PMIX_CLASS_INSTANCE(pmix_active_code_t, pmix_list_item_t, accon, NULL); static void evcon(pmix_events_t *p) { p->nhdlrs = 0; p->first = NULL; p->last = NULL; PMIX_CONSTRUCT(&p->actives, pmix_list_t); PMIX_CONSTRUCT(&p->single_events, pmix_list_t); PMIX_CONSTRUCT(&p->multi_events, pmix_list_t); PMIX_CONSTRUCT(&p->default_events, pmix_list_t); } static void evdes(pmix_events_t *p) { if (NULL != p->first) { PMIX_RELEASE(p->first); } if (NULL != p->last) { PMIX_RELEASE(p->last); } PMIX_LIST_DESTRUCT(&p->actives); PMIX_LIST_DESTRUCT(&p->single_events); PMIX_LIST_DESTRUCT(&p->multi_events); PMIX_LIST_DESTRUCT(&p->default_events); } PMIX_CLASS_INSTANCE(pmix_events_t, pmix_object_t, evcon, evdes); static void chcon(pmix_event_chain_t *p) { p->timer_active = false; memset(p->source.nspace, 0, PMIX_MAX_NSLEN + 1); p->source.rank = PMIX_RANK_UNDEF; p->nondefault = false; p->endchain = false; p->cached = false; p->targets = NULL; p->ntargets = 0; p->range = PMIX_RANGE_UNDEF; p->affected = NULL; p->naffected = 0; p->info = NULL; p->ninfo = 0; p->nallocated = 0; p->interim_status = PMIX_ERROR; p->results = NULL; p->nresults = 0; p->interim = NULL; p->ninterim = 0; p->evhdlr = NULL; p->opcbfunc = NULL; p->cbdata = NULL; p->final_cbfunc = NULL; p->final_cbdata = NULL; } static void chdes(pmix_event_chain_t *p) { if (p->timer_active) { pmix_event_del(&p->ev); } if (NULL != p->targets) { PMIX_PROC_FREE(p->targets, p->ntargets); } if (NULL != p->affected) { PMIX_PROC_FREE(p->affected, p->naffected); } if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->nallocated); } if (NULL != p->results) { PMIX_INFO_FREE(p->results, p->nresults); } } PMIX_CLASS_INSTANCE(pmix_event_chain_t, pmix_list_item_t, chcon, chdes); pmix-6.1.1~rc2/src/event/Makefile.include0000664000175000017500000000043315203536752020467 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2016 Intel, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ headers += \ event/pmix_event.h sources += \ event/pmix_event_notification.c \ event/pmix_event_registration.c pmix-6.1.1~rc2/src/event/pmix_event_registration.c0000664000175000017500000013067715203536752022537 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2017-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/client/pmix_client_ops.h" #include "src/event/pmix_event.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/bfrops.h" #include "src/server/pmix_server_ops.h" static void rscon(pmix_rshift_caddy_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); p->firstoverall = false; p->enviro = false; p->list = NULL; p->hdlr = NULL; p->cd = NULL; p->codes = NULL; p->ncodes = 0; p->info = NULL; p->ninfo = 0; p->affected = NULL; p->naffected = 0; p->evhdlr = NULL; p->evregcbfn = NULL; p->cbdata = NULL; } static void rsdes(pmix_rshift_caddy_t *p) { PMIX_DESTRUCT_LOCK(&p->lock); if (0 < p->ncodes) { free(p->codes); } if (NULL != p->cd) { PMIX_RELEASE(p->cd); } } PMIX_CLASS_INSTANCE(pmix_rshift_caddy_t, pmix_object_t, rscon, rsdes); static void check_cached_events(pmix_rshift_caddy_t *cd); /* catch the event registration response message from the * server and process it */ static void regevents_cbfunc(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_rshift_caddy_t *rb = (pmix_rshift_caddy_t *) cbdata; pmix_rshift_caddy_t *cd = (pmix_rshift_caddy_t *) rb->cd; pmix_status_t rc, ret; int cnt; size_t index = rb->index; pmix_output_verbose(2, pmix_client_globals.event_output, "pmix: regevents callback recvd"); PMIX_HIDE_UNUSED_PARAMS(hdr); /* unpack the status code */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ret, &cnt, PMIX_STATUS); if ((PMIX_SUCCESS != rc) || (PMIX_SUCCESS != ret)) { /* remove the err handler and call the error handler * reg completion callback fn so the requestor * doesn't hang */ if (NULL == rb->list) { if (NULL != rb->hdlr) { PMIX_RELEASE(rb->hdlr); } if (rb->firstoverall) { pmix_globals.events.first = NULL; } else { pmix_globals.events.last = NULL; } } else if (NULL != rb->hdlr) { pmix_list_remove_item(rb->list, &rb->hdlr->super); PMIX_RELEASE(rb->hdlr); } ret = PMIX_ERR_SERVER_FAILED_REQUEST; index = UINT_MAX; } /* call the callback */ if (NULL != cd) { /* check this event against anything in our cache */ check_cached_events(cd); if (NULL != cd->evregcbfn) { cd->evregcbfn(ret, index, cd->cbdata); } } /* release any info we brought along as they are * internally generated and not provided by the caller */ if (NULL != rb->info) { PMIX_INFO_FREE(rb->info, rb->ninfo); } if (NULL != rb->codes) { free(rb->codes); } PMIX_RELEASE(rb); } static void _regcbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_rshift_caddy_t *rb = (pmix_rshift_caddy_t *) scd->cbdata; pmix_rshift_caddy_t *cd = (pmix_rshift_caddy_t *) rb->cd; pmix_status_t rc = scd->status; size_t index = rb->index; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (PMIX_SUCCESS != scd->status) { /* if we failed to register, then remove this event */ if (NULL == rb->list) { if (NULL != rb->hdlr) { PMIX_RELEASE(rb->hdlr); } if (rb->firstoverall) { pmix_globals.events.first = NULL; } else { pmix_globals.events.last = NULL; } } else if (NULL != rb->hdlr) { pmix_list_remove_item(rb->list, &rb->hdlr->super); PMIX_RELEASE(rb->hdlr); } rc = PMIX_ERR_SERVER_FAILED_REQUEST; index = UINT_MAX; } if (NULL != cd && NULL != cd->evregcbfn) { /* pass back our local index */ cd->evregcbfn(rc, index, cd->cbdata); } /* release any info we brought along as they are * internally generated and not provided by the caller */ if (NULL != rb->info) { PMIX_INFO_FREE(rb->info, rb->ninfo); } if (NULL != rb->codes) { free(rb->codes); } // cd is released by the rb destructor PMIX_RELEASE(rb); PMIX_RELEASE(scd); } static void reg_cbfunc(pmix_status_t status, void *cbdata) { pmix_shift_caddy_t *scd; scd = PMIX_NEW(pmix_shift_caddy_t); scd->status = status; scd->cbdata = cbdata; PMIX_THREADSHIFT(scd, _regcbfunc); } static pmix_status_t _send_to_server(pmix_rshift_caddy_t *rcd) { pmix_rshift_caddy_t *cd = (pmix_rshift_caddy_t *) rcd->cd; pmix_status_t rc; pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_REGEVENTS_CMD; msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack the number of codes */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cd->ncodes, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack any provided codes */ if (0 < cd->ncodes) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cd->codes, cd->ncodes, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } /* pack the number of info */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &rcd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack any provided info */ if (0 < rcd->ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, rcd->info, rcd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, regevents_cbfunc, rcd); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); } return rc; } static pmix_status_t _add_hdlr(pmix_rshift_caddy_t *cd, pmix_list_t *xfer) { pmix_rshift_caddy_t *cd2; pmix_info_caddy_t *ixfer; size_t n; bool registered, need_register = false; pmix_active_code_t *active; pmix_status_t rc; pmix_output_verbose(2, pmix_client_globals.event_output, "pmix: _add_hdlr"); /* check to see if we have an active registration on these codes */ if (NULL == cd->codes) { registered = false; PMIX_LIST_FOREACH (active, &pmix_globals.events.actives, pmix_active_code_t) { if (PMIX_MAX_ERR_CONSTANT == active->code && (NULL != active->peer && active->peer == pmix_client_globals.myserver)) { /* we have registered a default */ registered = true; ++active->nregs; break; } } if (!registered) { active = PMIX_NEW(pmix_active_code_t); active->code = PMIX_MAX_ERR_CONSTANT; active->nregs = 1; active->peer = pmix_client_globals.myserver; pmix_list_append(&pmix_globals.events.actives, &active->super); /* ensure we register it */ need_register = true; } } else { for (n = 0; n < cd->ncodes; n++) { registered = false; PMIX_LIST_FOREACH (active, &pmix_globals.events.actives, pmix_active_code_t) { if (active->code == cd->codes[n] && (NULL != active->peer && active->peer == pmix_client_globals.myserver)) { registered = true; ++active->nregs; break; } } if (!registered) { active = PMIX_NEW(pmix_active_code_t); active->code = cd->codes[n]; active->nregs = 1; active->peer = pmix_client_globals.myserver; pmix_list_append(&pmix_globals.events.actives, &active->super); /* ensure we register it */ need_register = true; } } } /* prep next step */ cd2 = PMIX_NEW(pmix_rshift_caddy_t); cd2->index = cd->index; cd2->firstoverall = cd->firstoverall; cd2->list = cd->list; cd2->hdlr = cd->hdlr; PMIX_RETAIN(cd); cd2->cd = cd; cd2->ninfo = pmix_list_get_size(xfer); if (0 < cd2->ninfo) { PMIX_INFO_CREATE(cd2->info, cd2->ninfo); n = 0; PMIX_LIST_FOREACH (ixfer, xfer, pmix_info_caddy_t) { PMIX_INFO_XFER(&cd2->info[n], ixfer->info); ++n; } } /* if we are a client, and we haven't already registered a handler of this * type with our server, or if we have directives, then we need to notify * the server - however, don't do this for a v1 server as the event * notification system there doesn't work */ if ((!PMIX_PEER_IS_SERVER(pmix_globals.mypeer) || PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) || PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) && pmix_atomic_check_bool(&pmix_globals.connected) && !PMIX_PEER_IS_V1(pmix_client_globals.myserver) && (need_register || 0 < pmix_list_get_size(xfer))) { pmix_output_verbose(2, pmix_client_globals.event_output, "pmix: _add_hdlr sending to server"); /* send the directives to the server - we will ack this * registration upon return from there */ if (PMIX_SUCCESS != (rc = _send_to_server(cd2))) { pmix_output_verbose(2, pmix_client_globals.event_output, "pmix: add_hdlr - pack send_to_server failed status=%d", rc); if (NULL != cd2->info) { PMIX_INFO_FREE(cd2->info, cd2->ninfo); } PMIX_RELEASE(cd2); return rc; } return PMIX_ERR_WOULD_BLOCK; } /* if we are a server and are registering for events, then we only contact * our host if we want environmental events */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) && cd->enviro && NULL != pmix_host_server.register_events) { pmix_output_verbose(2, pmix_client_globals.event_output, "pmix: _add_hdlr registering with server"); rc = pmix_host_server.register_events(cd->codes, cd->ncodes, cd2->info, cd2->ninfo, reg_cbfunc, cd2); if (PMIX_SUCCESS != rc && PMIX_OPERATION_SUCCEEDED != rc) { if (NULL != cd2->info) { PMIX_INFO_FREE(cd2->info, cd2->ninfo); } PMIX_RELEASE(cd2); return rc; } return PMIX_SUCCESS; } else { if (NULL != cd2->info) { PMIX_INFO_FREE(cd2->info, cd2->ninfo); } PMIX_RELEASE(cd2); } return PMIX_SUCCESS; } static void check_cached_events(pmix_rshift_caddy_t *cd) { size_t n; pmix_notify_caddy_t *ncd; bool found, matched; pmix_event_chain_t *chain; int j; for (j = 0; j < pmix_globals.max_events; j++) { pmix_hotel_knock(&pmix_globals.notifications, j, (void **) &ncd); if (NULL == ncd) { continue; } found = false; if (NULL == cd->codes) { if (!ncd->nondefault) { /* they registered a default event handler - always matches */ found = true; } } else { for (n = 0; n < cd->ncodes; n++) { if (cd->codes[n] == ncd->status) { found = true; break; } } } if (!found) { continue; } /* if we were given specific targets, check if we are one */ if (NULL != ncd->targets) { matched = false; for (n = 0; n < ncd->ntargets; n++) { if (PMIX_CHECK_PROCID(&pmix_globals.myid, &ncd->targets[n])) { matched = true; break; } } if (!matched) { /* do not notify this one */ continue; } } /* if they specified affected proc(s) they wanted to know about, check */ if (!pmix_notify_check_affected(cd->affected, cd->naffected, ncd->affected, ncd->naffected)) { continue; } /* create the chain */ chain = PMIX_NEW(pmix_event_chain_t); chain->status = ncd->status; pmix_strncpy(chain->source.nspace, pmix_globals.myid.nspace, PMIX_MAX_NSLEN); chain->source.rank = pmix_globals.myid.rank; /* we always leave space for event hdlr name and a callback object */ chain->nallocated = ncd->ninfo + 2; PMIX_INFO_CREATE(chain->info, chain->nallocated); if (0 < ncd->ninfo) { chain->ninfo = ncd->ninfo; /* need to copy the info */ for (n = 0; n < ncd->ninfo; n++) { PMIX_INFO_XFER(&chain->info[n], &ncd->info[n]); if (PMIX_CHECK_KEY(&ncd->info[n], PMIX_EVENT_NON_DEFAULT)) { chain->nondefault = true; } else if (PMIX_CHECK_KEY(&ncd->info[n], PMIX_EVENT_AFFECTED_PROC)) { PMIX_PROC_CREATE(chain->affected, 1); if (NULL == chain->affected) { PMIX_RELEASE(chain); return; } chain->naffected = 1; memcpy(chain->affected, ncd->info[n].value.data.proc, sizeof(pmix_proc_t)); } else if (PMIX_CHECK_KEY(&ncd->info[n], PMIX_EVENT_AFFECTED_PROCS)) { chain->naffected = ncd->info[n].value.data.darray->size; PMIX_PROC_CREATE(chain->affected, chain->naffected); if (NULL == chain->affected) { chain->naffected = 0; PMIX_RELEASE(chain); return; } memcpy(chain->affected, ncd->info[n].value.data.darray->array, chain->naffected * sizeof(pmix_proc_t)); } } } /* check this event out of the cache since we * are processing it */ pmix_hotel_checkout(&pmix_globals.notifications, ncd->room); /* release the storage */ PMIX_RELEASE(ncd); /* we don't want this chain to propagate, so indicate it * should only be run as a single-shot */ chain->endchain = true; /* now notify any matching registered callbacks we have */ pmix_invoke_local_event_hdlr(chain); } } void pmix_internal_reg_event_hdlr(int sd, short args, void *cbdata) { pmix_rshift_caddy_t *cd = (pmix_rshift_caddy_t *) cbdata; size_t index = 0, n; pmix_status_t rc; pmix_event_hdlr_t *evhdlr, *ev; uint8_t location = PMIX_EVENT_ORDER_NONE; char *name = NULL, *locator = NULL; bool firstoverall = false, lastoverall = false; bool found; bool oneshot = false; pmix_list_t xfer; pmix_info_caddy_t *ixfer; void *cbobject = NULL; pmix_data_range_t range = PMIX_RANGE_UNDEF; pmix_proc_t *parray = NULL; size_t nprocs = 0; /* need to acquire the object from its originating thread */ PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(2, pmix_client_globals.event_output, "[%s]: register event_hdlr with %d infos", PMIX_NAME_PRINT(&pmix_globals.myid), (int) cd->ninfo); PMIX_CONSTRUCT(&xfer, pmix_list_t); /* if directives were included */ if (NULL != cd->info) { for (n = 0; n < cd->ninfo; n++) { if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_HDLR_FIRST)) { /* flag if they asked to put this one first overall */ firstoverall = PMIX_INFO_TRUE(&cd->info[n]); location = PMIX_EVENT_ORDER_FIRST_OVERALL; } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_HDLR_LAST)) { /* flag if they asked to put this one last overall */ lastoverall = PMIX_INFO_TRUE(&cd->info[n]); location = PMIX_EVENT_ORDER_LAST_OVERALL; } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_HDLR_PREPEND)) { /* flag if they asked to prepend this handler */ if (PMIX_INFO_TRUE(&cd->info[n])) { location = PMIX_EVENT_ORDER_PREPEND; } } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_HDLR_APPEND)) { /* flag if they asked to append this handler */ if (PMIX_INFO_TRUE(&cd->info[n])) { location = PMIX_EVENT_ORDER_APPEND; } } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_HDLR_NAME)) { name = cd->info[n].value.data.string; } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_RETURN_OBJECT)) { cbobject = cd->info[n].value.data.ptr; } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_HDLR_FIRST_IN_CATEGORY)) { if (PMIX_INFO_TRUE(&cd->info[n])) { location = PMIX_EVENT_ORDER_FIRST; } } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_HDLR_LAST_IN_CATEGORY)) { if (PMIX_INFO_TRUE(&cd->info[n])) { location = PMIX_EVENT_ORDER_LAST; } } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_HDLR_BEFORE)) { location = PMIX_EVENT_ORDER_BEFORE; locator = cd->info[n].value.data.string; } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_HDLR_AFTER)) { location = PMIX_EVENT_ORDER_AFTER; locator = cd->info[n].value.data.string; } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_RANGE)) { range = cd->info[n].value.data.range; } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_CUSTOM_RANGE)) { /* provides an array of pmix_proc_t identifying the procs * that are to receive this notification, or a single pmix_proc_t */ if (PMIX_DATA_ARRAY == cd->info[n].value.type && NULL != cd->info[n].value.data.darray && NULL != cd->info[n].value.data.darray->array) { parray = (pmix_proc_t *) cd->info[n].value.data.darray->array; nprocs = cd->info[n].value.data.darray->size; } else if (PMIX_PROC == cd->info[n].value.type && NULL != cd->info[n].value.data.proc) { parray = cd->info[n].value.data.proc; nprocs = 1; } else { /* this is an error */ rc = PMIX_ERR_BAD_PARAM; goto ack; } } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_AFFECTED_PROC)) { cd->affected = cd->info[n].value.data.proc; cd->naffected = 1; ixfer = PMIX_NEW(pmix_info_caddy_t); ixfer->info = &cd->info[n]; ixfer->ninfo = 1; pmix_list_append(&xfer, &ixfer->super); } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_AFFECTED_PROCS)) { cd->affected = (pmix_proc_t *) cd->info[n].value.data.darray->array; cd->naffected = cd->info[n].value.data.darray->size; ixfer = PMIX_NEW(pmix_info_caddy_t); ixfer->info = &cd->info[n]; ixfer->ninfo = 1; pmix_list_append(&xfer, &ixfer->super); } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_EVENT_ONESHOT)) { oneshot = PMIX_INFO_TRUE(&cd->info[n]); } else { ixfer = PMIX_NEW(pmix_info_caddy_t); ixfer->info = &cd->info[n]; ixfer->ninfo = 1; pmix_list_append(&xfer, &ixfer->super); } } } /* check the codes for system events */ for (n = 0; n < cd->ncodes; n++) { if (PMIX_SYSTEM_EVENT(cd->codes[n])) { cd->enviro = true; break; } } /* if they indicated this is to be the "first" or "last" event, then * first check to ensure they didn't already direct some * other event into the same cherished position */ if (firstoverall || lastoverall) { if ((firstoverall && NULL != pmix_globals.events.first) || (lastoverall && NULL != pmix_globals.events.last)) { /* oops - someone already took that position */ index = UINT_MAX; rc = PMIX_ERR_EVENT_REGISTRATION; goto ack; } evhdlr = PMIX_NEW(pmix_event_hdlr_t); if (NULL == evhdlr) { index = UINT_MAX; rc = PMIX_ERR_EVENT_REGISTRATION; goto ack; } if (NULL != name) { evhdlr->name = strdup(name); } evhdlr->oneshot = oneshot; evhdlr->precedence = location; index = pmix_globals.events.nhdlrs; evhdlr->index = index; ++pmix_globals.events.nhdlrs; evhdlr->rng.range = range; if (NULL != parray && 0 < nprocs) { evhdlr->rng.nprocs = nprocs; PMIX_PROC_CREATE(evhdlr->rng.procs, nprocs); if (NULL == evhdlr->rng.procs) { index = UINT_MAX; rc = PMIX_ERR_EVENT_REGISTRATION; PMIX_RELEASE(evhdlr); goto ack; } memcpy(evhdlr->rng.procs, parray, nprocs * sizeof(pmix_proc_t)); } if (NULL != cd->affected && 0 < cd->naffected) { evhdlr->naffected = cd->naffected; PMIX_PROC_CREATE(evhdlr->affected, cd->naffected); if (NULL == evhdlr->affected) { index = UINT_MAX; rc = PMIX_ERR_EVENT_REGISTRATION; PMIX_RELEASE(evhdlr); goto ack; } memcpy(evhdlr->affected, cd->affected, cd->naffected * sizeof(pmix_proc_t)); } evhdlr->evhdlr = cd->evhdlr; evhdlr->cbobject = cbobject; if (NULL != cd->codes) { evhdlr->codes = (pmix_status_t *) malloc(cd->ncodes * sizeof(pmix_status_t)); if (NULL == evhdlr->codes) { PMIX_RELEASE(evhdlr); index = UINT_MAX; rc = PMIX_ERR_EVENT_REGISTRATION; goto ack; } memcpy(evhdlr->codes, cd->codes, cd->ncodes * sizeof(pmix_status_t)); evhdlr->ncodes = cd->ncodes; } if (firstoverall) { pmix_globals.events.first = evhdlr; } else { pmix_globals.events.last = evhdlr; } cd->index = index; cd->list = NULL; cd->hdlr = evhdlr; cd->firstoverall = firstoverall; goto tellserver; } /* get here if this isn't an overall first or last event - start * by creating an event */ evhdlr = PMIX_NEW(pmix_event_hdlr_t); if (NULL == evhdlr) { index = UINT_MAX; rc = PMIX_ERR_EVENT_REGISTRATION; goto ack; } if (NULL != name) { evhdlr->name = strdup(name); } index = pmix_globals.events.nhdlrs; evhdlr->index = index; ++pmix_globals.events.nhdlrs; evhdlr->oneshot = oneshot; evhdlr->precedence = location; if (NULL != locator) { evhdlr->locator = strdup(locator); } evhdlr->rng.range = range; if (NULL != parray && 0 < nprocs) { evhdlr->rng.nprocs = nprocs; PMIX_PROC_CREATE(evhdlr->rng.procs, nprocs); if (NULL == evhdlr->rng.procs) { index = UINT_MAX; rc = PMIX_ERR_EVENT_REGISTRATION; PMIX_RELEASE(evhdlr); goto ack; } memcpy(evhdlr->rng.procs, parray, nprocs * sizeof(pmix_proc_t)); } if (NULL != cd->affected && 0 < cd->naffected) { evhdlr->naffected = cd->naffected; PMIX_PROC_CREATE(evhdlr->affected, cd->naffected); if (NULL == evhdlr->affected) { index = UINT_MAX; rc = PMIX_ERR_EVENT_REGISTRATION; PMIX_RELEASE(evhdlr); goto ack; } memcpy(evhdlr->affected, cd->affected, cd->naffected * sizeof(pmix_proc_t)); } evhdlr->evhdlr = cd->evhdlr; evhdlr->cbobject = cbobject; if (NULL == cd->codes) { /* this is a default handler */ cd->list = &pmix_globals.events.default_events; } else { evhdlr->codes = (pmix_status_t *) malloc(cd->ncodes * sizeof(pmix_status_t)); if (NULL == evhdlr->codes) { PMIX_RELEASE(evhdlr); index = UINT_MAX; rc = PMIX_ERR_EVENT_REGISTRATION; goto ack; } memcpy(evhdlr->codes, cd->codes, cd->ncodes * sizeof(pmix_status_t)); evhdlr->ncodes = cd->ncodes; if (1 == cd->ncodes) { cd->list = &pmix_globals.events.single_events; } else { cd->list = &pmix_globals.events.multi_events; } } /* setup to add the handler */ cd->index = index; cd->hdlr = evhdlr; cd->firstoverall = false; if (NULL != cd->list) { /* now add this event to the appropriate list - if the registration * subsequently fails, it will be removed */ /* if the list is empty, or no location was specified, just put this on it */ if (0 == pmix_list_get_size(cd->list) || PMIX_EVENT_ORDER_NONE == location) { pmix_list_prepend(cd->list, &evhdlr->super); } else if (PMIX_EVENT_ORDER_FIRST == location) { /* see if the first handler on the list was also declared as "first" */ ev = (pmix_event_hdlr_t *) pmix_list_get_first(cd->list); if (PMIX_EVENT_ORDER_FIRST == ev->precedence) { /* this is an error */ --pmix_globals.events.nhdlrs; rc = PMIX_ERR_EVENT_REGISTRATION; index = UINT_MAX; PMIX_RELEASE(evhdlr); goto ack; } /* prepend it to the list */ pmix_list_prepend(cd->list, &evhdlr->super); } else if (PMIX_EVENT_ORDER_LAST == location) { /* see if the last handler on the list was also declared as "last" */ ev = (pmix_event_hdlr_t *) pmix_list_get_last(cd->list); if (PMIX_EVENT_ORDER_LAST == ev->precedence) { /* this is an error */ --pmix_globals.events.nhdlrs; rc = PMIX_ERR_EVENT_REGISTRATION; index = UINT_MAX; PMIX_RELEASE(evhdlr); goto ack; } /* append it to the list */ pmix_list_append(cd->list, &evhdlr->super); } else if (PMIX_EVENT_ORDER_PREPEND == location) { /* we know the list isn't empty - check the first element to see if * it is designated to be "first". If so, then we need to put this * right after it */ ev = (pmix_event_hdlr_t *) pmix_list_get_first(cd->list); if (PMIX_EVENT_ORDER_FIRST == ev->precedence) { ev = (pmix_event_hdlr_t *) pmix_list_get_next(&ev->super); if (NULL != ev) { pmix_list_insert_pos(cd->list, &ev->super, &evhdlr->super); } else { /* we are at the end of the list */ pmix_list_append(cd->list, &evhdlr->super); } } else { pmix_list_prepend(cd->list, &evhdlr->super); } } else if (PMIX_EVENT_ORDER_APPEND == location) { /* we know the list isn't empty - check the last element to see if * it is designated to be "last". If so, then we need to put this * right before it */ ev = (pmix_event_hdlr_t *) pmix_list_get_last(cd->list); if (PMIX_EVENT_ORDER_LAST == ev->precedence) { pmix_list_insert_pos(cd->list, &ev->super, &evhdlr->super); } else { pmix_list_append(cd->list, &evhdlr->super); } } else if (NULL != locator) { /* find the named event */ found = false; PMIX_LIST_FOREACH (ev, cd->list, pmix_event_hdlr_t) { if (NULL == ev->name) { continue; } if (0 == strcmp(ev->name, name)) { if (PMIX_EVENT_ORDER_BEFORE == location) { /* put it before this handler */ pmix_list_insert_pos(cd->list, &ev->super, &evhdlr->super); } else { /* put it after this handler */ ev = (pmix_event_hdlr_t *) pmix_list_get_next(&ev->super); if (NULL != ev) { pmix_list_insert_pos(cd->list, &ev->super, &evhdlr->super); } else { /* we are at the end of the list */ pmix_list_append(cd->list, &evhdlr->super); } } found = true; break; } } /* if the handler wasn't found, then it is still possible that the * named handler is either FIRST_OVERALL or LAST_OVERALL. Check * those two possibilities */ if (!found) { if (NULL != pmix_globals.events.first && 0 == strcmp(pmix_globals.events.first->name, locator)) { /* if they asked to go AFTER this event, then we can oblige */ if (PMIX_EVENT_ORDER_AFTER == location) { /* put this first on the list */ pmix_list_prepend(cd->list, &evhdlr->super); found = true; } /* only other options would be BEFORE, and that isn't allowed */ } else if (NULL != pmix_globals.events.last && 0 == strcmp(pmix_globals.events.last->name, locator)) { /* if they asked to go BEFORE this event, then we can oblige */ if (PMIX_EVENT_ORDER_BEFORE == location) { /* put this at the end of the list */ pmix_list_append(cd->list, &evhdlr->super); found = true; } /* only other options would be AFTER, and that isn't allowed */ } } /* if the handler wasn't found, then we return an error. At some * future time, we may change this behavior and cache this handler * until the reference one has been registered. However, this could * turn out to be a laborious search procedure as the reference * event handler may in turn be dependent on another handler, etc. */ if (!found) { /* this is an error */ --pmix_globals.events.nhdlrs; rc = PMIX_ERR_EVENT_REGISTRATION; index = UINT_MAX; PMIX_RELEASE(evhdlr); goto ack; } } } tellserver: /* tell the server about it, if necessary - any actions * will be deferred until after this event completes */ if (PMIX_RANGE_PROC_LOCAL == range) { rc = PMIX_SUCCESS; } else { rc = _add_hdlr(cd, &xfer); } PMIX_LIST_DESTRUCT(&xfer); if (PMIX_SUCCESS != rc && PMIX_ERR_WOULD_BLOCK != rc) { /* unable to register */ --pmix_globals.events.nhdlrs; rc = PMIX_ERR_EVENT_REGISTRATION; index = UINT_MAX; if (firstoverall) { pmix_globals.events.first = NULL; } else if (lastoverall) { pmix_globals.events.last = NULL; } else if (NULL != cd->list) { pmix_list_remove_item(cd->list, &evhdlr->super); } PMIX_RELEASE(evhdlr); } if (PMIX_ERR_WOULD_BLOCK == rc) { /* the callback will provide our response */ PMIX_RELEASE(cd); return; } ack: /* check if any matching notifications have been locally cached */ check_cached_events(cd); if (NULL != cd->codes) { free(cd->codes); cd->codes = NULL; } /* acknowledge the registration so the caller can release * their data AND record the event handler index */ if (NULL != cd->evregcbfn) { cd->evregcbfn(rc, index, cd->cbdata); PMIX_RELEASE(cd); } } static void mycbfn(pmix_status_t status, size_t refid, void *cbdata) { pmix_rshift_caddy_t *cd = (pmix_rshift_caddy_t *) cbdata; PMIX_ACQUIRE_OBJECT(cd); if (PMIX_SUCCESS == status) { cd->status = refid; } else { cd->status = status; } PMIX_WAKEUP_THREAD(&cd->lock); } PMIX_EXPORT pmix_status_t PMIx_Register_event_handler(pmix_status_t codes[], size_t ncodes, pmix_info_t info[], size_t ninfo, pmix_notification_fn_t event_hdlr, pmix_hdlr_reg_cbfunc_t cbfunc, void *cbdata) { pmix_rshift_caddy_t *cd; pmix_status_t rc = PMIX_SUCCESS; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* need to thread shift this request so we can access * our global data to register this *local* event handler */ cd = PMIX_NEW(pmix_rshift_caddy_t); /* we have to save the codes as we will check them against existing * registrations AFTER we have executed the callback which allows * the caller to release their storage */ if (0 < ncodes) { cd->codes = (pmix_status_t *) malloc(ncodes * sizeof(pmix_status_t)); if (NULL == cd->codes) { /* immediately return error */ PMIX_RELEASE(cd); return PMIX_ERR_NOMEM; } memcpy(cd->codes, codes, ncodes * sizeof(pmix_status_t)); } cd->ncodes = ncodes; cd->info = info; cd->ninfo = ninfo; cd->evhdlr = event_hdlr; if (NULL != cbfunc) { pmix_output_verbose(2, pmix_client_globals.event_output, "pmix_register_event_hdlr shifting to progress thread"); cd->evregcbfn = cbfunc; cd->cbdata = cbdata; PMIX_THREADSHIFT(cd, pmix_internal_reg_event_hdlr); } else { cd->evregcbfn = mycbfn; cd->cbdata = cd; PMIX_RETAIN(cd); // so reg_event_hdlr doesn't wind up releasing it PMIX_THREADSHIFT(cd, pmix_internal_reg_event_hdlr); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; PMIX_RELEASE(cd); } return rc; } pmix_status_t pmix_deregister_event_hdlr(size_t event_hdlr_ref, pmix_buffer_t *msg) { pmix_status_t rc; pmix_event_hdlr_t *evhdlr, *ev; size_t n; pmix_active_code_t *active; pmix_status_t wildcard = PMIX_MAX_ERR_CONSTANT; /* check the first and last locations */ if ((NULL != pmix_globals.events.first && pmix_globals.events.first->index == event_hdlr_ref) || (NULL != pmix_globals.events.last && pmix_globals.events.last->index == event_hdlr_ref)) { /* found it */ if (NULL != pmix_globals.events.first && pmix_globals.events.first->index == event_hdlr_ref) { ev = pmix_globals.events.first; } else { ev = pmix_globals.events.last; } /* if this is a default handler, see if any other default * handlers remain */ if (NULL == ev->codes) { if (NULL != msg) { if (0 == pmix_list_get_size(&pmix_globals.events.default_events)) { /* tell the server to dereg our default handler */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &wildcard, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { return rc; } } } } else { for (n = 0; n < ev->ncodes; n++) { /* see if this is the last registration we have for this code */ PMIX_LIST_FOREACH (active, &pmix_globals.events.actives, pmix_active_code_t) { if (active->code == ev->codes[n]) { --active->nregs; if (0 == active->nregs) { pmix_list_remove_item(&pmix_globals.events.actives, &active->super); if (NULL != msg) { /* tell the server to dereg this code */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &active->code, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(active); return rc; } } PMIX_RELEASE(active); } break; } } } } if (ev == pmix_globals.events.first) { pmix_globals.events.first = NULL; } else { pmix_globals.events.last = NULL; } PMIX_RELEASE(ev); return PMIX_SUCCESS; } /* the registration can be in any of three places, so check each of them */ PMIX_LIST_FOREACH (evhdlr, &pmix_globals.events.default_events, pmix_event_hdlr_t) { if (evhdlr->index == event_hdlr_ref) { /* found it */ pmix_list_remove_item(&pmix_globals.events.default_events, &evhdlr->super); if (NULL != msg) { /* if there are no more default handlers registered, tell * the server to dereg the default handler */ if (0 == pmix_list_get_size(&pmix_globals.events.default_events)) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &wildcard, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { return rc; } } } PMIX_RELEASE(evhdlr); return PMIX_SUCCESS; } } PMIX_LIST_FOREACH (evhdlr, &pmix_globals.events.single_events, pmix_event_hdlr_t) { if (evhdlr->index == event_hdlr_ref) { /* found it */ pmix_list_remove_item(&pmix_globals.events.single_events, &evhdlr->super); /* see if this is the last registration we have for this code */ PMIX_LIST_FOREACH (active, &pmix_globals.events.actives, pmix_active_code_t) { if (active->code == evhdlr->codes[0]) { --active->nregs; if (0 == active->nregs) { pmix_list_remove_item(&pmix_globals.events.actives, &active->super); if (NULL != msg) { /* tell the server to dereg this code */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &active->code, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(active); return rc; } } PMIX_RELEASE(active); } break; } } PMIX_RELEASE(evhdlr); return PMIX_SUCCESS; } } PMIX_LIST_FOREACH (evhdlr, &pmix_globals.events.multi_events, pmix_event_hdlr_t) { if (evhdlr->index == event_hdlr_ref) { /* found it */ pmix_list_remove_item(&pmix_globals.events.multi_events, &evhdlr->super); for (n = 0; n < evhdlr->ncodes; n++) { /* see if this is the last registration we have for this code */ PMIX_LIST_FOREACH (active, &pmix_globals.events.actives, pmix_active_code_t) { if (active->code == evhdlr->codes[n]) { --active->nregs; if (0 == active->nregs) { pmix_list_remove_item(&pmix_globals.events.actives, &active->super); if (NULL != msg) { /* tell the server to dereg this code */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &active->code, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(active); return rc; } } PMIX_RELEASE(active); } break; } } } PMIX_RELEASE(evhdlr); return PMIX_SUCCESS; } } return PMIX_SUCCESS; } static void dereg_event_hdlr(int sd, short args, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; pmix_buffer_t *msg = NULL; pmix_cmd_t cmd = PMIX_DEREGEVENTS_CMD; pmix_status_t rc = PMIX_SUCCESS; /* need to acquire the object from its originating thread */ PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); /* if I am not the server, and I am connected, then I need * to notify the server to remove my registration */ if ((!PMIX_PEER_IS_SERVER(pmix_globals.mypeer) || PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) && pmix_atomic_check_bool(&pmix_globals.connected)) { msg = PMIX_NEW(pmix_buffer_t); PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); goto cleanup; } } pmix_deregister_event_hdlr(cd->ref, msg); if (NULL != msg) { /* threadshift to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, NULL, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); } } cleanup: /* must release the caller */ if (NULL != cd->cbfunc.opcbfn) { cd->cbfunc.opcbfn(rc, cd->cbdata); } PMIX_RELEASE(cd); } static void myopcb(pmix_status_t status, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; PMIX_ACQUIRE_OBJECT(cd); cd->status = status; PMIX_WAKEUP_THREAD(&cd->lock); } PMIX_EXPORT pmix_status_t PMIx_Deregister_event_handler(size_t event_hdlr_ref, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_shift_caddy_t *cd; pmix_status_t rc = PMIX_SUCCESS; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* need to thread shift this request */ cd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == cbfunc) { cd->cbfunc.opcbfn = myopcb; PMIX_RETAIN(cd); cd->cbdata = cd; } else { cd->cbfunc.opcbfn = cbfunc; cd->cbdata = cbdata; } cd->ref = event_hdlr_ref; pmix_output_verbose(2, pmix_client_globals.event_output, "pmix_deregister_event_hdlr shifting to progress thread"); PMIX_THREADSHIFT(cd, dereg_event_hdlr); if (NULL == cbfunc) { PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; PMIX_RELEASE(cd); } return rc; } pmix-6.1.1~rc2/src/event/pmix_event.h0000664000175000017500000003726515203536752017751 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_EVENT_H #define PMIX_EVENT_H #include "src/include/pmix_config.h" #include "src/include/pmix_types.h" #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/mca/bfrops/bfrops_types.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_output.h" BEGIN_C_DECLS #define PMIX_EVENT_ORDER_NONE 0x00 #define PMIX_EVENT_ORDER_FIRST 0x01 #define PMIX_EVENT_ORDER_LAST 0x02 #define PMIX_EVENT_ORDER_BEFORE 0x04 #define PMIX_EVENT_ORDER_AFTER 0x08 #define PMIX_EVENT_ORDER_PREPEND 0x10 #define PMIX_EVENT_ORDER_APPEND 0x20 #define PMIX_EVENT_ORDER_FIRST_OVERALL 0x40 #define PMIX_EVENT_ORDER_LAST_OVERALL 0x80 /* define an internal attribute for marking that the * server processed an event before passing it up * to its host in case it comes back down - avoids * infinite loop */ #define PMIX_SERVER_INTERNAL_NOTIFY "pmix.srvr.internal.notify" /* define a struct for tracking registration ranges */ typedef struct { pmix_data_range_t range; pmix_proc_t *procs; size_t nprocs; } pmix_range_trkr_t; #define PMIX_RANGE_TRKR_STATIC_INIT \ { \ .range = PMIX_RANGE_UNDEF, \ .procs = NULL, \ .nprocs = 0 \ } /* define a common struct for tracking event handlers */ typedef struct { pmix_list_item_t super; char *name; size_t index; uint8_t precedence; bool oneshot; char *locator; pmix_proc_t source; // who generated this event /* When registering for events, callers can specify * the range of sources from which they are willing * to receive notifications - e.g., for callers to * define different handlers for events coming from * the RM vs those coming from their peers. We use * the rng field to track these values upon registration. */ pmix_range_trkr_t rng; /* For registration, we use the affected field to track * the range of procs that, if affected by the event, * should cause the handler to be called (subject, of * course, to any rng constraints). */ pmix_proc_t *affected; size_t naffected; pmix_notification_fn_t evhdlr; void *cbobject; pmix_status_t *codes; size_t ncodes; } pmix_event_hdlr_t; PMIX_CLASS_DECLARATION(pmix_event_hdlr_t); #define PMIX_EVENT_HDLR_STATIC_INIT \ { \ .super = PMIX_LIST_ITEM_STATIC_INIT, \ .name = NULL, \ .index = SIZE_MAX, \ .precedence = UINT8_MAX, \ .locator = NULL, \ .source = PMIX_PROC_STATIC_INIT, \ .rng = PMIX_RANGE_TRKR_STATIC_INIT, \ .affected - NULL, \ .naffected = 0, \ .evhdlr = NULL, \ .cbobject = NULL, \ .codes = NULL, \ .ncodes = 0 \ } /* define an object for tracking status codes we are actively * registered to receive */ typedef struct { pmix_list_item_t super; pmix_status_t code; size_t nregs; void *peer; // (pmix_peer_t *) } pmix_active_code_t; PMIX_CLASS_DECLARATION(pmix_active_code_t); /* define an object for housing the different lists of events * we have registered so we can easily scan them in precedent * order when we get an event */ typedef struct { pmix_object_t super; size_t nhdlrs; pmix_event_hdlr_t *first; pmix_event_hdlr_t *last; pmix_list_t actives; pmix_list_t single_events; pmix_list_t multi_events; pmix_list_t default_events; } pmix_events_t; PMIX_CLASS_DECLARATION(pmix_events_t); #define PMIX_EVENTS_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \ .nhdlrs = 0, \ .first = NULL, \ .last = NULL, \ .actives = PMIX_LIST_STATIC_INIT, \ .single_events = PMIX_LIST_STATIC_INIT, \ .multi_events = PMIX_LIST_STATIC_INIT, \ .default_events = PMIX_LIST_STATIC_INIT \ } /* define an object for chaining event notifications thru * the local state machine. Each registered event handler * that asked to be notified for a given code is given a * chance to "see" the reported event, starting with * single-code handlers, then multi-code handlers, and * finally default handlers. This object provides a * means for us to relay the event across that chain */ typedef struct pmix_event_chain_t { pmix_list_item_t super; pmix_status_t status; pmix_event_t ev; bool timer_active; bool nondefault; bool endchain; bool cached; pmix_proc_t source; pmix_data_range_t range; /* When generating events, callers can specify * the range of targets to receive notifications. */ pmix_proc_t *targets; size_t ntargets; /* the processes that we affected by the event */ pmix_proc_t *affected; size_t naffected; /* any info provided by the event generator */ pmix_info_t *info; size_t ninfo; size_t nallocated; pmix_status_t interim_status; pmix_info_t *results; size_t nresults; pmix_info_t *interim; size_t ninterim; pmix_event_hdlr_t *evhdlr; pmix_op_cbfunc_t opcbfunc; void *cbdata; pmix_op_cbfunc_t final_cbfunc; void *final_cbdata; } pmix_event_chain_t; PMIX_CLASS_DECLARATION(pmix_event_chain_t); typedef struct { pmix_object_t super; volatile bool active; pmix_event_t ev; pmix_lock_t lock; pmix_status_t status; size_t index; bool firstoverall; bool enviro; pmix_list_t *list; pmix_event_hdlr_t *hdlr; void *cd; pmix_status_t *codes; size_t ncodes; pmix_info_t *info; size_t ninfo; pmix_proc_t *affected; size_t naffected; pmix_notification_fn_t evhdlr; pmix_hdlr_reg_cbfunc_t evregcbfn; void *cbdata; } pmix_rshift_caddy_t; PMIX_CLASS_DECLARATION(pmix_rshift_caddy_t); /* prepare a chain for processing by cycling across provided * info structs and translating those supported by the event * system into the chain object*/ PMIX_EXPORT pmix_status_t pmix_prep_event_chain(pmix_event_chain_t *chain, const pmix_info_t *info, size_t ninfo, bool xfer); /* invoke the error handler that is registered against the given * status, passing it the provided info on the procs that were * affected, plus any additional info provided by the server */ PMIX_EXPORT void pmix_invoke_local_event_hdlr(pmix_event_chain_t *chain); PMIX_EXPORT bool pmix_notify_check_range(pmix_range_trkr_t *rng, const pmix_proc_t *proc); PMIX_EXPORT bool pmix_notify_check_affected(pmix_proc_t *interested, size_t ninterested, pmix_proc_t *affected, size_t naffected); PMIX_EXPORT pmix_status_t pmix_deregister_event_hdlr(size_t event_hdlr_ref, pmix_buffer_t *msg); /* invoke the server event notification handler */ PMIX_EXPORT pmix_status_t pmix_server_notify_client_of_event(pmix_status_t status, const pmix_proc_t *source, pmix_data_range_t range, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_notify_server_of_event(pmix_status_t status, const pmix_proc_t *source, pmix_data_range_t range, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata, bool dolocal); PMIX_EXPORT void pmix_event_timeout_cb(int sd, short args, void *cbdata); PMIX_EXPORT void pmix_internal_notify_event(int sd, short args, void *cbdata); PMIX_EXPORT void pmix_internal_reg_event_hdlr(int sd, short args, void *cbdata); #define PMIX_REPORT_EVENT(e, p, r, f) \ do { \ pmix_event_chain_t *ch, *cp; \ size_t _n; \ \ ch = NULL; \ /* see if we already have this event cached */ \ PMIX_LIST_FOREACH (cp, &pmix_globals.cached_events, pmix_event_chain_t) { \ if (cp->status == (e)) { \ ch = cp; \ break; \ } \ } \ if (NULL == ch) { \ /* nope - need to add it */ \ ch = PMIX_NEW(pmix_event_chain_t); \ ch->status = (e); \ ch->range = (r); \ PMIX_LOAD_PROCID(&ch->source, (p)->nptr->nspace, (p)->info->pname.rank); \ PMIX_PROC_CREATE(ch->affected, 1); \ ch->naffected = 1; \ PMIX_LOAD_PROCID(ch->affected, (p)->nptr->nspace, (p)->info->pname.rank); \ /* if this is lost-connection-to-server, then we let it go to */ \ /* the default event handler - otherwise, we don't */ \ if (PMIX_ERR_LOST_CONNECTION != (e) && PMIX_ERR_UNREACH != (e)) { \ ch->ninfo = 1; \ ch->nallocated = 3; \ PMIX_INFO_CREATE(ch->info, ch->nallocated); \ /* mark for non-default handlers only */ \ PMIX_INFO_LOAD(&ch->info[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); \ } else { \ ch->nallocated = 2; \ PMIX_INFO_CREATE(ch->info, ch->nallocated); \ } \ ch->final_cbfunc = (f); \ ch->final_cbdata = ch; \ /* cache it */ \ pmix_list_append(&pmix_globals.cached_events, &ch->super); \ ch->timer_active = true; \ pmix_event_assign(&ch->ev, pmix_globals.evbase, -1, 0, pmix_event_timeout_cb, ch); \ PMIX_POST_OBJECT(ch); \ pmix_event_add(&ch->ev, &pmix_globals.event_window); \ } else { \ /* add this peer to the array of sources */ \ pmix_proc_t proc_tmp; \ pmix_info_t *info_tmp; \ size_t ninfo_tmp; \ pmix_strncpy(proc_tmp.nspace, (p)->nptr->nspace, PMIX_MAX_NSLEN); \ proc_tmp.rank = (p)->info->pname.rank; \ ninfo_tmp = ch->nallocated + 1; \ PMIX_INFO_CREATE(info_tmp, ninfo_tmp); \ /* must keep the hdlr name and return object at the end, so prepend */ \ PMIX_INFO_LOAD(&info_tmp[0], PMIX_PROCID, &proc_tmp, PMIX_PROC); \ for (_n = 0; _n < ch->ninfo; _n++) { \ PMIX_INFO_XFER(&info_tmp[_n + 1], &ch->info[_n]); \ } \ PMIX_INFO_FREE(ch->info, ch->nallocated); \ ch->nallocated = ninfo_tmp; \ ch->info = info_tmp; \ ch->ninfo = ninfo_tmp - 2; \ /* reset the timer */ \ if (ch->timer_active) { \ pmix_event_del(&ch->ev); \ } \ PMIX_POST_OBJECT(ch); \ ch->timer_active = true; \ pmix_event_add(&ch->ev, &pmix_globals.event_window); \ } \ } while (0) END_C_DECLS #endif /* PMIX_EVENT_H */ pmix-6.1.1~rc2/src/tool/0000775000175000017500000000000015203536752015241 5ustar alastairalastairpmix-6.1.1~rc2/src/tool/pmix_tool_ops.h0000664000175000017500000000131315203536752020303 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ */ #ifndef PMIX_TOOL_OPS_H #define PMIX_TOOL_OPS_H #include "src/include/pmix_config.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" PMIX_EXPORT pmix_status_t pmix_tool_relay_op(pmix_cmd_t cmd, pmix_peer_t *peer, pmix_buffer_t *bfr, uint32_t tag); PMIX_EXPORT void pmix_tool_retry_set(int sd, short args, void *cbdata); PMIX_EXPORT void pmix_tool_retry_attach(int sd, short args, void *cbdata); #endif // PMIX_TOOL_OPS_H pmix-6.1.1~rc2/src/tool/pmix_tool_ops.c0000664000175000017500000001042415203536752020301 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/ptl/ptl.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "pmix_tool_ops.h" static void tool_switchyard(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); /* the following function is used by the PMIx server * switchyard to process commands sent to one tool by * another tool. Tool processes cannot have PMIx clients * as they are tools and NOT servers. Thus, the only * case we must handle is that where one tool has * connected to another tool as its primary server * (for example, a debugger fork/exec'ing a launcher). * In this case, the tool must relay the request to * a server that can process it since it will itself * lack the ability to do so. * * For example, a "spawn" command must be relayed to * the local system server so it can be executed as * the tool itself has no mechanism by which it can * do so * * Input params: * cmd - the command we received * * peer - the tool that sent us the request * * bfr - the buffer containing the request */ pmix_status_t pmix_tool_relay_op(pmix_cmd_t cmd, pmix_peer_t *peer, pmix_buffer_t *bfr, uint32_t tag) { pmix_shift_caddy_t *s; pmix_status_t rc; pmix_buffer_t *relay; pmix_cmd_t relaycmds[] = {PMIX_SPAWNNB_CMD}; bool found = false; size_t nrelaycmds, n; /***** IF IT IS THE SPAWN COMMAND, WE SEND IT WITH A SEPARATE CBFUNC SO WE CAN INTERCEPT THE RESPONSE *****/ /* there are some commands we just cannot relay as * it makes no sense to do so */ nrelaycmds = sizeof(relaycmds) / sizeof(pmix_cmd_t); for (n = 0; n < nrelaycmds; n++) { if (cmd == relaycmds[n]) { found = true; break; } } if (!found) { return PMIX_ERR_NOT_SUPPORTED; } if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } s = PMIX_NEW(pmix_shift_caddy_t); PMIX_RETAIN(peer); s->peer = peer; s->ncodes = tag; /* reset the buffer's pointers so the entire * message is resent */ bfr->unpack_ptr = bfr->base_ptr; relay = PMIX_NEW(pmix_buffer_t); PMIX_BFROPS_COPY_PAYLOAD(rc, peer, relay, bfr); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(relay); PMIX_RELEASE(s); return rc; } PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, relay, tool_switchyard, (void *) s); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(relay); PMIX_RELEASE(s); return rc; } return PMIX_SUCCESS; } static void tool_switchyard(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_shift_caddy_t *s = (pmix_shift_caddy_t *) cbdata; pmix_buffer_t *relay; pmix_status_t rc; uint32_t tag = (uint32_t) s->ncodes; PMIX_HIDE_UNUSED_PARAMS(pr, hdr); /* the tag for the original sender was stored in ncodes, and * the server would have packed the buffer using my * bfrops plugin */ relay = PMIX_NEW(pmix_buffer_t); PMIX_BFROPS_COPY_PAYLOAD(rc, pmix_globals.mypeer, relay, buf); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(relay); return; } PMIX_SERVER_QUEUE_REPLY(rc, s->peer, tag, relay); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(relay); } PMIX_RELEASE(s); } pmix-6.1.1~rc2/src/tool/pmix_tool.c0000664000175000017500000022125015203536752017421 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2021 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "include/pmix_server.h" #include "include/pmix_tool.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_DIRENT_H # include #endif /* HAVE_DIRENT_H */ #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/common/pmix_attributes.h" #include "src/common/pmix_iof.h" #include "src/common/pmix_pfexec.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/mca/pmdl/base/base.h" #include "src/mca/pnet/base/base.h" #include "src/mca/psec/psec.h" #include "src/mca/ptl/base/base.h" #include "src/runtime/pmix_progress_threads.h" #include "src/runtime/pmix_rte.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "src/tool/pmix_tool_ops.h" #define PMIX_MAX_RETRIES 10 static pmix_event_t stdinsig, parentdied; static pmix_iof_read_event_t stdinev; static pmix_proc_t myparent; static void _pdiedcb(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t*)cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_RELEASE(cb); } static void pdiedfn(int fd, short flags, void *arg) { pmix_proc_t keepalive; pmix_cb_t *cb; PMIX_HIDE_UNUSED_PARAMS(fd, flags, arg); PMIX_LOAD_PROCID(&keepalive, "PMIX_KEEPALIVE_PIPE", PMIX_RANK_UNDEF); /* generate a job-terminated event */ cb = PMIX_NEW(pmix_cb_t); cb->ninfo = 2; PMIX_INFO_CREATE(cb->info, cb->ninfo); PMIX_INFO_LOAD(&cb->info[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&cb->info[1], PMIX_EVENT_AFFECTED_PROC, &keepalive, PMIX_PROC); cb->infocopy = true; // ensure cleanup PMIx_Notify_event(PMIX_ERR_JOB_TERMINATED, &pmix_globals.myid, PMIX_RANGE_PROC_LOCAL, cb->info, cb->ninfo, _pdiedcb, (void*)cb); } static void _notify_complete(pmix_status_t status, void *cbdata) { pmix_event_chain_t *chain = (pmix_event_chain_t *) cbdata; pmix_notify_caddy_t *cd; size_t n; pmix_status_t rc; PMIX_ACQUIRE_OBJECT(chain); /* if the event wasn't found, then cache it as it might * be registered later */ if (PMIX_ERR_NOT_FOUND == status && !chain->cached) { cd = PMIX_NEW(pmix_notify_caddy_t); cd->status = chain->status; PMIX_LOAD_PROCID(&cd->source, chain->source.nspace, chain->source.rank); cd->range = chain->range; if (0 < chain->ninfo) { cd->ninfo = chain->ninfo; PMIX_INFO_CREATE(cd->info, cd->ninfo); cd->nondefault = chain->nondefault; /* need to copy the info */ for (n = 0; n < cd->ninfo; n++) { PMIX_INFO_XFER(&cd->info[n], &chain->info[n]); } } if (NULL != chain->targets) { cd->ntargets = chain->ntargets; PMIX_PROC_CREATE(cd->targets, cd->ntargets); memcpy(cd->targets, chain->targets, cd->ntargets * sizeof(pmix_proc_t)); } if (NULL != chain->affected) { cd->naffected = chain->naffected; PMIX_PROC_CREATE(cd->affected, cd->naffected); if (NULL == cd->affected) { cd->naffected = 0; goto cleanup; } memcpy(cd->affected, chain->affected, cd->naffected * sizeof(pmix_proc_t)); } /* cache it */ rc = pmix_notify_event_cache(cd); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd); goto cleanup; } chain->cached = true; } cleanup: PMIX_RELEASE(chain); } static void pmix_tool_notify_recv(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_status_t rc; int32_t cnt; pmix_cmd_t cmd; pmix_event_chain_t *chain; size_t ninfo; pmix_data_range_t range; PMIX_HIDE_UNUSED_PARAMS(peer, hdr, cbdata); pmix_output_verbose(2, pmix_client_globals.event_output, "pmix:tool_notify_recv - processing event"); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { return; } /* start the local notification chain */ chain = PMIX_NEW(pmix_event_chain_t); chain->final_cbfunc = _notify_complete; chain->final_cbdata = chain; cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &cmd, &cnt, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &chain->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } /* unpack the source of the event */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &chain->source, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } /* unpack the info that might have been provided */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } /* we always leave space for event hdlr name and a callback object */ chain->nallocated = ninfo + 2; PMIX_INFO_CREATE(chain->info, chain->nallocated); if (NULL == chain->info) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); PMIX_RELEASE(chain); return; } if (0 < ninfo) { chain->ninfo = ninfo; cnt = ninfo; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, chain->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } } /* unpack the range, if provided */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &range, &cnt, PMIX_DATA_RANGE); if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { range = PMIX_RANGE_LOCAL; } if (PMIX_RANGE_LOCAL != range && pmix_atomic_check_bool(&pmix_globals.connected) && !(PMIX_CHECK_NSPACE(peer->nptr->nspace, pmix_client_globals.myserver->nptr->nspace) && peer->info->pname.rank == pmix_client_globals.myserver->info->pname.rank)) { pmix_output_verbose(2, pmix_client_globals.event_output, "[%s:%d] pmix:tool_notify_recv - relaying to server", pmix_globals.myid.nspace, pmix_globals.myid.rank); rc = pmix_notify_server_of_event(chain->status, &chain->source, range, chain->info, chain->ninfo, NULL, NULL, false); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } } pmix_output_verbose(2, pmix_client_globals.event_output, "[%s:%d] pmix:tool_notify_recv - processing event %s from source %s:%d, calling errhandler", pmix_globals.myid.nspace, pmix_globals.myid.rank, PMIx_Error_string(chain->status), chain->source.nspace, chain->source.rank); rc = pmix_server_notify_client_of_event(chain->status, &chain->source, range, chain->info, chain->ninfo, _notify_complete, chain); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } return; error: /* we always need to return */ pmix_output_verbose(2, pmix_client_globals.event_output, "pmix:tool_notify_recv - unpack error status =%d, calling def errhandler", rc); chain = PMIX_NEW(pmix_event_chain_t); chain->status = rc; pmix_invoke_local_event_hdlr(chain); } static void tool_iof_handler(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_peer_t *peer = (pmix_peer_t *) pr; pmix_proc_t source; pmix_iof_channel_t channel; pmix_byte_object_t bo; int32_t cnt; pmix_status_t rc; size_t refid, ninfo = 0; pmix_iof_req_t *req; pmix_info_t *info = NULL; PMIX_HIDE_UNUSED_PARAMS(hdr, cbdata); pmix_output_verbose(2, pmix_client_globals.iof_output, "recvd IOF with %d bytes", (int) buf->bytes_used); /* if the buffer is empty, they are simply closing the socket */ if (0 == buf->bytes_used) { return; } PMIX_BYTE_OBJECT_CONSTRUCT(&bo); cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &source, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &channel, &cnt, PMIX_IOF_CHANNEL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &refid, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } if (0 < ninfo) { PMIX_INFO_CREATE(info, ninfo); cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &bo, &cnt, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* lookup the handler for this IOF package */ req = (pmix_iof_req_t *) pmix_pointer_array_get_item(&pmix_globals.iof_requests, refid); if (NULL != req && NULL != req->cbfunc) { req->cbfunc(refid, channel, &source, &bo, info, ninfo); } else { /* otherwise, simply write it out to the specified std IO channel */ if (NULL != bo.bytes && 0 < bo.size) { pmix_iof_write_output(&source, channel, &bo); } } cleanup: /* cleanup the memory */ if (0 < ninfo) { PMIX_INFO_FREE(info, ninfo); } PMIX_BYTE_OBJECT_DESTRUCT(&bo); } /* callback to receive job info */ static void job_data(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_status_t rc; char *nspace; int32_t cnt = 1; pmix_cb_t *cb = (pmix_cb_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(pr, hdr); /* unpack the nspace - should be same as our own */ PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &nspace, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); cb->status = PMIX_ERROR; PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); return; } /* decode it */ PMIX_GDS_STORE_JOB_INFO(cb->status, pmix_client_globals.myserver, nspace, buf); cb->status = PMIX_SUCCESS; PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } /* event handler registration callback */ static void evhandler_reg_callbk(pmix_status_t status, size_t evhandler_ref, void *cbdata) { pmix_lock_t *lock = (pmix_lock_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(evhandler_ref); lock->status = status; PMIX_WAKEUP_THREAD(lock); } static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { pmix_lock_t *lock = NULL; char *name = NULL; size_t n; PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, results, nresults); pmix_output_verbose(2, pmix_client_globals.base_output, "[%s:%d] DEBUGGER RELEASE RECVD", pmix_globals.myid.nspace, pmix_globals.myid.rank); if (NULL != info) { lock = NULL; for (n = 0; n < ninfo; n++) { if (0 == strncmp(info[n].key, PMIX_EVENT_RETURN_OBJECT, PMIX_MAX_KEYLEN)) { lock = (pmix_lock_t *) info[n].value.data.ptr; } else if (0 == strncmp(info[n].key, PMIX_EVENT_HDLR_NAME, PMIX_MAX_KEYLEN)) { name = info[n].value.data.string; } } /* if the object wasn't returned, then that is an error */ if (NULL == lock) { pmix_output_verbose(2, pmix_client_globals.base_output, "event handler %s failed to return object", (NULL == name) ? "NULL" : name); /* let the event handler progress */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } return; } } if (NULL != lock) { PMIX_WAKEUP_THREAD(lock); } if (NULL != cbfunc) { cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } static int tool_init_cntr = 0; PMIX_EXPORT int PMIx_tool_init(pmix_proc_t *proc, pmix_info_t info[], size_t ninfo) { pmix_status_t rc; char *evar, *nspace = NULL, *suri; pmix_rank_t rank = PMIX_RANK_UNDEF; bool do_not_connect = false; bool nspace_given = false; bool nspace_in_enviro = false; bool rank_given = false; bool fwd_stdin = false; bool connect_optional = false; pmix_info_t ginfo, *iptr, evinfo[3]; size_t n; pmix_ptl_posted_recv_t *rcv; pmix_proc_t wildcard, myserver; int fd; pmix_proc_type_t ptype = PMIX_PROC_TYPE_STATIC_INIT; pmix_cb_t cb, *cbptr; pmix_buffer_t *req; pmix_cmd_t cmd; pmix_iof_req_t *iofreq; pmix_lock_t reglock, releaselock; bool outputio = true; pmix_kval_t *kptr; pmix_rshift_caddy_t *cd; // check if an init has been called if (pmix_atomic_test_and_set(&pmix_globals.init_called)) { // track the ref count pmix_atomic_fetch_add(&tool_init_cntr, 1); // did the prior call get far enough? We might be in a tight // race between multiple calls to PMIx_tool_init - bad programming // technique, but all we can do is try to protect against it if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } // return our proc name if they requested it if (NULL != proc) { PMIX_LOAD_PROCID(proc, pmix_globals.myid.nspace, pmix_globals.myid.rank); } return PMIX_SUCCESS; } else { // require a location to return the proc name if (NULL == proc) { return PMIX_ERR_BAD_PARAM; } pmix_atomic_fetch_add(&tool_init_cntr, 1); } /* init the parent procid to something innocuous */ PMIX_LOAD_PROCID(&myparent, NULL, PMIX_RANK_UNDEF); /* backward compatibility fix - remove any directive to use * the old usock component so we avoid a warning message */ if (NULL != (evar = getenv("PMIX_MCA_ptl"))) { if (0 == strcmp(evar, "usock")) { /* we cannot support a usock-only environment */ fprintf(stderr, "-------------------------------------------------------------------\n"); fprintf(stderr, "PMIx no longer supports the \"usock\" transport for client-server\n"); fprintf(stderr, "communication. A directive was detected that only allows that mode.\n"); fprintf(stderr, "We cannot continue - please remove that constraint and try again.\n"); fprintf(stderr, "-------------------------------------------------------------------\n"); return PMIX_ERR_INIT; } /* anything else should just be cleared */ pmix_unsetenv("PMIX_MCA_ptl", &environ); } /* parse the input directives */ PMIX_SET_PROC_TYPE(&ptype, PMIX_PROC_TOOL); if (NULL != info) { for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_TOOL_DO_NOT_CONNECT)) { do_not_connect = PMIX_INFO_TRUE(&info[n]); } else if (0 == strncmp(info[n].key, PMIX_TOOL_NSPACE, PMIX_MAX_KEYLEN)) { if (NULL != nspace) { /* cannot define it twice */ free(nspace); return PMIX_ERR_BAD_PARAM; } nspace = strdup(info[n].value.data.string); nspace_given = true; } else if (PMIX_CHECK_KEY(&info[n], PMIX_TOOL_RANK)) { rank = info[n].value.data.rank; rank_given = true; } else if (PMIX_CHECK_KEY(&info[n], PMIX_FWD_STDIN)) { /* they want us to forward our stdin to someone */ fwd_stdin = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_LAUNCHER)) { if (PMIX_INFO_TRUE(&info[n])) { PMIX_SET_PROC_TYPE(&ptype, PMIX_PROC_LAUNCHER); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_SCHEDULER)) { if (PMIX_INFO_TRUE(&info[n])) { PMIX_SET_PROC_TYPE(&ptype, PMIX_PROC_SCHEDULER); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_TMPDIR)) { if (NULL != pmix_server_globals.tmpdir) { free(pmix_server_globals.tmpdir); } pmix_server_globals.tmpdir = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SYSTEM_TMPDIR)) { if (NULL != pmix_server_globals.system_tmpdir) { free(pmix_server_globals.system_tmpdir); } pmix_server_globals.system_tmpdir = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_TOOL_CONNECT_OPTIONAL)) { connect_optional = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_IOF_LOCAL_OUTPUT)) { outputio = PMIX_INFO_TRUE(&info[n]); } } } if (NULL == pmix_server_globals.tmpdir) { if (NULL == (evar = getenv("PMIX_SERVER_TMPDIR"))) { pmix_server_globals.tmpdir = strdup(pmix_tmp_directory()); } else { pmix_server_globals.tmpdir = strdup(evar); } } if (NULL == pmix_server_globals.system_tmpdir) { if (NULL == (evar = getenv("PMIX_SYSTEM_TMPDIR"))) { pmix_server_globals.system_tmpdir = strdup(pmix_tmp_directory()); } else { pmix_server_globals.system_tmpdir = strdup(evar); } } if ((nspace_given && !rank_given) || (!nspace_given && rank_given)) { /* can't have one and not the other */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); if (NULL != nspace) { free(nspace); } return PMIX_ERR_BAD_PARAM; } /* if we were not passed an nspace in the info keys, * check to see if we were given one in the env - this * will be the case when we are launched by a PMIx-enabled * daemon */ if (!nspace_given) { if (NULL != (evar = getenv("PMIX_NAMESPACE"))) { nspace = strdup(evar); nspace_in_enviro = true; } } /* also look for the rank - it normally is zero, but if we * were launched, then it might have been as part of a * multi-process tool */ if (!rank_given) { if (NULL != (evar = getenv("PMIX_RANK"))) { rank = strtol(evar, NULL, 10); if (!nspace_in_enviro) { /* this is an error - we can't have one and not * the other */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* flag that this tool is also a client */ if (PMIX_PROC_IS_LAUNCHER(&ptype)) { PMIX_SET_PROC_TYPE(&ptype, PMIX_PROC_CLIENT_LAUNCHER); } else { PMIX_SET_PROC_TYPE(&ptype, PMIX_PROC_CLIENT_TOOL); } } else if (nspace_in_enviro) { /* this is an error - we can't have one and not * the other */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); if (NULL != nspace) { free(nspace); } return PMIX_ERR_BAD_PARAM; } } /* setup the runtime - this init's the globals, * opens and initializes the required frameworks */ if (PMIX_SUCCESS != (rc = pmix_rte_init(ptype.type, info, ninfo, pmix_tool_notify_recv))) { PMIX_ERROR_LOG(rc); if (NULL != nspace) { free(nspace); } return rc; } /* if we were given a keepalive pipe, register an * event to capture the event */ if (NULL != (evar = getenv("PMIX_KEEPALIVE_PIPE"))) { rc = strtol(evar, NULL, 10); pmix_event_set(pmix_globals.evbase, &parentdied, rc, PMIX_EV_READ, pdiedfn, NULL); pmix_event_add(&parentdied, NULL); pmix_unsetenv("PMIX_KEEPALIVE_PIPE", &environ); pmix_fd_set_cloexec(rc); // don't let children inherit this } /* if we were given a name, then set it now */ if (nspace_given || nspace_in_enviro) { PMIX_LOAD_PROCID(&pmix_globals.myid, nspace, rank); free(nspace); nspace = NULL; } /* setup the IO Forwarding recv */ rcv = PMIX_NEW(pmix_ptl_posted_recv_t); rcv->tag = PMIX_PTL_TAG_IOF; rcv->cbfunc = tool_iof_handler; /* add it to the end of the list of recvs */ pmix_list_append(&pmix_ptl_base.posted_recvs, &rcv->super); /* default tools to outputting their IOF */ pmix_globals.iof_flags.local_output = outputio; /* setup the globals */ PMIX_CONSTRUCT(&pmix_client_globals.groups, pmix_list_t); PMIX_CONSTRUCT(&pmix_client_globals.pending_requests, pmix_list_t); PMIX_CONSTRUCT(&pmix_client_globals.peers, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_client_globals.peers, 1, INT_MAX, 1); pmix_client_globals.myserver = PMIX_NEW(pmix_peer_t); if (NULL == pmix_client_globals.myserver) { return PMIX_ERR_NOMEM; } pmix_client_globals.myserver->nptr = PMIX_NEW(pmix_namespace_t); if (NULL == pmix_client_globals.myserver->nptr) { PMIX_RELEASE(pmix_client_globals.myserver); return PMIX_ERR_NOMEM; } pmix_client_globals.myserver->info = PMIX_NEW(pmix_rank_info_t); if (NULL == pmix_client_globals.myserver->info) { PMIX_RELEASE(pmix_client_globals.myserver); return PMIX_ERR_NOMEM; } pmix_output_verbose(2, pmix_globals.debug_output, "pmix: init called"); /* setup a rank_info object for us */ pmix_globals.mypeer->info = PMIX_NEW(pmix_rank_info_t); if (NULL == pmix_globals.mypeer->info) { return PMIX_ERR_NOMEM; } if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) { /* if we are a client, then we need to pickup the * rest of the envar-based server assignments */ pmix_globals.pindex = -1; pmix_globals.mypeer->info->pname.nspace = strdup(pmix_globals.myid.nspace); pmix_globals.mypeer->info->pname.rank = pmix_globals.myid.rank; } pmix_globals.mypeer->info->realuid = pmix_globals.realuid; pmix_globals.mypeer->info->uid = pmix_globals.uid; pmix_globals.mypeer->info->realgid = pmix_globals.realgid; pmix_globals.mypeer->info->gid = pmix_globals.gid; pmix_globals.mypeer->info->pid = pmix_globals.pid; /* select our bfrops compat module */ pmix_globals.mypeer->nptr->compat.bfrops = pmix_bfrops_base_assign_module(NULL); if (NULL == pmix_globals.mypeer->nptr->compat.bfrops) { return PMIX_ERR_INIT; } /* the server will be using the same */ pmix_client_globals.myserver->nptr->compat.bfrops = pmix_globals.mypeer->nptr->compat.bfrops; /* select our psec compat module - the selection may be based * on the corresponding envars that should have been passed * to us at launch */ evar = getenv("PMIX_SECURITY_MODE"); pmix_globals.mypeer->nptr->compat.psec = pmix_psec_base_assign_module(evar); if (NULL == pmix_globals.mypeer->nptr->compat.psec) { return PMIX_ERR_INIT; } /* the server will be using the same */ pmix_client_globals.myserver->nptr->compat.psec = pmix_globals.mypeer->nptr->compat.psec; /* set the buffer type - the selection will be based * on the corresponding envars that should have been passed * to us at launch */ evar = getenv("PMIX_BFROP_BUFFER_TYPE"); if (NULL == evar) { /* just set to our default */ pmix_globals.mypeer->nptr->compat.type = pmix_bfrops_globals.default_type; } else if (0 == strcmp(evar, "PMIX_BFROP_BUFFER_FULLY_DESC")) { pmix_globals.mypeer->nptr->compat.type = PMIX_BFROP_BUFFER_FULLY_DESC; } else { pmix_globals.mypeer->nptr->compat.type = PMIX_BFROP_BUFFER_NON_DESC; } /* the server will be using the same */ pmix_client_globals.myserver->nptr->compat.type = pmix_globals.mypeer->nptr->compat.type; /* tools are restricted to the "hash" component for interacting * with a server's GDS framework */ PMIX_INFO_LOAD(&ginfo, PMIX_GDS_MODULE, "hash", PMIX_STRING); pmix_globals.mypeer->nptr->compat.gds = pmix_gds_base_assign_module(&ginfo, 1); PMIX_INFO_DESTRUCT(&ginfo); if (NULL == pmix_globals.mypeer->nptr->compat.gds) { return PMIX_ERR_INIT; } pmix_client_globals.myserver->nptr->compat.gds = pmix_globals.mypeer->nptr->compat.gds; /* tools can, in some scenarios, act as servers, * so initialize the server globals too */ if (PMIX_SUCCESS != (rc = pmix_server_initialize())) { PMIX_ERROR_LOG(rc); return rc; } /* setup the function pointers */ memset(&pmix_host_server, 0, sizeof(pmix_server_module_t)); if (do_not_connect) { /* ensure we mark that we are not connected */ pmix_atomic_unset_bool(&pmix_globals.connected); /* it is not an error if we were not given an nspace/rank */ if (!nspace_given || !rank_given) { /* self-assign a namespace and rank for ourselves. Use our hostname:pid * for the nspace, and rank clearly is 0 */ pmix_snprintf(pmix_globals.myid.nspace, PMIX_MAX_NSLEN - 1, "%s:%lu", pmix_globals.hostname, (unsigned long) pmix_globals.pid); pmix_globals.myid.rank = 0; nspace_given = false; rank_given = false; /* also setup the client myserver to point to ourselves */ pmix_client_globals.myserver->nptr->nspace = strdup(pmix_globals.myid.nspace); pmix_client_globals.myserver->info = PMIX_NEW(pmix_rank_info_t); pmix_client_globals.myserver->info->pname.nspace = strdup(pmix_globals.myid.nspace); pmix_client_globals.myserver->info->pname.rank = pmix_globals.myid.rank; pmix_client_globals.myserver->info->uid = pmix_globals.uid; pmix_client_globals.myserver->info->gid = pmix_globals.gid; // set the type of the server to be our own PMIX_SET_PEER_TYPE(pmix_client_globals.myserver, ptype.type); } } else { /* connect to the server */ rc = pmix_ptl.connect_to_peer((struct pmix_peer_t *) pmix_client_globals.myserver, info, ninfo, &suri); if (PMIX_SUCCESS == rc) { /* store the URI for subsequent lookups */ PMIX_KVAL_NEW(kptr, PMIX_SERVER_URI); kptr->value->type = PMIX_STRING; pmix_asprintf(&kptr->value->data.string, "%s.%u;%s", pmix_client_globals.myserver->info->pname.nspace, pmix_client_globals.myserver->info->pname.rank, suri); free(suri); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); PMIX_RELEASE(kptr); // maintain accounting if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } else { /* if connection wasn't optional, then error out */ if (!connect_optional) { return rc; } /* if connection was optional, then we need to self-assign * a namespace and rank for ourselves. Use our hostname:pid * for the nspace, and rank clearly is 0 */ pmix_snprintf(pmix_globals.myid.nspace, PMIX_MAX_NSLEN - 1, "%s:%lu", pmix_globals.hostname, (unsigned long) pmix_globals.pid); pmix_globals.myid.rank = 0; nspace_given = false; rank_given = false; /* also setup the client myserver to point to ourselves */ pmix_client_globals.myserver->nptr->nspace = strdup(pmix_globals.myid.nspace); pmix_client_globals.myserver->info = PMIX_NEW(pmix_rank_info_t); pmix_client_globals.myserver->info->pname.nspace = strdup(pmix_globals.myid.nspace); pmix_client_globals.myserver->info->pname.rank = pmix_globals.myid.rank; pmix_client_globals.myserver->info->uid = pmix_globals.uid; pmix_client_globals.myserver->info->gid = pmix_globals.gid; // set the type of the server to be our own PMIX_SET_PEER_TYPE(pmix_client_globals.myserver, ptype.type); /* mark us as not connecting to avoid asking for our job info */ do_not_connect = true; } } /* setup the wildcard ID */ PMIX_LOAD_PROCID(&wildcard, pmix_globals.myid.nspace, PMIX_RANK_WILDCARD); /* pass back the ID */ PMIX_LOAD_PROCID(proc, pmix_globals.myid.nspace, pmix_globals.myid.rank); /* cache the server in case we later want to call "set_server" on it */ PMIX_RETAIN(pmix_client_globals.myserver); pmix_pointer_array_add(&pmix_server_globals.clients, pmix_client_globals.myserver); /* load into our own peer object */ if (NULL == pmix_globals.mypeer->nptr->nspace) { pmix_globals.mypeer->nptr->nspace = strdup(pmix_globals.myid.nspace); } /* setup a rank_info object for us */ pmix_globals.mypeer->info = PMIX_NEW(pmix_rank_info_t); if (NULL == pmix_globals.mypeer->info) { return PMIX_ERR_NOMEM; } pmix_globals.mypeer->info->pname.nspace = strdup(pmix_globals.myid.nspace); pmix_globals.mypeer->info->pname.rank = pmix_globals.myid.rank; /* if we are acting as a server, then setup the global recv */ if (PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) || PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { /* setup the wildcard recv for inbound messages from clients */ rcv = PMIX_NEW(pmix_ptl_posted_recv_t); rcv->tag = UINT32_MAX; rcv->cbfunc = pmix_server_message_handler; /* add it to the end of the list of recvs */ pmix_list_append(&pmix_ptl_base.posted_recvs, &rcv->super); } /* open the pmdl framework and select the active modules for this environment * as we might need them if we are asking a server to launch something for us */ rc = pmix_mca_base_framework_open(&pmix_pmdl_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { return rc; } if (PMIX_SUCCESS != (rc = pmix_pmdl_base_select())) { return rc; } /* setup IOF */ PMIX_IOF_SINK_DEFINE(&pmix_client_globals.iof_stdout, &pmix_globals.myid, 1, PMIX_FWD_STDOUT_CHANNEL, pmix_iof_write_handler); PMIX_IOF_SINK_DEFINE(&pmix_client_globals.iof_stderr, &pmix_globals.myid, 2, PMIX_FWD_STDERR_CHANNEL, pmix_iof_write_handler); /* create the default iof handler */ iofreq = PMIX_NEW(pmix_iof_req_t); iofreq->channels = PMIX_FWD_STDOUT_CHANNEL | PMIX_FWD_STDERR_CHANNEL | PMIX_FWD_STDDIAG_CHANNEL; pmix_pointer_array_set_item(&pmix_globals.iof_requests, 0, iofreq); if (fwd_stdin) { /* setup the read - we don't want to set nonblocking on our * stdio stream. If we do so, we set the file descriptor to * non-blocking for everyone that has that file descriptor, which * includes everyone else in our shell pipeline chain. (See * http://lists.freebsd.org/pipermail/freebsd-hackers/2005-January/009742.html). * This causes things like "prun -np 1 big_app | cat" to lose * output, because cat's stdout is then ALSO non-blocking and cat * isn't built to deal with that case (same with almost all other * unix text utils).*/ fd = fileno(stdin); if (isatty(fd)) { /* We should avoid trying to read from stdin if we * have a terminal, but are backgrounded. Catch the * signals that are commonly used when we switch * between being backgrounded and not. If the * filedescriptor is not a tty, don't worry about it * and always stay connected. */ pmix_event_signal_set(pmix_globals.evauxbase, &stdinsig, SIGCONT, pmix_iof_stdin_cb, &stdinev); /* setup a read event to read stdin, but don't activate it yet. The * dst_name indicates who should receive the stdin. If that recipient * doesn't do a corresponding pull, however, then the stdin will * be dropped upon receipt at the local daemon */ PMIX_CONSTRUCT(&stdinev, pmix_iof_read_event_t); stdinev.fd = fd; stdinev.always_readable = pmix_iof_fd_always_ready(fd); if (stdinev.always_readable) { pmix_event_evtimer_set(pmix_globals.evbase, &stdinev.ev, pmix_iof_read_local_handler, &stdinev); } else { pmix_event_set(pmix_globals.evbase, &stdinev.ev, fd, PMIX_EV_READ, pmix_iof_read_local_handler, &stdinev); } /* check to see if we want the stdin read event to be * active - we will always at least define the event, * but may delay its activation */ if (pmix_iof_stdin_check(fd)) { PMIX_IOF_READ_ACTIVATE(&stdinev); } } else { /* if we are not looking at a tty, just setup a read event * and activate it */ PMIX_CONSTRUCT(&stdinev, pmix_iof_read_event_t); stdinev.fd = fd; stdinev.always_readable = pmix_iof_fd_always_ready(fd); if (stdinev.always_readable) { pmix_event_evtimer_set(pmix_globals.evbase, &stdinev.ev, pmix_iof_read_local_handler, &stdinev); } else { pmix_event_set(pmix_globals.evbase, &stdinev.ev, fd, PMIX_EV_READ, pmix_iof_read_local_handler, &stdinev); } PMIX_IOF_READ_ACTIVATE(&stdinev); } } /* fill in our local * datastore with typical job-related info. No point * in having the server generate these as we are * obviously a singleton, and so the values are well-known */ rc = pmix_tool_init_info(); if (PMIX_SUCCESS != rc) { return rc; } /* if we are connected, then send a request for our * job info - we do this as a non-blocking * transaction because some systems cannot handle very large * blocking operations and error out if we try them. */ if (!do_not_connect && !PMIX_PEER_IS_SCHEDULER(pmix_client_globals.myserver)) { req = PMIX_NEW(pmix_buffer_t); cmd = PMIX_REQ_CMD; PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, req, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(req); return rc; } /* send to the server */ PMIX_CONSTRUCT(&cb, pmix_cb_t); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, req, job_data, (void *) &cb); if (PMIX_SUCCESS != rc) { return rc; } /* wait for the data to return */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; PMIX_DESTRUCT(&cb); if (PMIX_SUCCESS != rc) { return rc; } /* quick check to see if we got something back. If this * is a launcher that is being executed multiple times * in a job-script, then the original registration data * may have been deleted after the first invocation. In * such a case, we simply regenerate it locally as it is * well-known */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &wildcard; cb.copy = true; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS != rc) { pmix_output_verbose(5, pmix_client_globals.get_output, "pmix:tool:client data not found in internal storage"); rc = pmix_tool_init_info(); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&cb); return rc; } } PMIX_DESTRUCT(&cb); } // enable show_help subsystem pmix_atomic_store_int(&pmix_show_help_enabled, 1); /* if we are acting as a server, then start listening * and register the server receive */ if (PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) || PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { /* setup the fork/exec framework */ rc = pmix_pfexec_base_open(); if (PMIX_SUCCESS != rc) { return rc; } /* if we don't know our topology, we better get it now as we * increasingly rely on it - note that our host will hopefully * have passed it to us so we don't duplicate their storage! */ if (PMIX_SUCCESS != (rc = pmix_hwloc_setup_topology(info, ninfo))) { return rc; } /* open the pnet framework and select the active modules for this environment */ rc = pmix_mca_base_framework_open(&pmix_pnet_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { return rc; } if (PMIX_SUCCESS != (rc = pmix_pnet_base_select())) { return rc; } /* start listening for connections */ rc = pmix_ptl_base_start_listening(info, ninfo); if (PMIX_SUCCESS != rc) { if (PMIX_ERR_SILENT != rc) { pmix_show_help("help-pmix-server.txt", "listener-thread-start", true); } return PMIX_ERR_INIT; } } /* see if they gave us a rendezvous URI to which we are to call back */ evar = getenv("PMIX_LAUNCHER_RNDZ_URI"); if (NULL != evar) { /* attach to the specified server so it can * tell us what we are to do - save our * current server for now */ PMIX_LOAD_PROCID(&myserver, pmix_client_globals.myserver->info->pname.nspace, pmix_client_globals.myserver->info->pname.rank); PMIX_INFO_CREATE(iptr, 3); PMIX_INFO_LOAD(&iptr[0], PMIX_SERVER_URI, evar, PMIX_STRING); rc = 2; // give us two seconds to connect PMIX_INFO_LOAD(&iptr[1], PMIX_TIMEOUT, &rc, PMIX_INT); PMIX_INFO_LOAD(&iptr[2], PMIX_PRIMARY_SERVER, NULL, PMIX_BOOL); cbptr = PMIX_NEW(pmix_cb_t); cbptr->info = iptr; cbptr->ninfo = 3; PMIX_THREADSHIFT(cbptr, pmix_tool_retry_attach); PMIX_WAIT_THREAD(&cbptr->lock); rc = cbptr->status; PMIX_RELEASE(cbptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return PMIX_ERR_UNREACH; } /* save our parent ID */ PMIX_KVAL_NEW(kptr, PMIX_PARENT_ID); kptr->value->type = PMIX_PROC; kptr->value->data.proc = &myparent; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); PMIX_RELEASE(kptr); // maintain accounting if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* retrieve any job info it has for us */ req = PMIX_NEW(pmix_buffer_t); cmd = PMIX_REQ_CMD; PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, req, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(req); return rc; } /* send to the server */ PMIX_CONSTRUCT(&cb, pmix_cb_t); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, req, job_data, (void *) &cb); if (PMIX_SUCCESS != rc) { return rc; } /* wait for the data to return */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; PMIX_DESTRUCT(&cb); if (PMIX_SUCCESS != rc) { return rc; } /* if the value was found, then we need to wait for debugger attach here */ /* register for the debugger release notification */ PMIX_CONSTRUCT_LOCK(®lock); PMIX_CONSTRUCT_LOCK(&releaselock); PMIX_INFO_LOAD(&evinfo[0], PMIX_EVENT_RETURN_OBJECT, &releaselock, PMIX_POINTER); PMIX_INFO_LOAD(&evinfo[1], PMIX_EVENT_HDLR_NAME, "WAIT-FOR-RELEASE", PMIX_STRING); PMIX_INFO_LOAD(&evinfo[2], PMIX_EVENT_ONESHOT, NULL, PMIX_BOOL); pmix_output_verbose(2, pmix_client_globals.event_output, "[%s:%d] WAITING IN INIT FOR RELEASE", pmix_globals.myid.nspace, pmix_globals.myid.rank); cd = PMIX_NEW(pmix_rshift_caddy_t); cd->codes = malloc(sizeof(int)); cd->codes[0] = PMIX_DEBUGGER_RELEASE; cd->ncodes = 1; cd->info = evinfo; cd->ninfo = 3; cd->evhdlr = notification_fn; cd->evregcbfn = evhandler_reg_callbk; cd->cbdata = cd; PMIX_RETAIN(cd); // so pmix_internal_reg_event_hdlr doesn't wind up releasing it PMIX_THREADSHIFT(cd, pmix_internal_reg_event_hdlr); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; PMIX_RELEASE(cd); PMIX_INFO_DESTRUCT(&evinfo[0]); PMIX_INFO_DESTRUCT(&evinfo[1]); PMIX_INFO_DESTRUCT(&evinfo[2]); if (0 > rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT_LOCK(&releaselock); return rc; } /* wait for release to arrive */ PMIX_WAIT_THREAD(&releaselock); PMIX_DESTRUCT_LOCK(&releaselock); /* restore our original primary server */ cbptr = PMIX_NEW(pmix_cb_t); cbptr->proc = &myserver; PMIX_THREADSHIFT(cbptr, pmix_tool_retry_set); /* wait for completion */ PMIX_WAIT_THREAD(&cbptr->lock); rc = cbptr->status; PMIX_RELEASE(cbptr); if (PMIX_SUCCESS != rc) { return rc; } } /* register the tool supported attrs */ rc = pmix_register_tool_attrs(); // mark ourselves as initialized pmix_atomic_set_bool(&pmix_globals.initialized); return rc; } PMIX_EXPORT pmix_status_t pmix_tool_init_info(void) { pmix_kval_t *kptr; pmix_status_t rc; pmix_proc_t wildcard; PMIX_LOAD_PROCID(&wildcard, pmix_globals.myid.nspace, PMIX_RANK_WILDCARD); /* the jobid is just our nspace */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_JOBID); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_STRING; kptr->value->data.string = strdup(pmix_globals.myid.nspace); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* our rank */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_RANK); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_INT; kptr->value->data.integer = 0; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* nproc offset */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_NPROC_OFFSET); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 0; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* node size */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_NODE_SIZE); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 1; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* local peers */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_LOCAL_PEERS); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_STRING; kptr->value->data.string = strdup("0"); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* local leader */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_LOCALLDR); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 0; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* universe size */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_UNIV_SIZE); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 1; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* job size - we are our very own job, so we have no peers */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_JOB_SIZE); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 1; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* local size - only us in our job */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_LOCAL_SIZE); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 1; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* max procs - since we are a self-started tool, there is no * allocation within which we can grow ourselves */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_MAX_PROCS); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 1; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* app number */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_APPNUM); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 0; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* app leader */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_APPLDR); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 0; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* app rank */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_APP_RANK); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 0; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* global rank */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_GLOBAL_RANK); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT32; kptr->value->data.uint32 = 0; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* local rank - we are alone in our job */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_LOCAL_RANK); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_UINT16; kptr->value->data.uint32 = 0; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* we cannot know the node rank as we don't know what * other processes are executing on this node - so * we'll add that info to the server-tool handshake * and load it from there */ /* hostname */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_HOSTNAME); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_STRING; kptr->value->data.string = strdup(pmix_globals.hostname); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* we cannot know the RM's nodeid for this host, so * we'll add that info to the server-tool handshake * and load it from there */ /* the nodemap is simply our hostname as there is no * regex to generate */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_NODE_MAP); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_STRING; kptr->value->data.string = strdup(pmix_globals.hostname); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* likewise, the proc map is just our rank as we are * the only proc in this job */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_PROC_MAP); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_STRING; kptr->value->data.string = strdup("0"); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &wildcard, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting /* store our server's ID */ if (NULL != pmix_client_globals.myserver && NULL != pmix_client_globals.myserver->info && NULL != pmix_client_globals.myserver->info->pname.nspace) { kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_SERVER_NSPACE); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_STRING; kptr->value->data.string = strdup(pmix_client_globals.myserver->info->pname.nspace); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_SERVER_RANK); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_PROC_RANK; kptr->value->data.rank = pmix_client_globals.myserver->info->pname.rank; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting } return PMIX_SUCCESS; } pmix_status_t PMIx_tool_set_server_module(pmix_server_module_t *module) { pmix_host_server = *module; /* mark that we are now a server */ PMIX_SET_PEER_TYPE(pmix_globals.mypeer, PMIX_PROC_SERVER); return PMIX_SUCCESS; } typedef struct { pmix_lock_t lock; pmix_event_t ev; bool active; } pmix_tool_timeout_t; /* timer callback */ static void fin_timeout(int sd, short args, void *cbdata) { pmix_tool_timeout_t *tev; tev = (pmix_tool_timeout_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:tool finwait timeout fired"); if (tev->active) { tev->active = false; PMIX_WAKEUP_THREAD(&tev->lock); } } /* callback for finalize completion */ static void finwait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_tool_timeout_t *tev; tev = (pmix_tool_timeout_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(pr, hdr, buf); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:tool finwait_cbfunc received"); if (tev->active) { tev->active = false; pmix_event_del(&tev->ev); // stop the timer } PMIX_WAKEUP_THREAD(&tev->lock); } PMIX_EXPORT pmix_status_t PMIx_tool_finalize(void) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_FINALIZE_CMD; pmix_status_t rc; pmix_tool_timeout_t tev; struct timeval tv = {5, 0}; int n; pmix_peer_t *peer; pmix_pfexec_child_t *child, *nxt; pmix_lock_t lock; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } pmix_atomic_unset_bool(&pmix_globals.initialized); pmix_globals.mypeer->finalized = true; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:tool finalize called"); /* if we are connected, then disconnect */ if (pmix_atomic_check_bool(&pmix_globals.connected)) { pmix_output_verbose(2, pmix_globals.debug_output, "pmix:tool sending finalize sync to server"); /* setup a cmd message to notify the PMIx * server that we are normally terminating */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* setup a timer to protect ourselves should the server be unable * to answer for some reason */ PMIX_CONSTRUCT_LOCK(&tev.lock); pmix_event_assign(&tev.ev, pmix_globals.evbase, -1, 0, fin_timeout, &tev); tev.active = true; PMIX_POST_OBJECT(&tev); pmix_event_add(&tev.ev, &tv); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, finwait_cbfunc, (void *) &tev); if (PMIX_SUCCESS != rc) { if (tev.active) { pmix_event_del(&tev.ev); } return rc; } /* wait for the ack to return */ PMIX_WAIT_THREAD(&tev.lock); PMIX_DESTRUCT_LOCK(&tev.lock); if (tev.active) { pmix_event_del(&tev.ev); } pmix_output_verbose(2, pmix_globals.debug_output, "pmix:tool finalize sync received"); } if (PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) || PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { /* if we have launched children, then we need to cleanly * terminate them - do this before stopping our progress * thread as we need it for terminating procs */ if (pmix_pfexec_globals.active) { pmix_event_del(pmix_pfexec_globals.handler); pmix_pfexec_globals.active = false; } PMIX_LIST_FOREACH_SAFE (child, nxt, &pmix_pfexec_globals.children, pmix_pfexec_child_t) { PMIX_CONSTRUCT_LOCK(&lock); PMIX_PFEXEC_KILL(&child->proc, &lock); PMIX_WAIT_THREAD(&lock); PMIX_DESTRUCT_LOCK(&lock); } pmix_pfexec_base_close(); } /* wait here until all active events have been processed */ PMIx_Progress_thread_stop(NULL, 0); /* flush anything that is still trying to be written out */ pmix_iof_static_dump_output(&pmix_client_globals.iof_stdout); pmix_iof_static_dump_output(&pmix_client_globals.iof_stderr); PMIX_LIST_DESTRUCT(&pmix_client_globals.pending_requests); for (n = 0; n < pmix_client_globals.peers.size; n++) { peer = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_client_globals.peers, n); if (NULL != peer) { PMIX_RELEASE(peer); } } pmix_ptl_base_stop_listening(); for (n = 0; n < pmix_server_globals.clients.size; n++) { peer = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, n); if (NULL != peer) { PMIX_RELEASE(peer); } } (void) pmix_mca_base_framework_close(&pmix_pnet_base_framework); PMIX_DESTRUCT(&pmix_server_globals.clients); PMIX_LIST_DESTRUCT(&pmix_server_globals.collectives); PMIX_LIST_DESTRUCT(&pmix_server_globals.remote_pnd); PMIX_LIST_DESTRUCT(&pmix_server_globals.local_reqs); PMIX_LIST_DESTRUCT(&pmix_server_globals.gdata); PMIX_LIST_DESTRUCT(&pmix_server_globals.events); PMIX_LIST_DESTRUCT(&pmix_server_globals.iof); (void) pmix_mca_base_framework_close(&pmix_pmdl_base_framework); (void) pmix_mca_base_framework_close(&pmix_pnet_base_framework); pmix_rte_finalize(); if (NULL != pmix_globals.mypeer) { PMIX_RELEASE(pmix_globals.mypeer); } if (NULL != pmix_client_globals.myserver) { PMIX_RELEASE(pmix_client_globals.myserver); } /* finalize the class/object system */ pmix_class_finalize(); return PMIX_SUCCESS; } bool PMIx_tool_is_connected(void) { return pmix_atomic_check_bool(&pmix_globals.connected); } pmix_status_t PMIx_tool_connect_to_server(pmix_proc_t *proc, pmix_info_t info[], size_t ninfo) { pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } rc = PMIx_tool_attach_to_server(proc, NULL, info, ninfo); return rc; } void pmix_tool_retry_attach(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_kval_t *kptr; pmix_peer_t *peer; size_t n; pmix_status_t rc; char *suri; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cb); /* check for directives */ cb->checked = false; for (n = 0; n < cb->ninfo; n++) { if (PMIX_CHECK_KEY(&cb->info[n], PMIX_PRIMARY_SERVER)) { cb->checked = PMIX_INFO_TRUE(&cb->info[n]); break; } } /* ask the ptl to establish connection to the new server */ peer = PMIX_NEW(pmix_peer_t); /* setup the infrastructure - assume this new server will follow * same rules as our current one */ peer->nptr = PMIX_NEW(pmix_namespace_t); peer->info = PMIX_NEW(pmix_rank_info_t); peer->nptr->compat.bfrops = pmix_globals.mypeer->nptr->compat.bfrops; peer->nptr->compat.psec = pmix_globals.mypeer->nptr->compat.psec; peer->nptr->compat.type = pmix_globals.mypeer->nptr->compat.type; peer->nptr->compat.gds = pmix_globals.mypeer->nptr->compat.gds; cb->status = pmix_ptl.connect_to_peer((struct pmix_peer_t *) peer, cb->info, cb->ninfo, &suri); if (PMIX_SUCCESS == cb->status) { /* return the name */ cb->pname.nspace = strdup(peer->info->pname.nspace); cb->pname.rank = peer->info->pname.rank; /* add the peer to our known clients */ pmix_pointer_array_add(&pmix_server_globals.clients, peer); if (cb->checked) { /* point our active server at this new one */ pmix_client_globals.myserver = peer; /* mark that we are connected */ pmix_atomic_set_bool(&pmix_globals.connected); /* update our active server's ID in the local key-value store */ kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_SERVER_NSPACE); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_STRING; kptr->value->data.string = strdup(peer->info->pname.nspace); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } PMIX_RELEASE(kptr); // maintain accounting kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_SERVER_RANK); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_PROC_RANK; kptr->value->data.rank = peer->info->pname.rank; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } PMIX_RELEASE(kptr); // maintain accounting /* store the URI for subsequent lookups */ PMIX_KVAL_NEW(kptr, PMIX_SERVER_URI); kptr->value->type = PMIX_STRING; pmix_asprintf(&kptr->value->data.string, "%s.%u;%s", peer->info->pname.nspace, peer->info->pname.rank, suri); free(suri); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); PMIX_RELEASE(kptr); // maintain accounting if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } } else { PMIX_RELEASE(peer); } PMIX_WAKEUP_THREAD(&cb->lock); PMIX_POST_OBJECT(cb); return; } pmix_status_t PMIx_tool_attach_to_server(pmix_proc_t *myproc, pmix_proc_t *server, pmix_info_t info[], size_t ninfo) { pmix_status_t rc; pmix_cb_t *cb; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* check for bozo error */ if (NULL == info || 0 == ninfo) { pmix_show_help("help-pmix-runtime.txt", "tool:no-server", true); return PMIX_ERR_BAD_PARAM; } cb = PMIX_NEW(pmix_cb_t); cb->info = info; cb->ninfo = ninfo; PMIX_THREADSHIFT(cb, pmix_tool_retry_attach); PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; /* if they gave us an address, we pass back our name */ if (NULL != myproc) { memcpy(myproc, &pmix_globals.myid, sizeof(pmix_proc_t)); } /* if the transition didn't succeed, then return at this point */ if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cb); return rc; } /* if they gave us an address, return the new server's ID */ if (NULL != server) { PMIX_LOAD_PROCID(server, cb->pname.nspace, cb->pname.rank); } PMIX_RELEASE(cb); return PMIX_SUCCESS; } static void disc(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_peer_t *peer = NULL, *pr; int n; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cb); if (NULL == cb->proc) { pmix_atomic_unset_bool(&pmix_globals.connected); cb->status = PMIX_SUCCESS; PMIX_WAKEUP_THREAD(&cb->lock); PMIX_POST_OBJECT(cb); return; } /* see if we have this server */ for (n = 0; n < pmix_server_globals.clients.size; n++) { pr = (pmix_peer_t *) pmix_pointer_array_get_item(&pmix_server_globals.clients, n); if (NULL == pr) { continue; } if (PMIX_CHECK_NSPACE(cb->proc->nspace, pr->info->pname.nspace) && PMIX_CHECK_RANK(cb->proc->rank, pr->info->pname.rank)) { peer = pr; pmix_pointer_array_set_item(&pmix_server_globals.clients, n, NULL); break; } } if (NULL == peer) { cb->status = PMIX_ERR_NOT_FOUND; PMIX_WAKEUP_THREAD(&cb->lock); PMIX_POST_OBJECT(cb); return; } /* if we are disconnecting from the active server, then we enter a * "disconnected" state where we point the active server back at * ourselves - effectively the same as when we init without connecting */ if (peer == pmix_client_globals.myserver) { PMIX_RETAIN(pmix_globals.mypeer); /* switch servers - we are in an event, so it is * safe to do so */ pmix_client_globals.myserver = pmix_globals.mypeer; pmix_atomic_unset_bool(&pmix_globals.connected); } /* now drop the connection */ PMIX_RELEASE(peer); cb->status = PMIX_SUCCESS; PMIX_WAKEUP_THREAD(&cb->lock); PMIX_POST_OBJECT(cb); return; } pmix_status_t PMIx_tool_disconnect(const pmix_proc_t *server) { pmix_status_t rc; pmix_cb_t *cb; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } cb = PMIX_NEW(pmix_cb_t); cb->proc = (pmix_proc_t *) server; PMIX_THREADSHIFT(cb, disc); PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; cb->proc = NULL; PMIX_RELEASE(cb); return rc; } static void getsrvrs(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; int n; size_t ns; pmix_list_t srvrs; pmix_proclist_t *ps; pmix_peer_t *pr; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cb); /* get servers */ PMIX_CONSTRUCT(&srvrs, pmix_list_t); /* put our current active server at the front */ if (pmix_globals.mypeer != pmix_client_globals.myserver) { ps = PMIX_NEW(pmix_proclist_t); PMIX_LOAD_PROCID(&ps->proc, pmix_client_globals.myserver->info->pname.nspace, pmix_client_globals.myserver->info->pname.rank); pmix_list_append(&srvrs, &ps->super); } for (n = 0; n < pmix_server_globals.clients.size; n++) { pr = (pmix_peer_t *) pmix_pointer_array_get_item(&pmix_server_globals.clients, n); if (NULL == pr) { continue; } /* if it is our current primary server, ignore it */ if (pr == pmix_client_globals.myserver) { continue; } /* record it */ ps = PMIX_NEW(pmix_proclist_t); PMIX_LOAD_PROCID(&ps->proc, pr->info->pname.nspace, pr->info->pname.rank); pmix_list_append(&srvrs, &ps->super); } ns = pmix_list_get_size(&srvrs); if (0 == ns) { /* we aren't connected to anyone */ cb->status = PMIX_ERR_UNREACH; cb->nprocs = 0; cb->procs = NULL; PMIX_DESTRUCT(&srvrs); PMIX_WAKEUP_THREAD(&cb->lock); PMIX_POST_OBJECT(cb); return; } /* allocate the array */ PMIX_PROC_CREATE(cb->procs, ns); cb->nprocs = ns; /* now load the array */ n = 0; PMIX_LIST_FOREACH (ps, &srvrs, pmix_proclist_t) { memcpy(&cb->procs[n], &ps->proc, sizeof(pmix_proc_t)); ++n; } cb->status = PMIX_SUCCESS; PMIX_LIST_DESTRUCT(&srvrs); PMIX_WAKEUP_THREAD(&cb->lock); PMIX_POST_OBJECT(cb); return; } pmix_status_t PMIx_tool_get_servers(pmix_proc_t *servers[], size_t *nservers) { pmix_status_t rc; pmix_cb_t *cb; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } cb = PMIX_NEW(pmix_cb_t); PMIX_THREADSHIFT(cb, getsrvrs); PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; *servers = cb->procs; *nservers = cb->nprocs; cb->procs = NULL; // protect the array cb->nprocs = 0; PMIX_RELEASE(cb); return rc; } void pmix_tool_retry_set(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; int n; pmix_peer_t *peer = NULL, *pr; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cb); /* if we are switching back to me, then there is no point in * searching the array of clients - I definitely won't be there! */ if (PMIX_CHECK_NSPACE(cb->proc->nspace, pmix_globals.myid.nspace) && PMIX_CHECK_RANK(cb->proc->rank, pmix_globals.myid.rank)) { pmix_client_globals.myserver = pmix_globals.mypeer; pmix_atomic_set_bool(&pmix_globals.connected); goto done; } /* see if we have this server */ for (n = 0; n < pmix_server_globals.clients.size; n++) { pr = (pmix_peer_t *) pmix_pointer_array_get_item(&pmix_server_globals.clients, n); if (NULL == pr) { continue; } if (PMIX_CHECK_NSPACE(cb->proc->nspace, pr->info->pname.nspace) && PMIX_CHECK_RANK(cb->proc->rank, pr->info->pname.rank)) { peer = pr; break; } } if (NULL == peer) { /* do they want us to wait? */ if (cb->checked) { /* have we timed out? */ --cb->status; if (cb->status < 0) { cb->status = PMIX_ERR_NOT_FOUND; PMIX_WAKEUP_THREAD(&cb->lock); return; } PMIX_THREADSHIFT_DELAY(cb, pmix_tool_retry_set, 0.25); } else { /* no - so just return failure */ cb->status = PMIX_ERR_UNREACH; PMIX_WAKEUP_THREAD(&cb->lock); } PMIX_POST_OBJECT(cb); return; } /* if this is the current active server, then ignore the request */ if (peer == pmix_client_globals.myserver) { pmix_atomic_set_bool(&pmix_globals.connected ); // just ensure we mark ourselves as connected cb->status = PMIX_SUCCESS; PMIX_WAKEUP_THREAD(&cb->lock); PMIX_POST_OBJECT(cb); return; } /* switch the active server - we are in an event, so * it is safe to do so */ PMIX_RETAIN(peer); pmix_client_globals.myserver = peer; pmix_atomic_set_bool(&pmix_globals.connected); done: cb->status = PMIX_SUCCESS; PMIX_WAKEUP_THREAD(&cb->lock); PMIX_POST_OBJECT(cb); return; } pmix_status_t PMIx_tool_set_server(const pmix_proc_t *server, pmix_info_t info[], size_t ninfo) { pmix_status_t rc; pmix_cb_t *cb; size_t n; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* threadshift this so we can access global structures */ cb = PMIX_NEW(pmix_cb_t); cb->proc = (pmix_proc_t *) server; for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_TIMEOUT)) { cb->status = 4 * info[n].value.data.integer; } else if (PMIX_CHECK_KEY(&info[n], PMIX_WAIT_FOR_CONNECTION)) { cb->checked = PMIX_INFO_TRUE(&info[n]); } } PMIX_THREADSHIFT(cb, pmix_tool_retry_set); /* wait for completion */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; PMIX_RELEASE(cb); return rc; } pmix-6.1.1~rc2/src/tool/Makefile.include0000664000175000017500000000036115203536752020323 0ustar alastairalastair# # Copyright (c) 2014-2020 Intel, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers += \ tool/pmix_tool_ops.h sources += \ tool/pmix_tool.c \ tool/pmix_tool_ops.c pmix-6.1.1~rc2/src/util/0000775000175000017500000000000015203536752015241 5ustar alastairalastairpmix-6.1.1~rc2/src/util/help-pmix-util.txt0000664000175000017500000000350615203536752020664 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017 Intel, Inc. All rights reserved. # Copyright (c) 2021 Oak Ridge National Laboratory. All rights reserved. # Copyright (c) 2023-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English general help file for PMIx. # [malformed net_private_ipv4] PMIx has detected at least one malformed IP address or netmask in the value of the opal_net_private_ipv4 MCA parameter. The opal_net_private_ipv4 MCA parameter accepts a semicolon-delimited list of Classless Inter-Domain Routing (CIDR) notation specifications, each of the form /. For example: 10.0.0.0/8;172.16.0.0/12;192.168.0.0/16;169.254.0.0/16 The first detected malformed entry was %s. # [invalid-net-mask] PMIx has detected a malformed IPv4 address or netmask: Value provided: %s Accepted values follow the Classless Inter-Domain Routing (CIDR) notation specifications. For example: 10.0.0.0/8 172.16/12 192.168 169.254.0.0/16 # [mkdir-failed] PMIx detected a call to mkdir was unable to create the desired directory: Directory: %s Error: %s Please check to ensure you have adequate permissions to perform the desired operation. # [unlink-error] We attempted to remove a file, but were unable to do so: Path: %s Error: %s # [failed-file-open] An attempt was made to open a shared memory backing file, but the attempt failed: File: %s Error: %s The PMIx shared memory subsystem will be disabled, but your job will continue by using the "hash" subsystem. # [duplicate-filename] The provided project show-help data array cannot be added as it contains a filename that matches one already in the system: Project1: %s Project2: %s Filename: %s pmix-6.1.1~rc2/src/util/pmix_getcwd.h0000664000175000017500000000266715203536752017737 0ustar alastairalastair/* * Copyright (c) 2007-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Per https://svn.open-mpi.org/trac/ompi/ticket/933, use a * combination of $PWD and getcwd() to find the current working * directory. */ #ifndef PMIX_GETCWD_H #define PMIX_GETCWD_H #include "src/include/pmix_config.h" BEGIN_C_DECLS /** * Per https://svn.open-mpi.org/trac/ompi/ticket/933, use a * combination of $PWD and getcwd() to find the current working * directory. * * Use $PWD instead of getcwd() a) if $PWD exists and b) is a valid * synonym for the results from getcwd(). If both of these conditions * are not met, just fall back and use the results of getcwd(). * * @param buf Caller-allocated buffer to put the result * @param size Length of the buf array * * @retval PMIX_ERR_OUT_OF_RESOURCE If internal malloc() fails. * @retval PMIX_ERR_TEMP_OUT_OF_RESOURCE If the supplied buf buffer * was not long enough to handle the result. * @retval PMIX_ERR_BAD_PARAM If buf is NULL or size>INT_MAX * @retval PMIX_ERR_IN_ERRNO If an other error occurred * @retval PMIX_SUCCESS If all went well and a valid value was placed * in the buf buffer. */ PMIX_EXPORT int pmix_getcwd(char *buf, size_t size); END_C_DECLS #endif /* PMIX_GETCWD_H */ pmix-6.1.1~rc2/src/util/pmix_os_path.c0000664000175000017500000000572715203536752020112 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #ifdef HAVE_SYS_PARAM_H # include #endif /* HAVE_SYS_PARAM_H */ #include #include #include "src/util/pmix_os_path.h" static const char *path_sep = PMIX_PATH_SEP; char *pmix_os_path(int relative, ...) { va_list ap; char *element, *path; size_t num_elements, total_length; va_start(ap, relative); /* no way to protect ourselves from reading too far, so have to trust caller that they ended the list with the NULL */ num_elements = 0; total_length = 0; while (NULL != (element = va_arg(ap, char *))) { num_elements++; total_length = total_length + strlen(element); if (path_sep[0] != element[0]) total_length++; } va_end(ap); if (0 == num_elements) { /* must be looking for a simple answer */ path = (char *) malloc(3); path[0] = '\0'; if (relative) { strcpy(path, "."); strcat(path, path_sep); } else { strcpy(path, path_sep); } return (path); } /* setup path with enough room for the string terminator, the elements, and the separator between each of the elements */ total_length = total_length + num_elements * strlen(path_sep) + 1; if (relative) { total_length++; } if (total_length > PMIX_PATH_MAX) { /* path length is too long - reject it */ return (NULL); } path = (char *) malloc(total_length); if (NULL == path) { return (NULL); } path[0] = 0; if (relative) { strcpy(path, "."); } va_start(ap, relative); if (NULL != (element = va_arg(ap, char *))) { if (path_sep[0] != element[0]) { strcat(path, path_sep); } strcat(path, element); } while (NULL != (element = va_arg(ap, char *))) { if (path_sep[0] != element[0]) { strcat(path, path_sep); } strcat(path, element); } va_end(ap); return pmix_make_filename_os_friendly(path); } pmix-6.1.1~rc2/src/util/pmix_timings.c0000664000175000017500000004571015203536752020123 0ustar alastairalastair/* * Copyright (C) 2014 Artem Polyakov * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include #include #include #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_SYS_RESOURCE_H # include #endif #if PMIX_ENABLE_TIMING #include "src/class/pmix_list.h" #include "src/class/pmix_pointer_array.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_output.h" #include "src/util/pmix_timings.h" #define DELTAS_SANE_LIMIT (10 * 1024 * 1024) struct interval_descr { pmix_timing_event_t *descr_ev, *begin_ev; double interval, overhead; }; pmix_timing_event_t *pmix_timing_event_alloc(pmix_timing_t *t); void pmix_timing_init(pmix_timing_t *t); pmix_timing_prep_t pmix_timing_prep_ev(pmix_timing_t *t, const char *fmt, ...); static PMIX_CLASS_INSTANCE(pmix_timing_event_t, pmix_list_item_t, NULL, NULL); static char *nodename = NULL; static char *jobid = ""; static double hnp_offs = 0; static bool pmix_timing_overhead = false; void pmix_init_id(char *nspace, int rank) { asprintf(&jobid, "%s:%d", nspace, rank); } /* Get current timestamp. Derived from MPI_Wtime */ static double get_ts_gettimeofday(void) { double ret; /* Use gettimeofday() if we pmix wasn't initialized */ struct timeval tv; gettimeofday(&tv, NULL); ret = tv.tv_sec; ret += (double) tv.tv_usec / 1000000.0; return ret; } static get_ts_t _init_timestamping(void) { return get_ts_gettimeofday; } pmix_timing_event_t *pmix_timing_event_alloc(pmix_timing_t *t) { if (t->buffer_offset >= t->buffer_size) { // notch timings overhead double alloc_begin = t->get_ts(); t->buffer = calloc(t->buffer_size, sizeof(pmix_timing_event_t)); if (t->buffer == NULL) { return NULL; } double alloc_end = t->get_ts(); t->buffer_offset = 0; t->buffer[0].fib = 1; t->buffer[0].ts_ovh = alloc_end - alloc_begin; } int tmp = t->buffer_offset; (t->buffer_offset)++; return t->buffer + tmp; } void pmix_timing_init(pmix_timing_t *t) { memset(t, 0, sizeof(*t)); t->next_id_cntr = 0; t->current_id = -1; /* initialize events list */ t->events = PMIX_NEW(pmix_list_t); /* Set buffer size */ t->buffer_size = PMIX_TIMING_BUFSIZE; /* Set buffer_offset = buffer_size so new buffer * will be allocated at first event report */ t->buffer_offset = t->buffer_size; /* initialize gettime function */ t->get_ts = _init_timestamping(); } pmix_timing_prep_t pmix_timing_prep_ev(pmix_timing_t *t, const char *fmt, ...) { pmix_timing_event_t *ev = pmix_timing_event_alloc(t); if (ev == NULL) { pmix_timing_prep_t p = {t, NULL, PMIX_ERR_OUT_OF_RESOURCE}; return p; } PMIX_CONSTRUCT(ev, pmix_timing_event_t); ev->ts = t->get_ts(); va_list args; va_start(args, fmt); vsnprintf(ev->descr, PMIX_TIMING_DESCR_MAX - 1, fmt, args); ev->descr[PMIX_TIMING_DESCR_MAX - 1] = '\0'; va_end(args); pmix_timing_prep_t p = {t, ev, 0}; return p; } pmix_timing_prep_t pmix_timing_prep_ev_end(pmix_timing_t *t, const char *fmt, ...) { pmix_timing_prep_t p = {t, NULL, 0}; PMIX_HIDE_UNUSED_PARAMS(fmt); if (t->current_id >= 0) { pmix_timing_event_t *ev = pmix_timing_event_alloc(t); if (ev == NULL) { pmix_timing_prep_t p2 = {t, NULL, PMIX_ERR_OUT_OF_RESOURCE}; return p2; } PMIX_CONSTRUCT(ev, pmix_timing_event_t); ev->ts = t->get_ts(); p.ev = ev; } return p; } void pmix_timing_add_step(pmix_timing_prep_t p, const char *func, const char *file, int line) { if (!p.errcode) { p.ev->func = func; p.ev->file = file; p.ev->line = line; p.ev->type = PMIX_TIMING_TRACE; pmix_list_append(p.t->events, (pmix_list_item_t *) p.ev); } } /* Add description of the interval */ int pmix_timing_descr(pmix_timing_prep_t p, const char *func, const char *file, int line) { if (!p.errcode) { p.ev->func = func; p.ev->file = file; p.ev->line = line; p.ev->type = PMIX_TIMING_INTDESCR; p.ev->id = p.t->next_id_cntr; (p.t->next_id_cntr)++; pmix_list_append(p.t->events, (pmix_list_item_t *) p.ev); return p.ev->id; } return -1; } void pmix_timing_start_id(pmix_timing_t *t, int id, const char *func, const char *file, int line) { /* No description is needed. If everything is OK * it'll be included in pmix_timing_start_init */ pmix_timing_event_t *ev = pmix_timing_event_alloc(t); if (ev == NULL) { return; } PMIX_CONSTRUCT(ev, pmix_timing_event_t); t->current_id = id; ev->ts = t->get_ts(); ev->func = func; ev->file = file; ev->line = line; ev->type = PMIX_TIMING_INTBEGIN; ev->id = id; pmix_list_append(t->events, (pmix_list_item_t *) ev); } void pmix_timing_end(pmix_timing_t *t, int id, const char *func, const char *file, int line) { /* No description is needed. If everything is OK * it'll be included in pmix_timing_start_init */ pmix_timing_event_t *ev = pmix_timing_event_alloc(t); if (ev == NULL) { return; } PMIX_CONSTRUCT(ev, pmix_timing_event_t); if (id < 0) { ev->id = t->current_id; t->current_id = -1; } else { if (t->current_id == id) { t->current_id = -1; } ev->id = id; } ev->ts = t->get_ts(); ev->func = func; ev->file = file; ev->line = line; ev->type = PMIX_TIMING_INTEND; pmix_list_append(t->events, (pmix_list_item_t *) ev); } void pmix_timing_end_prep(pmix_timing_prep_t p, const char *func, const char *file, int line) { pmix_timing_event_t *ev = p.ev; if (!p.errcode && (NULL != ev)) { assert(p.t->current_id >= 0); ev->id = p.t->current_id; p.t->current_id = -1; ev->func = func; ev->file = file; ev->line = line; ev->type = PMIX_TIMING_INTEND; pmix_list_append(p.t->events, (pmix_list_item_t *) ev); } } static int _prepare_descriptions(pmix_timing_t *t, struct interval_descr **__descr) { struct interval_descr *descr; pmix_timing_event_t *ev, *next; if (t->next_id_cntr == 0) { return 0; } *__descr = calloc(t->next_id_cntr, sizeof(struct interval_descr)); descr = *__descr; PMIX_LIST_FOREACH_SAFE (ev, next, t->events, pmix_timing_event_t) { /* pmix_output(0,"EVENT: type = %d, id=%d, ts = %.12le, ovh = %.12le %s", ev->type, ev->id, ev->ts, ev->ts_ovh, ev->descr ); */ switch (ev->type) { case PMIX_TIMING_INTDESCR: { if (ev->id >= t->next_id_cntr) { char *file = pmix_basename(ev->file); pmix_output(0, "pmix_timing: bad event id at %s:%d:%s, ignore and remove", file, ev->line, ev->func); free(file); pmix_list_remove_item(t->events, (pmix_list_item_t *) ev); continue; } if (NULL != descr[ev->id].descr_ev) { pmix_timing_event_t *prev = descr[ev->id].descr_ev; char *file = pmix_basename(ev->file); char *file_prev = pmix_basename(prev->file); pmix_output(0, "pmix_timing: duplicated description at %s:%d:%s, " "previous: %s:%d:%s, ignore and remove", file, ev->line, ev->func, file_prev, prev->line, prev->func); free(file); free(file_prev); pmix_list_remove_item(t->events, (pmix_list_item_t *) ev); continue; } descr[ev->id].descr_ev = ev; descr[ev->id].begin_ev = NULL; descr[ev->id].interval = 0; descr[ev->id].overhead = 0; break; } case PMIX_TIMING_INTBEGIN: case PMIX_TIMING_INTEND: { if (ev->id >= t->next_id_cntr || (NULL == descr[ev->id].descr_ev)) { char *file = pmix_basename(ev->file); pmix_output(0, "pmix_timing: bad event id at %s:%d:%s, ignore and remove", file, ev->line, ev->func); free(file); pmix_list_remove_item(t->events, (pmix_list_item_t *) ev); continue; } break; } case PMIX_TIMING_TRACE: break; } } return t->next_id_cntr; } /* Output lines in portions that doesn't * exceed PMIX_TIMING_OUTBUF_SIZE for later automatic processing */ int pmix_timing_report(pmix_timing_t *t, char *fname) { pmix_timing_event_t *ev; FILE *fp = NULL; char *buf = NULL; int buf_size = 0; struct interval_descr *descr = NULL; int rc = PMIX_SUCCESS; if (fname != NULL) { fp = fopen(fname, "a"); if (fp == NULL) { pmix_output(0, "pmix_timing_report: Cannot open %s file" " for writing timing information!", fname); rc = PMIX_ERROR; goto err_exit; } } _prepare_descriptions(t, &descr); buf = calloc((PMIX_TIMING_OUTBUF_SIZE + 1), sizeof(char)); if (buf == NULL) { rc = PMIX_ERR_OUT_OF_RESOURCE; goto err_exit; } double overhead = 0; PMIX_LIST_FOREACH (ev, t->events, pmix_timing_event_t) { char *line, *file; if (ev->fib && pmix_timing_overhead) { overhead += ev->ts_ovh; } file = pmix_basename(ev->file); switch (ev->type) { case PMIX_TIMING_INTDESCR: // Service event, skip it. continue; case PMIX_TIMING_TRACE: rc = asprintf(&line, "[%s:%d] %s \"%s\" [PMIX_TRACE] %s:%d %.10lf\n", nodename, getpid(), jobid, ev->descr, file, ev->line, ev->ts + hnp_offs + overhead); break; case PMIX_TIMING_INTBEGIN: rc = asprintf(&line, "[%s:%d] %s \"%s [start]\" [PMIX_TRACE] %s:%d %.10lf\n", nodename, getpid(), jobid, descr[ev->id].descr_ev->descr, file, ev->line, ev->ts + hnp_offs + overhead); break; case PMIX_TIMING_INTEND: rc = asprintf(&line, "[%s:%d] %s \"%s [stop]\" [PMIX_TRACE] %s:%d %.10lf\n", nodename, getpid(), jobid, descr[ev->id].descr_ev->descr, file, ev->line, ev->ts + hnp_offs + overhead); break; } free(file); if (rc < 0) { rc = PMIX_ERR_OUT_OF_RESOURCE; goto err_exit; } rc = 0; /* Sanity check: this shouldn't happen since description * is event only 1KB long and other fields should never * exceed 9KB */ assert(strlen(line) <= PMIX_TIMING_OUTBUF_SIZE); if (buf_size + strlen(line) > PMIX_TIMING_OUTBUF_SIZE) { // flush buffer to the file if (fp != NULL) { fprintf(fp, "%s", buf); fprintf(fp, "\n"); } else { pmix_output(0, "\n%s", buf); } buf[0] = '\0'; buf_size = 0; } snprintf(buf, PMIX_TIMING_STR_LEN, "%s%s", buf, line); buf_size += strlen(line); free(line); } if (buf_size > 0) { // flush buffer to the file if (fp != NULL) { fprintf(fp, "%s", buf); fprintf(fp, "\n"); } else { pmix_output(0, "\n%s", buf); } buf[0] = '\0'; buf_size = 0; } err_exit: if (NULL != descr) { free(descr); } if (buf != NULL) { free(buf); } if (fp != NULL) { fflush(fp); fclose(fp); } return rc; } /* Output events as one buffer so the data won't be mixed * with other output. This function is supposed to be human readable. * The output goes only to stdout. */ int pmix_timing_deltas(pmix_timing_t *t, char *fname) { pmix_timing_event_t *ev; FILE *fp = NULL; char *buf = NULL; struct interval_descr *descr = NULL; int i, rc = PMIX_SUCCESS; size_t buf_size = 0, buf_used = 0; if (fname != NULL) { fp = fopen(fname, "a"); if (fp == NULL) { pmix_output(0, "pmix_timing_report: Cannot open %s file" " for writing timing information!", fname); rc = PMIX_ERROR; goto err_exit; } } _prepare_descriptions(t, &descr); PMIX_LIST_FOREACH (ev, t->events, pmix_timing_event_t) { int id; if (ev->fib) { /* this event caused buffered memory allocation * for events. Account the overhead for all active * intervals. */ for (i = 0; i < t->next_id_cntr; i++) { if ((NULL != descr[i].descr_ev) && (NULL != descr[i].begin_ev)) { if (pmix_timing_overhead) { descr[i].overhead += ev->ts_ovh; } } } } /* we already process all PMIX_TIMING_DESCR events * and we ignore PMIX_TIMING_EVENT */ if (ev->type == PMIX_TIMING_INTDESCR || ev->type == PMIX_TIMING_TRACE) { /* skip */ continue; } id = ev->id; if (id < 0 || id >= t->next_id_cntr) { char *file = pmix_basename(ev->file); pmix_output(0, "pmix_timing_deltas: bad interval event id: %d at %s:%d:%s (maxid=%d)", id, file, ev->line, ev->func, t->next_id_cntr - 1); free(file); /* skip */ continue; } /* id's assigned auomatically. There shouldn't be any gaps in descr[] */ assert(NULL != descr[id].descr_ev); if (ev->type == PMIX_TIMING_INTBEGIN) { if (NULL != descr[id].begin_ev) { /* the measurement on this interval was already * started! */ pmix_timing_event_t *prev = descr[ev->id].begin_ev; char *file = pmix_basename(ev->file); char *file_prev = pmix_basename(prev->file); pmix_output(0, "pmix_timing_deltas: duplicated start statement at %s:%d:%s, " "previous: %s:%d:%s", file, ev->line, ev->func, file_prev, prev->line, prev->func); free(file); free(file_prev); } else { /* save pointer to the start of measurement event */ descr[id].begin_ev = ev; } /* done, go to the next event */ continue; } if (ev->type == PMIX_TIMING_INTEND) { if (NULL == descr[id].begin_ev) { /* the measurement on this interval wasn't started! */ char *file = pmix_basename(ev->file); pmix_output(0, "pmix_timing_deltas: interval end without start at %s:%d:%s", file, ev->line, ev->func); free(file); } else { descr[id].interval += ev->ts - descr[id].begin_ev->ts; descr[id].begin_ev = NULL; if (ev->fib) { descr[id].overhead += ev->ts_ovh; } } continue; } /* shouldn't ever get here: bad ev->type */ pmix_output(0, "pmix_timing_deltas: bad event type %d", ev->type); assert(0); } buf = calloc((PMIX_TIMING_OUTBUF_SIZE + 1), sizeof(char)); if (buf == NULL) { rc = PMIX_ERR_OUT_OF_RESOURCE; goto err_exit; } buf_size = PMIX_TIMING_OUTBUF_SIZE + 1; buf_used = 0; for (i = 0; i < t->next_id_cntr; i++) { char *line = NULL; size_t line_size; rc = asprintf(&line, "[%s:%d] %s \"%s\" [PMIX_OVHD] %le\n", nodename, getpid(), jobid, descr[i].descr_ev->descr, descr[i].interval - descr[i].overhead); if (rc < 0) { rc = PMIX_ERR_OUT_OF_RESOURCE; goto err_exit; } rc = 0; line_size = strlen(line); /* Sanity check: this shouldn't happen since description * is event only 1KB long and other fields should never * exceed 9KB */ assert(line_size <= PMIX_TIMING_OUTBUF_SIZE); if (buf_used + strlen(line) > buf_size) { // Increase output buffer while (buf_used + line_size > buf_size && buf_size < DELTAS_SANE_LIMIT) { buf_size += PMIX_TIMING_OUTBUF_SIZE + 1; } if (buf_size > DELTAS_SANE_LIMIT) { pmix_output(0, "pmix_timing_report: delta sane limit overflow (%u > %u)!\n", (unsigned int) buf_size, DELTAS_SANE_LIMIT); free(line); rc = PMIX_ERR_OUT_OF_RESOURCE; goto err_exit; } buf = realloc(buf, buf_size); if (buf == NULL) { pmix_output(0, "pmix_timing_deltas: Out of memory!\n"); rc = PMIX_ERR_OUT_OF_RESOURCE; goto err_exit; } } snprintf(buf, PMIX_TIMING_STR_LEN, "%s%s", buf, line); buf_used += line_size; free(line); } if (buf_used > 0) { // flush buffer to the file if (fp != NULL) { fprintf(fp, "%s", buf); fprintf(fp, "\n"); } else { pmix_output(0, "\n%s", buf); } buf[0] = '\0'; buf_size = 0; } err_exit: if (NULL != descr) { free(descr); } if (NULL != buf) { free(buf); } if (fp != NULL) { fflush(fp); fclose(fp); } return rc; } void pmix_timing_release(pmix_timing_t *t) { int cnt = pmix_list_get_size(t->events); if (cnt > 0) { pmix_list_t *tmp = PMIX_NEW(pmix_list_t); int i; for (i = 0; i < cnt; i++) { pmix_timing_event_t *ev = (pmix_timing_event_t *) pmix_list_remove_first(t->events); if (ev->fib) { pmix_list_append(tmp, (pmix_list_item_t *) ev); } } cnt = pmix_list_get_size(tmp); for (i = 0; i < cnt; i++) { pmix_timing_event_t *ev = (pmix_timing_event_t *) pmix_list_remove_first(tmp); free(ev); } PMIX_RELEASE(tmp); } else { // Error case. At list one event was inserted at initialization. } PMIX_RELEASE(t->events); t->events = NULL; } #endif pmix-6.1.1~rc2/src/util/pmix_show_help.c0000664000175000017500000005000215203536752020427 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #include #include "pmix.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/mca/pinstalldirs/pinstalldirs.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" int pmix_show_help_enabled = 0; static time_t show_help_time_last_displayed = 0; static bool show_help_timer_set = false; static pmix_event_t show_help_timer_event; static int output_stream = -1; static bool pmix_show_help_initialized = false; /* How long to wait between displaying duplicate show_help notices */ static struct timeval show_help_interval = {5, 0}; static void local_delivery(const char *file, const char *topic, const char *msg) { pmix_shift_caddy_t *cd; if (!pmix_show_help_initialized || 0 == pmix_atomic_load_int(&pmix_show_help_enabled) || NULL == pmix_globals.evbase) { /* the show help subsystem has not yet been enabled, * likely because we haven't gotten far enough thru * client/server/tool "init". In this case, we can * only output the help locally as we don't have * access to anything else */ fprintf(stderr, "%s", msg); return; } cd = PMIX_NEW(pmix_shift_caddy_t); cd->ninfo = 1; PMIX_INFO_CREATE(cd->info, cd->ninfo); PMIX_INFO_LOAD(&cd->info[0], PMIX_LOG_STDERR, msg, PMIX_STRING); cd->infocopy = true; cd->ndirs = 2; PMIX_INFO_CREATE(cd->directives, cd->ndirs); PMIX_INFO_LOAD(&cd->directives[0], PMIX_LOG_KEY, file, PMIX_STRING); PMIX_INFO_LOAD(&cd->directives[1], PMIX_LOG_VAL, topic, PMIX_STRING); cd->dircopy = true; PMIX_PROC_CREATE(cd->proc, 1); memcpy(cd->proc, &pmix_globals.myid, sizeof(pmix_proc_t)); PMIX_THREADSHIFT(cd, pmix_log_local_op); // function will release the caddy } /* List items for arrays to search */ typedef struct { pmix_list_item_t super; char *project; pmix_show_help_file_t *array; } tuple_array_item_t; static void tacon(tuple_array_item_t *p) { p->project = NULL; } static void tades(tuple_array_item_t *p) { if (NULL != p->project) { free(p->project); } } static PMIX_CLASS_INSTANCE(tuple_array_item_t, pmix_list_item_t, tacon, tades); // list of arrays to search static pmix_list_t data_arrays; /* List items for holding (filename, topic) tuples */ typedef struct { pmix_list_item_t super; /* The filename */ char *tli_filename; /* The topic */ char *tli_topic; /* List of process names that have displayed this (filename, topic) */ pmix_list_t tli_processes; /* Time this message was displayed */ time_t tli_time_displayed; /* Count of processes since last display (i.e., "new" processes that have showed this message that have not yet been output) */ int tli_count_since_last_display; /* Do we want to display these? */ bool tli_display; } tuple_list_item_t; static void tuple_list_item_constructor(tuple_list_item_t *obj) { obj->tli_filename = NULL; obj->tli_topic = NULL; PMIX_CONSTRUCT(&(obj->tli_processes), pmix_list_t); obj->tli_time_displayed = time(NULL); obj->tli_count_since_last_display = 0; obj->tli_display = true; } static void tuple_list_item_destructor(tuple_list_item_t *obj) { if (NULL != obj->tli_filename) { free(obj->tli_filename); } if (NULL != obj->tli_topic) { free(obj->tli_topic); } PMIX_LIST_DESTRUCT(&(obj->tli_processes)); } static PMIX_CLASS_INSTANCE(tuple_list_item_t, pmix_list_item_t, tuple_list_item_constructor, tuple_list_item_destructor); /* List of (filename, topic) tuples that have already been displayed */ static pmix_list_t abd_tuples; /* * Private variables */ static const char *dash_line = "--------------------------------------------------------------------------\n"; static pmix_status_t match(const char *a, const char *b) { int rc = PMIX_ERROR; char *p1, *p2, *tmp1 = NULL, *tmp2 = NULL; size_t min; /* Check straight string match first */ if (0 == strcmp(a, b)) return PMIX_SUCCESS; if (NULL != strchr(a, '*') || NULL != strchr(b, '*')) { tmp1 = strdup(a); if (NULL == tmp1) { return PMIX_ERR_OUT_OF_RESOURCE; } tmp2 = strdup(b); if (NULL == tmp2) { free(tmp1); return PMIX_ERR_OUT_OF_RESOURCE; } p1 = strchr(tmp1, '*'); p2 = strchr(tmp2, '*'); if (NULL != p1) { *p1 = '\0'; } if (NULL != p2) { *p2 = '\0'; } min = strlen(tmp1); if (strlen(tmp2) < min) { min = strlen(tmp2); } if (0 == min || 0 == strncmp(tmp1, tmp2, min)) { rc = PMIX_SUCCESS; } free(tmp1); free(tmp2); return rc; } /* No match */ return PMIX_ERROR; } static pmix_status_t pmix_get_tli(const char *filename, const char *topic, tuple_list_item_t **tli_) { tuple_list_item_t *tli; /* Search the list for a duplicate. */ PMIX_LIST_FOREACH(tli, &abd_tuples, tuple_list_item_t) { if (PMIX_SUCCESS == match(tli->tli_filename, filename) && PMIX_SUCCESS == match(tli->tli_topic, topic)) { *tli_ = tli; return PMIX_SUCCESS; } } /* Nope, we didn't find it -- make a new one */ tli = PMIX_NEW(tuple_list_item_t); if (NULL == tli) { return PMIX_ERR_OUT_OF_RESOURCE; } tli->tli_filename = strdup(filename); tli->tli_topic = strdup(topic); pmix_list_append(&abd_tuples, &(tli->super)); *tli_ = tli; return PMIX_ERR_NOT_FOUND; } static void pmix_show_accumulated_duplicates(int fd, short event, void *context) { time_t now = time(NULL); tuple_list_item_t *tli; char *tmp; PMIX_HIDE_UNUSED_PARAMS(fd, event, context); /* Loop through all the messages we've displayed and see if any processes have sent duplicates that have not yet been displayed yet */ PMIX_LIST_FOREACH(tli, &abd_tuples, tuple_list_item_t) { if (tli->tli_display && tli->tli_count_since_last_display > 0) { static bool first = true; pmix_asprintf(&tmp, "%d more process%s sent help message %s / %s\n", tli->tli_count_since_last_display, (tli->tli_count_since_last_display > 1) ? "es have" : " has", tli->tli_filename, tli->tli_topic); tli->tli_time_displayed = time(NULL); char stamp[50] = {0}; strftime(stamp, 50, "%Y-%m-%d %H:%M:%S", localtime(&tli->tli_time_displayed)); char *buf; pmix_asprintf(&buf, "%s-%s", tli->tli_filename, stamp); local_delivery(buf, tli->tli_topic, tmp); free(buf); tli->tli_count_since_last_display = 0; if (first) { pmix_asprintf(&tmp, "%s", "Set MCA parameter \"base_help_aggregate\" to 0 to see all help / error messages\n"); local_delivery(tli->tli_filename, tli->tli_topic, tmp); first = false; } } } show_help_time_last_displayed = now; show_help_timer_set = false; } pmix_status_t pmix_help_check_dups(const char *filename, const char *topic) { tuple_list_item_t *tli; time_t now = time(NULL); int rc; rc = pmix_get_tli(filename, topic, &tli); if (PMIX_SUCCESS == rc) { /* Already displayed! But do we want to print anything? That's complicated. We always show the first message of a given (filename, topic) tuple as soon as it arrives. But we don't want to show duplicate notices often, because we could get overrun with them. So we want to gather them up and say "We got N duplicates" every once in a while. And keep in mind that at termination, we'll unconditionally show all accumulated duplicate notices. A simple scheme is as follows: - when the first of a (filename, topic) tuple arrives - print the message - if a timer is not set, set T=now - when a duplicate (filename, topic) tuple arrives - if now>(T+5) and timer is not set (due to non-pre-emptiveness of our libevent, a timer *could* be set!) - print all accumulated duplicates - reset T=now - else if a timer was not set, set the timer for T+5 - else if a timer was set, do nothing (just wait) - set T=now when the timer expires */ ++tli->tli_count_since_last_display; if (now > show_help_time_last_displayed + 5 && !show_help_timer_set) { pmix_show_accumulated_duplicates(0, 0, NULL); } if (!show_help_timer_set) { pmix_event_evtimer_set(pmix_globals.evbase, &show_help_timer_event, pmix_show_accumulated_duplicates, NULL); pmix_event_evtimer_add(&show_help_timer_event, &show_help_interval); show_help_timer_set = true; } } /* Not already displayed */ else if (PMIX_ERR_NOT_FOUND == rc) { if (!show_help_timer_set) { show_help_time_last_displayed = now; } } else { /* Some other error occurred */ PMIX_ERROR_LOG(rc); return rc; } return rc; } /* * Local functions */ pmix_status_t pmix_show_help_init(void) { pmix_output_stream_t lds; tuple_array_item_t *da; if (pmix_show_help_initialized) { return PMIX_SUCCESS; } PMIX_CONSTRUCT(&lds, pmix_output_stream_t); lds.lds_want_stderr = true; output_stream = pmix_output_open(&lds); PMIX_CONSTRUCT(&abd_tuples, pmix_list_t); PMIX_CONSTRUCT(&data_arrays, pmix_list_t); da = PMIX_NEW(tuple_array_item_t); da->project = strdup("pmix"); da->array = pmix_show_help_data; pmix_list_append(&data_arrays, &da->super); pmix_show_help_initialized = true; return PMIX_SUCCESS; } pmix_status_t pmix_show_help_finalize(void) { if (!pmix_show_help_initialized) { return PMIX_SUCCESS; } pmix_output_close(output_stream); output_stream = -1; PMIX_LIST_DESTRUCT(&abd_tuples); PMIX_LIST_DESTRUCT(&data_arrays); pmix_show_help_initialized = false; return PMIX_SUCCESS; } /* * Make one big string with all the lines. This isn't the most * efficient method in the world, but we're going for clarity here -- * not optimization. :-) */ static pmix_status_t array2string(char **outstring, int want_error_header, char **lines) { int i, count; size_t len; /* See how much space we need */ len = want_error_header ? 2 * strlen(dash_line) : 0; count = PMIx_Argv_count((char**)lines); for (i = 0; i < count; ++i) { if (NULL == lines[i]) { break; } len += strlen(lines[i]) + 1; } /* Malloc it out */ (*outstring) = (char *) calloc((len + 1), sizeof(char)); if (NULL == *outstring) { return PMIX_ERR_OUT_OF_RESOURCE; } /* Fill the big string */ *(*outstring) = '\0'; if (want_error_header) { strcat(*outstring, dash_line); } for (i = 0; i < count; ++i) { if (NULL == lines[i]) { break; } strcat(*outstring, lines[i]); strcat(*outstring, "\n"); } if (want_error_header) { strcat(*outstring, dash_line); } return PMIX_SUCCESS; } static void get_content(char ***output, char *project, const char *filename, const char* topic) { tuple_array_item_t *da; pmix_show_help_file_t *fe; pmix_show_help_entry_t *ie; int i, j, m; char *p, *tp, *file, *pj, *line; if (!pmix_show_help_initialized || NULL == project || 0 == strcmp(project, "pmix")) { // restrict to local array for (i = 0; NULL != pmix_show_help_data[i].filename; ++i) { fe = &(pmix_show_help_data[i]); if (0 == strcmp(fe->filename, filename)) { for (j = 0; NULL != fe->entries[j].topic; ++j) { ie = &(fe->entries[j]); if (0 == strcmp(ie->topic, topic)) { // found a matching entry for (m=0; NULL != ie->content[m]; m++) { if (0 == strncmp(ie->content[m], "#include", strlen("#include"))) { // parse the project (if provided), file and topic being included p = strrchr(ie->content[m], '#'); tp = p + 1; --p; p = strrchr(p, '#'); file = p + 1; --p; // project can only be "pmix" get_content(output, "pmix", file, tp); } else { PMIx_Argv_append_nosize(output, ie->content[m]); } } return; } } } } // if we didn't find an entry and the project is NULL and // we are initialized, then check the other projects if (pmix_show_help_initialized && NULL == project) { goto next; } return; } next: PMIX_LIST_FOREACH(da, &data_arrays, tuple_array_item_t) { if (NULL != project && 0 != strcmp(project, da->project)) { continue; } for (i = 0; NULL != da->array[i].filename; ++i) { fe = &(da->array[i]); if (0 == strcmp(fe->filename, filename)) { for (j = 0; NULL != fe->entries[j].topic; ++j) { ie = &(fe->entries[j]); if (0 == strcmp(ie->topic, topic)) { for (m=0; NULL != ie->content[m]; m++) { if (0 == strncmp(ie->content[m], "#include", strlen("#include"))) { line = strdup(ie->content[m]); // parse the project (if provided), file and topic being included p = strrchr(line, '#'); *p = '\0'; tp = p + 1; p = strrchr(line, '#'); *p = '\0'; file = p + 1; p = strrchr(line, '#'); ++p; // if this isn't pointing at "include", then it must be a project if (0 != strncmp(p, "include", strlen("include"))) { pj = p; } else { pj = da->project; } get_content(output, pj, file, tp); free(line); } else { PMIx_Argv_append_nosize(output, ie->content[m]); } } return; } } } } } } char *pmix_show_help_vstring(const char *filename, const char *topic, int want_error_header, va_list arglist) { int rc; char *single_string, *output; char **content = NULL; char *msg; /* Load the message */ get_content(&content, NULL, filename, topic); if (NULL == content) { pmix_asprintf(&msg, "%sSorry! You were supposed to get help about:\n\n Filename: %s\n Topic: %s\n\nBut I couldn't find " "that help reference.\n\nSorry!\n%s", dash_line, filename, topic, dash_line); local_delivery(filename, topic, msg); free(msg); return NULL; } /* Convert it to a single raw string */ rc = array2string(&single_string, want_error_header, content); PMIx_Argv_free(content); if (PMIX_SUCCESS == rc) { /* Apply the formatting to make the final output string */ if (0 > vasprintf(&output, single_string, arglist)) { output = NULL; } free(single_string); } return (PMIX_SUCCESS == rc) ? output : NULL; } char *pmix_show_help_string(const char *filename, const char *topic, int want_error_handler, ...) { char *output; va_list arglist; va_start(arglist, want_error_handler); output = pmix_show_help_vstring(filename, topic, want_error_handler, arglist); va_end(arglist); return output; } pmix_status_t pmix_show_help(const char *filename, const char *topic, int want_error_header, ...) { va_list arglist; char *output; va_start(arglist, want_error_header); output = pmix_show_help_vstring(filename, topic, want_error_header, arglist); va_end(arglist); /* If nothing came back, there's nothing to do */ if (NULL == output) { return PMIX_SUCCESS; } local_delivery(filename, topic, output); return PMIX_SUCCESS; } pmix_status_t pmix_show_help_add_data(const char *project, pmix_show_help_file_t *array) { tuple_array_item_t *da; pmix_show_help_file_t *fe; int i, j; // check for duplicate entries PMIX_LIST_FOREACH(da, &data_arrays, tuple_array_item_t) { for (i = 0; NULL != da->array[i].filename; ++i) { fe = &(da->array[i]); for (j=0; NULL != array[j].filename; j++) { if (0 == strcmp(fe->filename, array[j].filename)) { // complain pmix_show_help("help-pmix-util.txt", "duplicate-filename", true, project, da->project, fe->filename); return PMIX_ERROR; } } } } da = PMIX_NEW(tuple_array_item_t); da->project = strdup(project); da->array = array; pmix_list_append(&data_arrays, &da->super); return PMIX_SUCCESS; } pmix_status_t pmix_show_help_norender(const char *filename, const char *topic, const char *output) { local_delivery(filename, topic, output); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/util/pmix_argv.c0000664000175000017500000002110515203536752017400 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Voltaire. All rights reserved. * Copyright (c) 2012 Los Alamos National Security, LLC. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_STDLIB_H # include #endif /* HAVE_STDLIB_H */ #ifdef HAVE_STRING_H # include #endif /* HAVE_STRING_H */ #include "pmix.h" #include "src/util/pmix_argv.h" #define ARGSIZE 128 /* * Append a string to the end of a new or existing argv array. */ pmix_status_t pmix_argv_append(int *argc, char ***argv, const char *arg) { pmix_status_t rc; /* add the new element */ if (PMIX_SUCCESS != (rc = PMIx_Argv_append_nosize(argv, arg))) { return rc; } *argc = PMIx_Argv_count(*argv); return PMIX_SUCCESS; } pmix_status_t pmix_argv_append_unique_idx(int *idx, char ***argv, const char *arg) { int i; pmix_status_t rc; /* if the provided array is NULL, then the arg cannot be present, * so just go ahead and append */ if (NULL == *argv) { goto add; } /* see if this arg is already present in the array */ for (i = 0; NULL != (*argv)[i]; i++) { if (0 == strcmp(arg, (*argv)[i])) { /* already exists */ *idx = i; return PMIX_SUCCESS; } } add: if (PMIX_SUCCESS != (rc = PMIx_Argv_append_nosize(argv, arg))) { return rc; } *idx = PMIx_Argv_count(*argv) - 1; return PMIX_SUCCESS; } /* * Join all the elements of an argv array from within a * specified range into a single newly-allocated string. */ char *pmix_argv_join_range(char **argv, size_t start, size_t end, int delimiter) { char **p; char *pp; char *str; size_t str_len = 0; size_t i; /* Bozo case */ if (NULL == argv || NULL == argv[0] || (int) start >= PMIx_Argv_count(argv)) { return strdup(""); } /* Find the total string length in argv including delimiters. The last delimiter is replaced by the NULL character. */ for (p = &argv[start], i = start; *p && i < end; ++p, ++i) { str_len += strlen(*p) + 1; } if (0 == str_len) { return strdup(""); } /* Allocate the string. */ if (NULL == (str = (char *) calloc(str_len, sizeof(char)))) { return NULL; } /* Loop filling in the string. */ str[--str_len] = '\0'; p = &argv[start]; pp = *p; for (i = 0; i < str_len; ++i) { if ('\0' == *pp) { /* End of a string, fill in a delimiter and go to the next string. */ str[i] = (char) delimiter; ++p; pp = *p; } else { str[i] = *pp++; } } /* All done */ return str; } /* * Return the number of bytes consumed by an argv array. */ size_t pmix_argv_len(char **argv) { char **p; size_t length; if (NULL == argv) return (size_t) 0; length = sizeof(char *); for (p = argv; *p; ++p) { length += strlen(*p) + 1 + sizeof(char *); } return length; } /* * Copy a NULL-terminated argv array, stripping any leading/trailing * quotes from each element */ char **pmix_argv_copy_strip(char **argv) { char **dupv = NULL; int n; char *start; bool mod; size_t len; if (NULL == argv) { return NULL; } /* create an "empty" list, so that we return something valid if we were passed a valid list with no contained elements */ dupv = (char **) malloc(sizeof(char *)); dupv[0] = NULL; for (n=0; NULL != argv[n]; n++) { mod = false; start = argv[n]; if ('\"' == argv[n][0]) { ++start; } len = strlen(argv[n]); if ('\"' == argv[n][len-1]) { argv[n][len-1] = '\0'; mod = true; } if (PMIX_SUCCESS != PMIx_Argv_append_nosize(&dupv, start)) { PMIx_Argv_free(dupv); if (mod) { argv[n][len-1] = '\"'; } return NULL; } if (mod) { argv[n][len-1] = '\"'; } } /* All done */ return dupv; } pmix_status_t pmix_argv_delete(int *argc, char ***argv, int start, int num_to_delete) { int i; int count; int suffix_count; char **tmp; /* Check for the bozo cases */ if (NULL == argv || NULL == *argv || 0 == num_to_delete) { return PMIX_SUCCESS; } count = PMIx_Argv_count(*argv); if (start > count) { return PMIX_SUCCESS; } else if (start < 0 || num_to_delete < 0) { return PMIX_ERR_BAD_PARAM; } /* Ok, we have some tokens to delete. Calculate the new length of the argv array. */ suffix_count = count - (start + num_to_delete); if (suffix_count < 0) { suffix_count = 0; } /* Free all items that are being deleted */ for (i = start; i < count && i < start + num_to_delete; ++i) { free((*argv)[i]); } /* Copy the suffix over the deleted items */ for (i = start; i < start + suffix_count; ++i) { (*argv)[i] = (*argv)[i + num_to_delete]; } /* Add the trailing NULL */ (*argv)[i] = NULL; /* adjust the argv array */ tmp = (char **) realloc(*argv, sizeof(char *) * (i + 1)); if (NULL != tmp) *argv = tmp; /* adjust the argc */ (*argc) -= num_to_delete; return PMIX_SUCCESS; } pmix_status_t pmix_argv_insert(char ***target, int start, char **source) { int i, source_count, target_count; int suffix_count; /* Check for the bozo cases */ if (NULL == target || NULL == *target || start < 0) { return PMIX_ERR_BAD_PARAM; } else if (NULL == source) { return PMIX_SUCCESS; } /* Easy case: appending to the end */ target_count = PMIx_Argv_count(*target); source_count = PMIx_Argv_count(source); if (start > target_count) { for (i = 0; i < source_count; ++i) { pmix_argv_append(&target_count, target, source[i]); } } /* Harder: insertting into the middle */ else { /* Alloc out new space */ *target = (char **) realloc(*target, sizeof(char *) * (target_count + source_count + 1)); /* Move suffix items down to the end */ suffix_count = target_count - start; for (i = suffix_count - 1; i >= 0; --i) { (*target)[start + source_count + i] = (*target)[start + i]; } (*target)[start + suffix_count + source_count] = NULL; /* Strdup in the source argv */ for (i = start; i < start + source_count; ++i) { (*target)[i] = strdup(source[i - start]); } } /* All done */ return PMIX_SUCCESS; } pmix_status_t pmix_argv_insert_element(char ***target, int location, char *source) { int i, target_count; int suffix_count; /* Check for the bozo cases */ if (NULL == target || NULL == *target || location < 0) { return PMIX_ERR_BAD_PARAM; } else if (NULL == source) { return PMIX_SUCCESS; } /* Easy case: appending to the end */ target_count = PMIx_Argv_count(*target); if (location > target_count) { pmix_argv_append(&target_count, target, source); return PMIX_SUCCESS; } /* Alloc out new space */ *target = (char **) realloc(*target, sizeof(char *) * (target_count + 2)); /* Move suffix items down to the end */ suffix_count = target_count - location; for (i = suffix_count - 1; i >= 0; --i) { (*target)[location + 1 + i] = (*target)[location + i]; } (*target)[location + suffix_count + 1] = NULL; /* Strdup in the source */ (*target)[location] = strdup(source); /* All done */ return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/util/convert-help.py0000775000175000017500000005716515203536752020242 0ustar alastairalastair#!/usr/bin/env python3 # # Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved. # Copyright (c) 2025-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # from __future__ import print_function import os import sys import argparse def parse_cmd_line_options(path, verbose=False): # read the file and parse it for options options = [] with open(path) as file: for line in file: stripped = line.strip() if stripped.startswith("#define"): # find the first space at end of "define" s1 = stripped.find(' ') # first word after "#define " is the name of the option start = 8 end = stripped.find(' ', start+1) if -1 == end: continue name = stripped[start:end] # find the first quote mark start = stripped.find('"', end) if start != -1: # find the ending quote mark end = stripped.find('"', start+1) # everything in-between is the actual option opt = stripped[start+1:end] # track it options.append((name, opt)) return options def find_files(root, verbose=False): # Check for existence of root directory - otherwise, we just # fall through with no error output if not os.path.isdir(root): sys.stderr.write("Root directory " + root + " does not exist\nCannot continue\n") exit(1) # Search for help-*.txt files across the source tree, skipping # some directories (e.g., .git) # Also find and retrieve all source files (.h or .c) # so we can search them for entries help_files = [] source_files = [] tool_help_files = [] tool_source_files = [] # skip infrastructure directories skip_dirs = ['.git', '.libs', '.deps'] # there may also be some help files we want to ignore skip_files = [] for root_dir, dirs, files in os.walk(root): for sd in skip_dirs: if sd in dirs: dirs.remove(sd) for file in files: if file.startswith("help-") and file.endswith(".txt"): skipit = False for sf in skip_files: if sf == file: skipit = True break if not skipit: full_path = os.path.join(root_dir, file) if "tools" in full_path: tool_help_files.append(full_path) if verbose: print("Found tool help: {full_path}".format(full_path=full_path)) else: help_files.append(full_path) if verbose: print("Found help: {full_path}".format(full_path=full_path)) elif file.endswith(".c") or file.endswith(".h"): full_path = os.path.join(root_dir, file) if "tools" in full_path: tool_source_files.append(full_path) else: source_files.append(full_path) if verbose: print("Found source: {full_path}".format(full_path=full_path)) return help_files, source_files, tool_help_files, tool_source_files def parse_help_files(file_paths, data, citations, verbose=False): # Parse INI-style help files, returning a dictionary with filenames as # keys. Don't use the Python configparse module in order to # reduce dependencies (i.e., so that we don't have to pip install # anything to run this script). for file_path in file_paths: sections = {} current_section = None with open(file_path) as file: for line in file: stripped = line.strip() if stripped.startswith("#include"): # if we aren't in a section, then this is an error if current_section is None: sys.stderr.write("ERROR: INCLUDE is specified in ", file_path, " outside of a section") continue # include the line in the section sections[current_section].append(stripped) # this line includes a file/topic from another file # find the '#' at the end of the "include" keyword start = stripped.find('#', 2) if start != -1: # find the '#'' at the end of the filename end = stripped.find('#', start+1) end2 = stripped.find('#', end+1) if end2 == -1: topic = stripped[end+1:] fil = stripped[start+1:end] citations.append((fil, topic)) else: topic = stripped[end2+1:] fil = stripped[end+1:end2] citations.append((fil, topic)) # if a section contains an include, we treat that # section as having been cited citations.append((os.path.basename(file_path), current_section)) continue if stripped.startswith('#'): current_section = None continue if current_section is None and not stripped: continue if stripped.startswith('['): # find the end of the section name end = stripped.find(']', 1) if -1 == end: continue current_section = stripped[1:end] sections[current_section] = list() elif current_section is not None: sections[current_section].append(stripped) if file_path in data: sys.stderr.write("ERROR: path " + file_path + " already exists in data dictionary\n") else: data[file_path] = sections if verbose: p = len(sections) print("Parsed: {file_path} ({p} sections found)".format(file_path=file_path, p=p)) return def parse_src_files(source_files, citations, verbose=False): # search the source code for show_help references for src in source_files: cont_topic = False cont_filename = False with open(src) as file: for line in file: line = line.strip() # skip the obvious comment lines if line.startswith("//") or line.startswith("/*") or line.startswith('*') or line.startswith("PMIX_EXPORT"): continue if cont_topic: # the topic for the prior filename should be on this line if verbose: print("CONT TOPIC LINE: ", line) start = line.find('"') if start != -1: end = line.find('"', start+1, -1) if end != -1: topic = line[start+1:end] citations.append((filename,topic)) if verbose: print("Found topic: ", filename, topic) cont_topic = False continue elif cont_filename: # the filename should be on this line if verbose: print("CONT FILENAME LINE: ", line) start = line.find('"') if start != -1: end = line.find('"', start+1, -1) if end != -1: filename = line[start+1:end] # see if the topic is on the same line start = line.find('"', end+1, -1) if start != -1: # find the end of it end = line.find('"', start+1, -1) if end != -1: topic = line[start+1:end] if verbose: print("Found all: ", filename, topic) citations.append((filename,topic)) else: # topic must be on next line cont_topic = True if verbose: print("Found filename: ", filename) cont_filename = False continue else: cont_filename = False sys.stderr.write("ERROR: Missing end of filename\n") continue if ("pmix_show_help(" in line and not "pmix_status_t" in line) or \ ("pmix_show_help_string(" in line and not "char *" in line) or \ ("send_error_show_help(" in line and not "void" in line): cont_topic = False cont_filename = False # line contains call to show-help - try to extract # filename/topic if verbose: print("LINE: ", line) start = line.find('"') if start != -1: end = line.find('"', start+1, -1) if end != -1: filename = line[start+1:end] # see if the topic is on this line start = line.find('"', end+1, -1) if start != -1: # find the end of it end = line.find('"', start+1, -1) if end != -1: topic = line[start+1:end] if verbose: print("Found all: ", filename, topic) citations.append((filename,topic)) else: # topic must be on next line cont_topic = True continue else: # the filename must be on next line cont_filename = True continue return def parse_tool_files(help_files, source_files, cli_options, citations, verbose=False): # cycle through the tool help files for hlp in help_files: topics = [] options = [] cli = [] local_cli = [] insection = False # scan the help file to find cmd line options that # are referenced in the help file itself with open(hlp) as file: for line in file: line = line.strip() if not line: continue if line.startswith('#'): insection = False continue if line.startswith('[') and line.endswith(']'): # topic - save it start = line.find('[') + 1 end = line.find(']') topic = line[start:end] topics.append(topic) if topic != "usage": insection = True continue if not insection: # scan the line for the "--" that indicates a cmd line option opt = line.find("--") if -1 == opt: continue # opt now points to the "--" in front of the option opt += 2 optend = line.find(' ', opt+1) option = line[opt:optend] # track the option options.append(option) # get the name of the tool this help file belongs to d = os.path.basename(hlp) # find the start of the tool name start = d.find('-') + 1 end = d.find('.', start) tool = d[start:end] # search the source files for the corresponding tool # note that we need to look at .c AND .h files for definitions found = False for src in source_files: f = os.path.basename(src) end = f.find('.') tsrc = f[0:end] if tool == tsrc: found = True # search this source for cmd line options with open(src) as srcfile: for lsrc in srcfile: lsrc = lsrc.strip() if lsrc.startswith("#define PMIX_CLI"): # defining a local option # find the first space at end of "define" s1 = lsrc.find(' ') # first word after "#define " is the name of the option start = 8 end = lsrc.find(' ', start+1) if -1 == end: continue name = lsrc[start:end] # find the first quote mark start = lsrc.find('"', end) if start != -1: # find the ending quote mark end = lsrc.find('"', start+1) # everything in-between is the actual option opt = lsrc[start+1:end] # track it local_cli.append((name, opt)) elif lsrc.startswith("PMIX_OPTION_") and lsrc != "PMIX_OPTION_END": # the option name starts with PMIX_CLI start = lsrc.find("PMIX_CLI_") end = lsrc.find(",", start+1) # find the option in the global list so we can # compare it to the help file options cli.append(lsrc[start:end]) if not found: sys.stderr.write("WARNING: No corresponding source code found for help file " + hlp + "\n") exit(1) # convert the CLI to strings so we can check the options and topics clistrings = [] for c in cli: found = False # check local definitions first for l in local_cli: if c == l[0]: found = True clistrings.append(l[1]) break if not found: # check the global definitions for copt in cli_options: if c == copt[0]: found = True clistrings.append(copt[1]) break if not found: # unrecognized option sys.stderr.write("WARNING: Unrecognized command line option " + c + " in source code " + os.path.basename(src) + "\n") exit(1) # check the cli and options to ensure they match for option in options: found = False for c in clistrings: # there must be a CLI entry for every option if c == option: found = True break if not found: sys.stderr.write("WARNING: Option " + option + " has no corresponding CLI defined for " + tool + "\n") exit(1) # reverse must also be true for c in clistrings: # ignore "help", "version", and "verbose" as those are handled # by the PMIx cmd line processor if "help" == c or "version" == c or "verbose" == c: continue found = False for option in options: # must be an option in the help file for each CLI entry if c == option: found = True break if not found: sys.stderr.write("WARNING: CLI definition " + c + " has no corresponding help entry in " + os.path.basename(hlp) + "\n") exit(1) # also require that there be a topic for each option so that # "--help option" works. Note that "help", "version", and "verbose" # are special cases handled by the cmd line processor # scan the options for option in options: if option == "help" or option == "version" or option == "verbose": continue # scan the topics for a match found = False for topic in topics: if option == topic: if verbose: print("CITED ", os.path.basename(hlp), option) found = True citations.append((os.path.basename(hlp), option)) break if not found: sys.stderr.write("WARNING: Option " + option + " has no topic entry in " + os.path.basename(hlp) + "\n") def purge(parsed_data, citations): result_data = {} errorFound = False for filename in parsed_data: # tools were processed separately sections = parsed_data[filename] if "tools" in filename: result_data[filename] = sections continue result_sections = {} for section in sections: content_list = sections[section] # check for duplicate entries content = '\n'.join(content_list) # search all other entries for a matching section for (file2, sec) in parsed_data.items(): if file2 == filename: continue for (sec2, cl) in sec.items(): cnt = '\n'.join(cl) if sec == section: if content == cnt: # these are the same sys.stderr.write("DUPLICATE FOUND - SECTION: " + section + "\nFILES: " + filename + "\n " + file2 + "\n") errorFound = True else: # same topic, different content sys.stderr.write("DUPLICATE SECTION WITH DIFFERENT CONTENT: " + section, "\nFILES: " + filename + "\n " + file2 + "\n") errorFound = True # search code files for usage # protect special values if section == "help" or section == "version" or section == "usage": result_sections[section] = content_list continue for entry in citations: used = False file2 = entry[0] sec = entry[1] if file2 == os.path.basename(filename) and sec == section: # this is a used entry result_sections[section] = content_list used = True break; if not used: sys.stderr.write("** WARNING: Unused help topic\n") sys.stderr.write(" File: " + filename + "\n") sys.stderr.write(" Section: " + section + "\n") errorFound = True # see if anything is left if 0 < len(result_sections): # don't retain the file if no citations for it are left result_data[filename] = result_sections else: sys.stderr.write("File " + filename + "has no used topics - omitting\n") errorFound = True if errorFound: exit(1) return result_data def generate_c_code(parsed_data): # Generate C code with an array of filenames and their # corresponding INI sections. c_code = "// THIS FILE IS GENERATED AUTOMATICALLY! EDITS WILL BE LOST!\n// This file generated by " + os.path.basename(sys.argv[0]) + "\n\n" c_code += "#include \"src/include/pmix_config.h\"\n#include \n#include \n\n#include \"src/include/pmix_globals.h\"\n\n" ini_arrays = [] file_entries = [] for idx, (fil, sections) in enumerate(sorted(parsed_data.items())): filename = os.path.basename(fil) var_name = filename.replace('-', '_').replace('.', '_') ini_entries = [] for section, content_list in sections.items(): entry = " { .topic = \"" + section + "\",\n .content = (const char *[]){\n" for content in content_list: c_content = content.replace('"','\\"').replace("\n", '\\n"\n"').replace("\\;", ";") entry += " \"" + c_content + "\",\n" entry += " NULL}\n },\n" ini_entries.append(entry) ini_entries.append(" { .topic = NULL, .content = NULL }") ini_array_name = "ini_entries_" + str(idx) ini_arrays.append("static pmix_show_help_entry_t " + ini_array_name + "[] = {\n" + "\n".join(ini_entries) + "\n};\n") file_entries.append(" { \"" + filename + "\", " + ini_array_name + "}") file_entries.append(" { NULL, NULL }") c_code += "\n".join(ini_arrays) + "\n" c_code += "pmix_show_help_file_t pmix_show_help_data[] = {\n" + ",\n".join(file_entries) + "\n};\n" return c_code #------------------------------- def main(): parser = argparse.ArgumentParser(description="Generate C code from help text INI files.") parser.add_argument("--root", required=True, help="Root directory to search for help-*.txt files") parser.add_argument("--out", required=True, help="Output C file") parser.add_argument("--verbose", action="store_true", help="Enable verbose output") parser.add_argument("--purge", action="store_true", help="Purge duplicates, update topic pointers as required") parser.add_argument("--dryrun", action="store_true", help="Do not write out resulting ini_array_name") args = parser.parse_args() parsed_data = {} citations = [] cli_options = [] outdata = {} rootdir = os.path.join(args.root, "src") # the options are in root/util/pmix_cmd_line.h path = os.path.join(rootdir, "util", "pmix_cmd_line.h") if not os.path.exists(path): sys.stderr.write("File " + path + " does not exist\nCannot continue\n") exit(1) # obtain a list of (option name, string) tuples cli_options = parse_cmd_line_options(path, args.verbose) help_files, source_files, tool_help_files, tool_source_files = find_files(rootdir, args.verbose) parse_help_files(help_files, parsed_data, citations, args.verbose) parse_help_files(tool_help_files, parsed_data, citations, args.verbose) parse_src_files(source_files, citations, args.verbose) parse_tool_files(tool_help_files, tool_source_files, cli_options, citations, args.verbose) if args.purge: outdata = purge(parsed_data, citations) else: outdata = parsed_data if not args.dryrun: c_code = generate_c_code(outdata) with open(args.out, "w") as f: f.write(c_code) if args.verbose: print("Generated C code written to ", args.out) if __name__ == "__main__": main() pmix-6.1.1~rc2/src/util/pmix_output.h0000664000175000017500000004571215203536752020020 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file * PMIX output stream facility. * * The PMIX output stream facility is used to send output from the PMIX * libraries to output devices. It is meant to fully replace all * forms of printf() (and friends). Output streams are opened via the * pmix_output_open() function call, and then sent output via * pmix_output_verbose(), PMIX_OUTPUT(), and pmix_output(). Streams are * closed with pmix_output_close(). * * Streams can multiplex output to several kinds of outputs (one of * each): * * - the syslog (if available) * - standard output * - standard error * - file * * Which outputs to use are specified during pmix_output_open(). * * WARNING: When using "file" as an output destination, be aware that * the file may not exist until the session directory for the process * exists. This is at least part of the way through MPI_INIT (for * example). Most MCA components and internals of PMIx won't be * affected by this, but some RTE / startup aspects of PMIx will * not be able to write to a file for output. See pmix_output() for * details on what happens in these cases. * * pmix_output_open() returns an integer handle that is used in * successive calls to PMIX_OUTPUT() and pmix_output() to send output to * the stream. * * The default "verbose" stream is opened after invoking * pmix_output_init() (and closed after invoking * pmix_output_finalize()). This stream outputs to stderr only, and * has a stream handle ID of 0. * * It is erroneous to have one thread close a stream and have another * try to write to it. Multiple threads writing to a single stream * will be serialized in an unspecified order. */ #ifndef PMIX_OUTPUT_H_ #define PMIX_OUTPUT_H_ #include "src/include/pmix_config.h" #ifdef HAVE_STDARG_H # include #endif #include "src/class/pmix_object.h" BEGIN_C_DECLS #define PMIX_OUTPUT_MAX_STREAMS 64 /* There are systems where all output needs to be redirected to syslog * and away from stdout/stderr or files - e.g., embedded systems whose * sole file system is in flash. To support such systems, we provide * the following environmental variables that support redirecting -all- * output (both from pmix_output and stdout/stderr of processes) to * syslog: * * PMIX_OUTPUT_REDIRECT - set to "syslog" to redirect to syslog. Other * options may someday be supported * PMIX_OUTPUT_SYSLOG_PRI - set to "info", "error", or "warn" to have * output sent to syslog at that priority * PMIX_OUTPUT_SYSLOG_IDENT - a string identifier for the log * * We also define two global variables that notify all other * layers that output is being redirected to syslog at the given * priority. These are used, for example, by the IO forwarding * subsystem to tell it to dump any collected output directly to * syslog instead of forwarding it to another location. */ PMIX_EXPORT extern bool pmix_output_redirected_to_syslog; PMIX_EXPORT extern int pmix_output_redirected_syslog_pri; /** * \class pmix_output_stream_t * * Structure used to request the opening of a PMIX output stream. A * pointer to this structure is passed to pmix_output_open() to tell * the pmix_output subsystem where to send output for a given stream. * It is valid to specify multiple destinations of output for a stream * -- output streams can be multiplexed to multiple different * destinations through the pmix_output facility. * * Note that all strings in this struct are cached on the stream by * value; there is no need to keep them allocated after the return * from pmix_output_open(). */ struct pmix_output_stream_t { /** Class parent */ pmix_object_t super; /** * Indicate the starting verbosity level of the stream. * * Verbose levels are a convenience mechanisms, and are only * consulted when output is sent to a stream through the * pmix_output_verbose() function. Verbose levels are ignored in * PMIX_OUTPUT() and pmix_output(). * * Valid verbose levels typically start at 0 (meaning "minimal * information"). Higher verbosity levels generally indicate that * more output and diagnostics should be displayed. */ int lds_verbose_level; /** * When pmix_output_stream_t::lds_want_syslog is true, this field is * examined to see what priority output from the stream should be * sent to the syslog. * * This value should be set as per the syslog(3) man page. It is * typically the OR value of "facilty" and "level" values described * in the man page. */ int lds_syslog_priority; /** * When pmix_output_stream_t::lds_want_syslog is true, this field is * examined to see what ident value should be passed to openlog(3). * * If a NULL value is given, the string "pmix" is used. */ #if !defined(__WINDOWS__) char *lds_syslog_ident; #elif !defined(_MSC_VER) char *lds_syslog_ident; #else HANDLE lds_syslog_ident; #endif /* !defined(__WINDOWS__) */ /** * String prefix added to all output on the stream. * * When this field is non-NULL, it is prefixed to all lines of * output on the stream. When this field is NULL, no prefix is * added to each line of output in the stream. The prefix is copied * to an internal structure in the call to pmix_output_open()! */ char *lds_prefix; /** * String suffix added to all output on the stream. * * When this field is non-NULL, it is appended to all lines of * output on the stream. When this field is NULL, no suffix is * added to each line of output in the stream. The suffix is copied * to an internal structure in the call to pmix_output_open()! */ char *lds_suffix; /** * Indicates whether the output of the stream is * debugging/developer-only output or not. * * This field should be "true" if the output is for debugging * purposes only. In that case, the output will never be sent to * the stream unless PMIX was configured with --enable-debug. */ bool lds_is_debugging; /** * Indicates whether output of the stream should be sent to the * syslog or not. * * If this field is true, output from this stream is sent to the * syslog, and the following fields are also examined: * * - lds_syslog_priority * - lds_syslog_ident * - lds_prefix * * If this field is false, the above three fields are ignored. */ bool lds_want_syslog; /** * Whether to send stream output to stdout or not. * * If this field is true, stream output is sent to stdout. */ bool lds_want_stdout; /** * Whether to send stream output to stderr or not. * * If this field is true, stream output is sent to stderr. */ bool lds_want_stderr; /** * Whether to send stream output to a file or not. * * When this field is true, stream output is sent to a file, and the * following fields are also examined: * * - lds_want_file_append * - lda_file_suffix */ bool lds_want_file; /** * When pmix_output_stream_t::lds_want_file is true, this field * indicates whether to append the file (if it exists) or overwrite * it. * * If false, the file is opened with the O_TRUNC flag. */ bool lds_want_file_append; /** * When pmix_output_stream_t::lds_want_file is true, this field * indicates the string suffix to add to the filename. * * The output file will be in the directory and begin with the * prefix set by pmix_output_set_output_file_info() (e.g., * "$dir/$prefix$suffix"). If this field is NULL and * lds_want_file is true, then the suffix "output.txt" is used. * * Note that it is possible that the output directory may not * exist when pmix_output_open() is invoked. See pmix_output() * for details on what happens in this situation. */ char *lds_file_suffix; }; /** * Convenience typedef */ typedef struct pmix_output_stream_t pmix_output_stream_t; /* tracking structure */ typedef struct { bool ldi_used; bool ldi_enabled; int ldi_verbose_level; bool ldi_syslog; int ldi_syslog_priority; char *ldi_syslog_ident; char *ldi_prefix; int ldi_prefix_len; char *ldi_suffix; int ldi_suffix_len; bool ldi_stdout; bool ldi_stderr; bool ldi_file; bool ldi_file_want_append; char *ldi_file_suffix; int ldi_fd; int ldi_file_num_lines_lost; } pmix_output_desc_t; PMIX_EXPORT extern pmix_output_desc_t pmix_output_info[]; /** * Initializes the output stream system and opens a default * "verbose" stream. * * @retval true Upon success. * @retval false Upon failure. * * This should be the first function invoked in the output * subsystem. After this call, the default "verbose" stream is open * and can be written to via calls to pmix_output_verbose() and * pmix_output_error(). * * By definition, the default verbose stream has a handle ID of 0, * and has a verbose level of 0. */ PMIX_EXPORT bool pmix_output_init(void); /** * Shut down the output stream system. * * Shut down the output stream system, including the default verbose * stream. */ PMIX_EXPORT void pmix_output_finalize(void); /** * Opens an output stream. * * @param lds A pointer to pmix_output_stream_t describing what the * characteristics of the output stream should be. * * This function opens an output stream and returns an integer * handle. The caller is responsible for maintaining the handle and * using it in successive calls to PMIX_OUTPUT(), pmix_output(), * pmix_output_switch(), and pmix_output_close(). * * If lds is NULL, the default descriptions will be used, meaning * that output will only be sent to stderr. * * It is safe to have multiple threads invoke this function * simultaneously; their execution will be serialized in an * unspecified manner. * * Be sure to see pmix_output() for a description of what happens * when open_open() / pmix_output() is directed to send output to a * file but the process session directory does not yet exist. */ PMIX_EXPORT int pmix_output_open(pmix_output_stream_t *lds); /** * Re-opens / redirects an output stream. * * @param output_id Stream handle to reopen * @param lds A pointer to pmix_output_stream_t describing what the * characteristics of the reopened output stream should be. * * This function redirects an existing stream into a new [set of] * location[s], as specified by the lds parameter. If the output_id * passed is invalid, this call is effectively the same as opening a * new stream with a specific stream handle. */ PMIX_EXPORT int pmix_output_reopen(int output_id, pmix_output_stream_t *lds); /** * Enables and disables output streams. * * @param output_id Stream handle to switch * @param enable Boolean indicating whether to enable the stream * output or not. * * @returns The previous enable state of the stream (true == enabled, * false == disabled). * * The output of a stream can be temporarily disabled by passing an * enable value to false, and later resumed by passing an enable * value of true. This does not close the stream -- it simply tells * the pmix_output subsystem to intercept and discard any output sent * to the stream via PMIX_OUTPUT() or pmix_output() until the output * is re-enabled. */ PMIX_EXPORT bool pmix_output_switch(int output_id, bool enable); /** * \internal * * Reopens all existing output streams. * * This function should never be called by user applications; it is * typically only invoked after a restart (i.e., in a new process) * where output streams need to be re-initialized. */ PMIX_EXPORT void pmix_output_reopen_all(void); /** * Close an output stream. * * @param output_id Handle of the stream to close. * * Close an output stream. No output will be sent to the stream * after it is closed. Be aware that pmix_output_handles tend to be * re-used; it is possible that after a stream is closed, if another * stream is opened, it will get the same handle value. */ PMIX_EXPORT void pmix_output_close(int output_id); /** * Main function to send output to a stream. * * @param output_id Stream id returned from pmix_output_open(). * @param format printf-style format string. * @param varargs printf-style varargs list to fill the string * specified by the format parameter. * * This is the main function to send output to custom streams (note * that output to the default "verbose" stream is handled through * pmix_output_verbose() and pmix_output_error()). * * It is never necessary to send a trailing "\n" in the strings to * this function; some streams requires newlines, others do not -- * this function will append newlines as necessary. * * Verbosity levels are ignored in this function. * * Note that for output streams that are directed to files, the * files are stored under the process' session directory. If the * session directory does not exist when pmix_output() is invoked, * the output will be discarded! Once the session directory is * created, pmix_output() will automatically create the file and * writing to it. */ PMIX_EXPORT void pmix_output(int output_id, const char *format, ...) __pmix_attribute_format__(__printf__, 2, 3); /** * Send output to a stream only if the passed verbosity level is * high enough. * * @param output_id Stream id returned from pmix_output_open(). * @param level Target verbosity level. * @param format printf-style format string. * @param varargs printf-style varargs list to fill the string * specified by the format parameter. * * Output is only sent to the stream if the current verbosity level * is greater than or equal to the level parameter. This mechanism * can be used to send "information" kinds of output to user * applications, but only when the user has asked for a high enough * verbosity level. * * It is never necessary to send a trailing "\n" in the strings to * this function; some streams requires newlines, others do not -- * this function will append newlines as necessary. * * This function is really a convenience wrapper around checking the * current verbosity level set on the stream, and if the passed * level is less than or equal to the stream's verbosity level, this * function will effectively invoke pmix_output to send the output to * the stream. * * @see pmix_output_set_verbosity() */ #define pmix_output_verbose(level, output_id, ...) \ if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS && \ pmix_output_info[output_id].ldi_verbose_level >= level) { \ pmix_output(output_id, __VA_ARGS__); \ } /* protect legacy users */ #define PMIX_OUTPUT_VERBOSE(a) pmix_output_verbose a #define PMIX_OUTPUT(a) pmix_output a /** * Set the verbosity level for a stream. * * @param output_id Stream id returned from pmix_output_open(). * @param level New verbosity level * * This function sets the verbosity level on a given stream. It * will be used for all future invocations of pmix_output_verbose(). */ PMIX_EXPORT void pmix_output_set_verbosity(int output_id, int level); /** * Get the verbosity level for a stream * * @param output_id Stream id returned from pmix_output_open() * @returns Verbosity of stream */ PMIX_EXPORT int pmix_output_get_verbosity(int output_id); /** * Set characteristics for output files. * * @param dir Directory where output files will go * @param olddir If non-NULL, the directory where output files * were previously opened * @param prefix Prefix of files in the output directory * @param oldprefix If non-NULL, the old prefix * * This function controls the final filename used for all new * output streams that request output files. Specifically, when * pmix_output_stream_t::lds_want_file is true, the output * filename will be of the form $dir/$prefix$suffix. * * The default value for the output directory is whatever is * specified in the TMPDIR environment variable if it exists, or * $HOME if it does not. The default value for the prefix is * "output-pid-" (where "" is replaced by the PID of the * current process). * * If dir or prefix are NULL, new values are not set. The strings * represented by dir and prefix are copied into internal storage; * it is safe to pass string constants or free() these values * after pmix_output_set_output_file_info() returns. * * If olddir or oldprefix are not NULL, copies of the old * directory and prefix (respectively) are returned in these * parameters. The caller is responsible for calling (free) on * these values. This allows one to get the old values, output an * output file in a specific directory and/or with a specific * prefix, and then restore the old values. * * Note that this function only affects the creation of \em new * streams -- streams that have already started writing to output * files are not affected (i.e., their output files are not moved * to the new directory). More specifically, the pmix_output * system only opens/creates output files lazily -- so calling * this function affects both new streams \em and any stream that * was previously opened but had not yet output anything. */ PMIX_EXPORT void pmix_output_set_output_file_info(const char *dir, const char *prefix, char **olddir, char **oldprefix); /** * Same as pmix_output_verbose(), but pointer to buffer and size. */ PMIX_EXPORT void pmix_output_hexdump(int verbose_level, int output_id, void *ptr, int buflen); /** * Declare the class of this type. Note that the constructor for * this class is for convenience only -- it is \em not necessary * to be invoked. If the constructor it used, it sets all values * in the struct to be false / 0 (i.e., turning off all output). * The intended usage is to invoke the constructor and then enable * the output fields that you want. */ PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_output_stream_t); END_C_DECLS #endif /* PMIX_OUTPUT_H_ */ pmix-6.1.1~rc2/src/util/pmix_show_help.h0000664000175000017500000001614215203536752020443 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * The "show help" subsystem (SHS) in PMIX is intended to help the * developer convey meaningful information to the user (read longer * than is convenient in a single printf), particularly when errors * occur. The SHS allows the storage of arbitrary-length help * messages in text files which can be parameterized by text filename, * message name, POSIX locale, and printf()-style parameters (e.g., * "%s", "%d", etc.). Note that the primary purpose of the SHS is to * display help messages, but it can actually be used to display any * arbitrary text messages. * * The function pmix_show_help() is used to find a help message and * display it. Its important parameters are a filename, message name, * and printf()-style varargs parameters used to substitute into the * message. * * It was originally intended that this system would support a very * simple version of i18n-like support, but we got (strong) feedback * that i18n support was not desired. So it never happened. * * As such, the file lookup is quite straightforward -- the caller * passes in the filename to find the help message, and the SHS looks * for that file in $pkgdatadir (typically $prefix/share/pmix). * * Once the file is successfully opened, the SHS looks for the * appropriate help message to display. It looks for the message name * in the file, reads in the message, and displays it. printf()-like * substitutions are performed (e.g., %d, %s, etc.) -- * pmix_show_help() takes a variable length argument list that are * used for these substitutions. * * The format of the help file is simplistic: * * - Comments begin with #. Any characters after a # on a line are * ignored. It is not possible to escape a #. * - Message names are on a line by themselves and marked with []. * Names can be any ASCII string within the [] (excluding the * characters newline, linefeed, [, ], and #). * - Messages are any characters between message names and/or the end * of the file. * * Here's a sample helpfile: * * \verbatimbegin * # This is a comment. * [topic 1] * Here's the first message. Let's substitute in an integer: %d. * The quick brown fox jumped over the lazy %s. * # This is another comment -- it's not displayed in the first message. * [another:topic:foo:foo:foo] * This is the second message. Let's just keep rolling along to get * to the second line in the message for this example. * \verbatimend * * It is expected that help messages will be grouped by filename; * similar messages should be in a single file. For example, an MCA * component may install its own helpfile in PMIX's $pkgdatadir, * and therefore the component can invoke pmix_show_help() to display * its own help messages. * * Message files in $pkgdatadir have a naming convention: they * generally start with the prefix "help-" and are followed by a name * descriptive of what kind of messages they contain. MCA components * should generally abide by the MCA prefix rule, with the exception * that they should start the filename with "help-", as mentioned * previously. */ #ifndef PMIX_SHOW_HELP_H #define PMIX_SHOW_HELP_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include #include "src/include/pmix_stdatomic.h" #include "src/include/pmix_globals.h" BEGIN_C_DECLS /** * \internal * * Initialization of show_help subsystem */ PMIX_EXPORT pmix_status_t pmix_show_help_init(void); /** * \internal * * Finalization of show_help subsystem */ PMIX_EXPORT pmix_status_t pmix_show_help_finalize(void); /** * Look up a text message in a text file and display it to the * stderr using printf()-like substitutions (%d, %s, etc.). * * @param filename File where the text messages are contained. * @param topic String index of which message to display from the * text file. * @param want_error_header Display error-bar line header and * footer with the message. * @param varargs Any additional parameters are substituted, * printf()-style into the help message that is displayed. * * This function looks for the filename in the $pkgdatadir * (typically $prefix/share/pmix), and looks up the message * based on the topic, and displays it. If want_error_header is * true, a header and footer of asterisks are also displayed. * * Note that the "want_error_header" argument is int instead of bool, * because passing a parameter that undergoes default argument * promotion to va_start() has undefined behavior (according to clang * warnings on MacOS High Sierra). */ PMIX_EXPORT pmix_status_t pmix_show_help(const char *filename, const char *topic, int want_error_header, ...); /** * This function does the same thing as pmix_show_help(), but returns * its output in a string (that must be freed by the caller). */ PMIX_EXPORT char *pmix_show_help_string(const char *filename, const char *topic, int want_error_header, ...); /** * This function does the same thing as pmix_show_help_string(), but * accepts a va_list form of varargs. */ PMIX_EXPORT char *pmix_show_help_vstring(const char *filename, const char *topic, int want_error_header, va_list ap); /** * This function adds another search location for the files that * back show_help messages. Locations will be searched starting * with the prefix installation directory, then cycled through * any additional directories in the order they were added */ PMIX_EXPORT pmix_status_t pmix_show_help_add_data(const char *project, pmix_show_help_file_t *array); // check for duplicate entries PMIX_EXPORT pmix_status_t pmix_help_check_dups(const char *filename, const char *topic); // output a previously rendered show-help message PMIX_EXPORT pmix_status_t pmix_show_help_norender(const char *filename, const char *topic, const char *output); PMIX_EXPORT extern int pmix_show_help_enabled; END_C_DECLS #endif pmix-6.1.1~rc2/src/util/pmix_basename.h0000664000175000017500000000626615203536752020234 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Returns an OS-independant basename() of a given filename. */ #ifndef PMIX_BASENAME_H #define PMIX_BASENAME_H #include "src/include/pmix_config.h" #include "pmix_common.h" BEGIN_C_DECLS /** * Return the basename of a filename. * * @param filename The filename to examine * * @returns A string containing the basename, or NULL if there is an error * * The contents of the \em filename parameter are unchanged. This * function returns a new string containing the basename of the * filename (which must be eventually freed by the caller), or * NULL if there is an error. Trailing "/" characters in the * filename do not count, unless it is in the only part of the * filename (e.g., "/" or "C:\"). * * This function will do the Right Things on POSIX and * Windows-based operating systems. For example: * * foo.txt returns "foo.txt" * * /foo/bar/baz returns "baz" * * /yow.c returns "yow.c" * * / returns "/" * * C:\foo\bar\baz returns "baz" * * D:foo.txt returns "foo.txt" * * E:\yow.c returns "yow.c" * * F: returns "F:" * * G:\ returns "G:" * * The caller is responsible for freeing the returned string. */ PMIX_EXPORT char * pmix_basename(const char *filename) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__; /** * Return the dirname of a filename. * * @param filename The filename to examine * * @returns A string containing the dirname, or NULL if there is an error * * The contents of the \em filename parameter are unchanged. This * function returns a new string containing the dirname of the * filename (which must be eventually freed by the caller), or * NULL if there is an error. Trailing "/" characters in the * filename do not count, unless it is in the only part of the * filename (e.g., "/" or "C:\"). * * This function will do the Right Things on POSIX and * Windows-based operating systems. For example: * * foo.txt returns "foo.txt" * * /foo/bar/baz returns "/foo/bar" * * /yow.c returns "/" * * / returns "" * * C:\foo\bar\baz returns "C:\foo\bar" * * D:foo.txt returns "D:" * * E:\yow.c returns "E:" * * F: returns "" * * G:\ returns "" * * The caller is responsible for freeing the returned string. */ PMIX_EXPORT char * pmix_dirname(const char *filename) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__; END_C_DECLS #endif /* PMIX_BASENAME_H */ pmix-6.1.1~rc2/src/util/pmix_few.h0000664000175000017500000000455415203536752017240 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_FEW_H #define PMIX_FEW_H #include "pmix_config.h" #include "pmix_common.h" BEGIN_C_DECLS /** * Forks, execs, and waits for a subordinate program * * @param argv Null-terminated argument vector; argv[0] is the program * (same as arguments to execvp()) * * @param status Upon success, will be filled with the return status * from waitpid(2). The WIF* macros can be used to examine the value * (see waitpid(2)). * * @retval PMIX_SUCCESS If the child launched and exited. * @retval PMIX_ERROR If a failure occurred, errno should be * examined for the specific error. * * This function forks, execs, and waits for an executable to * complete. The input argv must be a NULL-terminated array (perhaps * built with the pmix_arr_*() interface). Upon success, PMIX_SUCCESS * is returned. This function will wait either until the child * process has exited or waitpid() returns an error other than EINTR. * * Note that a return of PMIX_SUCCESS does \em not imply that the child * process exited successfully -- it simply indicates that the child * process exited. The WIF* macros (see waitpid(2)) should be used to * examine the status to see hold the child exited. * * \warning This function should not be called if \c orte_init() * or \c MPI_Init() have been called. This function is not * safe in a multi-threaded environment in which a handler * for \c SIGCHLD has been registered. */ PMIX_EXPORT pmix_status_t pmix_few(char *argv[], int *status); END_C_DECLS #endif /* PMIX_FEW_H */ pmix-6.1.1~rc2/src/util/pmix_pty.c0000664000175000017500000002257015203536752017264 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2018 Cisco Systems, Inc. All rights reserved * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_CDEFS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_TERMIOS_H # include #else # ifdef HAVE_TERMIO_H # include # endif #endif #include #ifdef HAVE_UNISTD_H # include #endif #include #include #ifdef HAVE_GRP_H # include #endif #ifdef HAVE_PTY_H # include #endif #ifdef HAVE_UTMP_H # include #endif #ifdef HAVE_PTSNAME # include # ifdef HAVE_STROPTS_H # include # endif #endif #ifdef HAVE_UTIL_H # include #endif #include "src/util/pmix_output.h" #include "src/util/pmix_pty.h" #if PMIX_ENABLE_PTY_SUPPORT == 0 PMIX_EXPORT int pmix_ptymopen(char *pts_name) { PMIX_HIDE_UNUSED_PARAMS(pts_name); return -1 } PMIX_EXPORT int pmix_ptysopen(int fdm, char *pts_name) { PMIX_HIDE_UNUSED_PARAMS(fdm, pts_name); return -1; } #else int pmix_ptymopen(char *pts_name, size_t maxlen) { int fdm; int errsave; # ifdef HAVE_PTSNAME char *ptr; # ifdef _AIX strncpy(pts_name, "/dev/ptc", maxlen); # else strncpy(pts_name, "/dev/ptmx", maxlen); # endif fdm = open(pts_name, O_RDWR); if (fdm < 0) { return -1; } if (grantpt(fdm) < 0) { /* grant access to slave */ errsave = errno; close(fdm); // might change errno errno = errsave; return -2; } if (unlockpt(fdm) < 0) { /* clear slave's lock flag */ errsave = errno; close(fdm); // might change errno errno = errsave; return -3; } ptr = ptsname(fdm); if (ptr == NULL) { /* get slave's name */ errsave = errno; close(fdm); // might change errno errno = errsave; return -4; } if (strlen(ptr) < maxlen) { strncpy(pts_name, ptr, maxlen); /* return name of slave */ return fdm; /* return fd of master */ } else { close(fdm); errno = EOVERFLOW; return -5; } # else // HAVE_PTSNAME char *ptr1, *ptr2; if (strlen("/dev/ptyXY") < maxlen-1) { strcpy(pts_name, "/dev/ptyXY"); } else { return PMIX_ERR_BAD_PARAM; } /* array index: 012345689 (for references in following code) */ for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) { pts_name[8] = *ptr1; for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) { pts_name[9] = *ptr2; /* try to open master */ fdm = open(pts_name, O_RDWR); if (fdm < 0) { if (errno == ENOENT) { /* different from EIO */ return -1; /* out of pty devices */ } else { continue; /* try next pty device */ } } pts_name[5] = 't'; /* change "pty" to "tty" */ return fdm; /* got it, return fd of master */ } } return -1; /* out of pty devices */ # endif } int pmix_ptysopen(int fdm, char *pts_name) { int fds; int errsave; # ifdef HAVE_PTSNAME /* following should allocate controlling terminal */ fds = open(pts_name, O_RDWR); if (fds < 0) { pmix_output(0, "FAILED WITH %s", strerror(errno)); errsave = errno; close(fdm); // might change errno errno = errsave; return -5; } # if defined(__SVR4) && defined(__sun) if (ioctl(fds, I_PUSH, "ptem") < 0) { errsave = errno; close(fdm); // might change errno close(fds); // might change errno errno = errsave; return -6; } if (ioctl(fds, I_PUSH, "ldterm") < 0) { errsave = errno; close(fdm); // might change errno close(fds); // might change errno errno = errsave; return -7; } # endif #ifdef TIOCSCTTY /* Acquire controlling tty on BSD */ // just make the attempt - don't worry if it fails ioctl(fds, TIOCSCTTY, 0); #endif return fds; # else int gid; struct group *grptr; grptr = getgrnam("tty"); if (grptr != NULL) { gid = grptr->gr_gid; } else { gid = -1; /* group tty is not in the group file */ } /* following two functions don't work unless we're root */ lchown(pts_name, getuid(), gid); // DO NOT FOLLOW LINKS chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP); fds = open(pts_name, O_RDWR); if (fds < 0) { errsave = errno; close(fdm); // might change errno errno = errsave; return -1; } return fds; # endif } #endif #if PMIX_ENABLE_PTY_SUPPORT == 0 int pmix_openpty(int *amaster, int *aslave, char *name, void *termp, void *winpp) { PMIX_HIDE_UNUSED_PARAMS(amaster, aslave, name, termp, winpp); return -1; } #elif defined(HAVE_OPENPTY) int pmix_openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp) { return openpty(amaster, aslave, name, termp, winp); } #else /* implement openpty in terms of pmix_ptymopen and pmix_ptysopen */ int pmix_openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp) { char line[20]; *amaster = pmix_ptymopen(line); if (*amaster < 0) { return -1; } *aslave = pmix_ptysopen(*amaster, line); if (*aslave < 0) { close(*amaster); return -1; } if (name) { // We don't know the max length of name, but we do know the // max length of the source, so at least use that. pmix_string_copy(name, line, sizeof(line)); } # ifndef TCSAFLUSH # define TCSAFLUSH TCSETAF # endif if (termp) { (void) tcsetattr(*aslave, TCSAFLUSH, termp); } # ifdef TIOCSWINSZ if (winp) { (void) ioctl(*aslave, TIOCSWINSZ, (char *) winp); } # endif return 0; } #endif /* #ifdef HAVE_OPENPTY */ #if PMIX_ENABLE_PTY_SUPPORT == 0 pid_t pmix_forkpty(int *master, char *slave, size_t len, const struct termios *sterm, const struct winsize *sws) { PMIX_HIDE_UNUSED_PARAMS(master, slave, len, sterm, sws); return -1; } #elif defined(HAVE_FORKPTY) pid_t pmix_forkpty(int *master, char *slave, const struct termios *sterm, const struct winsize *sws) { // some OS don't have the "const" in the above declaration return forkpty(master, slave, (struct termios *)sterm, (struct winsize *)sws); } #else pid_t pmix_forkpty(int *master, char *slave, const struct termios *sterm, const struct winsize *sws) { PMIX_HIDE_UNUSED_PARAMS(master, slave, sterm, sws); return -1; } #endif pmix-6.1.1~rc2/src/util/pmix_timings.h0000664000175000017500000003142015203536752020121 0ustar alastairalastair/* * Copyright (C) 2014 Artem Polyakov * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_UTIL_TIMING_H #define PMIX_UTIL_TIMING_H #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #if PMIX_ENABLE_TIMING # define PMIX_TIMING_DESCR_MAX 1024 # define PMIX_TIMING_BUFSIZE 32 # define PMIX_TIMING_OUTBUF_SIZE (10 * 1024) # define PMIX_TIMING_STR_LEN 1024 typedef enum { PMIX_TIMING_TRACE, PMIX_TIMING_INTDESCR, PMIX_TIMING_INTBEGIN, PMIX_TIMING_INTEND } pmix_event_type_t; typedef struct { pmix_list_item_t super; int fib; pmix_event_type_t type; const char *func; const char *file; int line; double ts, ts_ovh; char descr[PMIX_TIMING_DESCR_MAX]; int id; } pmix_timing_event_t; typedef double (*get_ts_t)(void); typedef struct pmix_timing_t { int next_id_cntr; // not thread safe! // The whole implementation is not thread safe now // since it is supposed to be used in service // thread only. Fix in the future or now? int current_id; pmix_list_t *events; pmix_timing_event_t *buffer; size_t buffer_offset, buffer_size; get_ts_t get_ts; } pmix_timing_t; typedef struct { pmix_timing_t *t; pmix_timing_event_t *ev; int errcode; } pmix_timing_prep_t; /* Pass down our namespace and rank for pretty-print purposes */ PMIX_EXPORT void pmix_init_id(char *nspace, int rank); /** * Initialize timing structure. * * @param t pointer to the timing handler structure */ PMIX_EXPORT void pmix_timing_init(pmix_timing_t *t); /** * Prepare timing event, do all printf-like processing. * Should not be directly used - for service purposes only. * * @param t pointer to the timing handler structure * @param fmt printf-like format * @param ... other parameters that should be converted to string representation * * @retval partly filled pmix_timing_prep_t structure */ PMIX_EXPORT pmix_timing_prep_t pmix_timing_prep_ev(pmix_timing_t *t, const char *fmt, ...); /** * Prepare timing event, ignore printf-like processing. * Should not be directly used - for service purposes only. * * @param t pointer to the timing handler structure * @param fmt printf-like format * @param ... other parameters that should be converted to string representation * * @retval partly filled pmix_timing_prep_t structure */ PMIX_EXPORT pmix_timing_prep_t pmix_timing_prep_ev_end(pmix_timing_t *t, const char *fmt, ...); /** * Enqueue timing event into the list of events in handler 't'. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval */ PMIX_EXPORT void pmix_timing_add_step(pmix_timing_prep_t p, const char *func, const char *file, int line); /** * Enqueue the description of the interval into a list of events * in handler 't'. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval id of event interval */ PMIX_EXPORT int pmix_timing_descr(pmix_timing_prep_t p, const char *func, const char *file, int line); /** * Enqueue the beginning of timing interval that already has the * description and assigned id into the list of events * in handler 't'. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval */ PMIX_EXPORT void pmix_timing_start_id(pmix_timing_t *t, int id, const char *func, const char *file, int line); /** * Enqueue the end of timing interval that already has * description and assigned id into the list of events * in handler 't'. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval */ PMIX_EXPORT void pmix_timing_end(pmix_timing_t *t, int id, const char *func, const char *file, int line); /** * Enqueue both description and start of timing interval * into the list of events and assign its id. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval interval id */ static inline int pmix_timing_start_init(pmix_timing_prep_t p, const char *func, const char *file, int line) { int id = pmix_timing_descr(p, func, file, line); if (id < 0) return id; pmix_timing_start_id(p.t, id, func, file, line); return id; } /** * The wrapper that is used to stop last measurement in PMIX_TIMING_MNEXT. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval interval id */ PMIX_EXPORT void pmix_timing_end_prep(pmix_timing_prep_t p, const char *func, const char *file, int line); /** * Report all events that were enqueued in the timing handler 't'. * - if fname == NULL the output will be done using pmix_output and * each line will be prefixed with "prefix" to ease grep'ing. * - otherwise the corresponding file will be used for output in "append" mode * WARRNING: not all filesystems provide enough support for that feature, some records may * disappear. * * @param t timing handler * @param account_overhead consider malloc overhead introduced by timing code * @param prefix prefix to use when no fname was specified to ease grep'ing * @param fname name of the output file (may be NULL) * * @retval PMIX_SUCCESS On success * @retval PMIX_ERROR or PMIX_ERR_OUT_OF_RESOURCE On failure */ PMIX_EXPORT pmix_status_t pmix_timing_report(pmix_timing_t *t, char *fname); /** * Report all intervals that were enqueued in the timing handler 't'. * - if fname == NULL the output will be done using pmix_output and * each line will be prefixed with "prefix" to ease grep'ing. * - otherwise the corresponding file will be used for output in "append" mode * WARRNING: not all filesystems provide enough support for that feature, some records may * disappear. * * @param t timing handler * @param account_overhead consider malloc overhead introduced by timing code * @param fname name of the output file (may be NULL) * * @retval PMIX_SUCCESS On success * @retval PMIX_ERROR or PMIX_ERR_OUT_OF_RESOURCE On failure */ PMIX_EXPORT pmix_status_t pmix_timing_deltas(pmix_timing_t *t, char *fname); /** * Release all memory allocated for the timing handler 't'. * * @param t timing handler * * @retval */ PMIX_EXPORT void pmix_timing_release(pmix_timing_t *t); /** * Macro for passing down process id - compiled out * when configured without --enable-timing */ # define PMIX_TIMING_ID(n, r) pmix_timing_id((n), (r)); /** * Main macro for use in declaring pmix timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * */ # define PMIX_TIMING_DECLARE(t) \ pmix_timing_t t; /* need semicolon here to avoid warnings when not enabled */ /** * Main macro for use in declaring external pmix timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * */ # define PMIX_TIMING_DECLARE_EXT(x, t) \ x extern pmix_timing_t t; /* need semicolon here to avoid warnings when not enabled */ /** * Main macro for use in initializing pmix timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_init() */ # define PMIX_TIMING_INIT(t) pmix_timing_init(t) /** * Macro that enqueues event with its description to the specified * timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_add_step() */ # define PMIX_TIMING_EVENT(x) \ pmix_timing_add_step(pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__) /** * MDESCR: Measurement DESCRiption * Introduce new timing measurement with string description for the specified * timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_descr() */ # define PMIX_TIMING_MDESCR(x) \ pmix_timing_descr(pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__) /** * MSTART_ID: Measurement START by ID. * Marks the beginning of the measurement with ID=id on the * specified timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_start_id() */ # define PMIX_TIMING_MSTART_ID(t, id) \ pmix_timing_start_id(t, id, __FUNCTION__, __FILE__, __LINE__) /** * MSTART: Measurement START * Introduce new timing measurement conjuncted with its start * on the specified timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_start_init() */ # define PMIX_TIMING_MSTART(x) \ pmix_timing_start_init(pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__) /** * MSTOP: STOP Measurement * Finishes the most recent measurement on the specified timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_end() */ # define PMIX_TIMING_MSTOP(t) pmix_timing_end(t, -1, __FUNCTION__, __FILE__, __LINE__) /** * MSTOP_ID: STOP Measurement with ID=id. * Finishes the measurement with give ID on the specified timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_end() */ # define PMIX_TIMING_MSTOP_ID(t, id) pmix_timing_end(t, id, __FUNCTION__, __FILE__, __LINE__) /** * MNEXT: start NEXT Measurement * Convenient macro, may be implemented with the sequence of three previously * defined macros: * - finish current measurement (PMIX_TIMING_MSTOP); * - introduce new timing measurement (PMIX_TIMING_MDESCR); * - starts next measurement (PMIX_TIMING_MSTART_ID) * on the specified timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_start_init() */ # define PMIX_TIMING_MNEXT(x) \ (pmix_timing_end_prep(pmix_timing_prep_ev_end x, __FUNCTION__, __FILE__, __LINE__), \ pmix_timing_start_init(pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__)) /** * The macro for use in reporting collected events with absolute values; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @param enable flag that enables/disables reporting. Used for fine-grained timing. * @see pmix_timing_report() */ # define PMIX_TIMING_REPORT(enable, t) \ { \ if (enable) { \ pmix_timing_report(t, pmix_timing_output); \ } \ } /** * The macro for use in reporting collected events with relative times; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @param enable flag that enables/disables reporting. Used for fine-grained timing. * @see pmix_timing_deltas() */ # define PMIX_TIMING_DELTAS(enable, t) \ { \ if (enable) { \ pmix_timing_deltas(t, pmix_timing_output); \ } \ } /** * Main macro for use in releasing allocated resources; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_release() */ # define PMIX_TIMING_RELEASE(t) pmix_timing_release(t) #else # define PMIX_TIMING_ID(n, r) # define PMIX_TIMING_DECLARE(t) # define PMIX_TIMING_DECLARE_EXT(x, t) # define PMIX_TIMING_INIT(t) # define PMIX_TIMING_EVENT(x) # define PMIX_TIMING_MDESCR(x) # define PMIX_TIMING_MSTART_ID(t, id) # define PMIX_TIMING_MSTART(x) # define PMIX_TIMING_MSTOP(t) # define PMIX_TIMING_MSTOP_ID(t, id) # define PMIX_TIMING_MNEXT(x) # define PMIX_TIMING_REPORT(enable, t) # define PMIX_TIMING_DELTAS(enable, t) # define PMIX_TIMING_RELEASE(t) #endif #endif pmix-6.1.1~rc2/src/util/pmix_cmd_line.h0000664000175000017500000003654215203536752020233 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2017 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2017 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_CMD_LINE_H #define PMIX_CMD_LINE_H #include "src/include/pmix_config.h" #ifdef HAVE_UNISTD_H # include #endif #include #include #include #include #include "src/class/pmix_list.h" #include "src/class/pmix_object.h" #include "src/util/pmix_argv.h" BEGIN_C_DECLS typedef struct { pmix_list_item_t super; char *key; char **values; } pmix_cli_item_t; PMIX_CLASS_DECLARATION(pmix_cli_item_t); typedef struct { pmix_object_t super; pmix_list_t instances; // comprised of pmix_cli_item_t's char **tail; // remainder of argv } pmix_cli_result_t; PMIX_CLASS_DECLARATION(pmix_cli_result_t); #define PMIX_CLI_RESULT_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \ .instances = PMIX_LIST_STATIC_INIT, \ .tail = NULL \ } /* define PMIX-named flags for argument required */ #define PMIX_ARG_REQD required_argument #define PMIX_ARG_NONE no_argument #define PMIX_ARG_OPTIONAL optional_argument /* define PMIX-named flags for whether parsing * CLI shall include deprecation warnings */ #define PMIX_CLI_SILENT true #define PMIX_CLI_WARN false /* define a long option that has no short option equivalent * * n = name of the option (see below for definitions) * a = whether or not it requires an argument */ #define PMIX_OPTION_DEFINE(n, a) \ { \ .name = (n), \ .has_arg = (a), \ .flag = NULL, \ .val = 0 \ } /* define a long option that has a short option equivalent * * n = name of the option (see below for definitions) * a = whether or not it requires an argument * c = single character equivalent option */ #define PMIX_OPTION_SHORT_DEFINE(n, a, c) \ { \ .name = (n), \ .has_arg = (a), \ .flag = NULL, \ .val = (c) \ } #define PMIX_OPTION_END {0, 0, 0, 0} // NAME STRING ARGUMENT // Basic options #define PMIX_CLI_HELP "help" // optional #define PMIX_CLI_VERSION "version" // none #define PMIX_CLI_VERBOSE "verbose" // number of instances => verbosity level #define PMIX_CLI_PMIXMCA "pmixmca" // requires TWO #define PMIX_CLI_PRETTY_PRINT "pretty-print" // none #define PMIX_CLI_PARSABLE "parsable" // none #define PMIX_CLI_PARSEABLE "parseable" // none // Tool connection options #define PMIX_CLI_SYS_SERVER_FIRST "system-server-first" // none #define PMIX_CLI_SYSTEM_SERVER "system-server" // none #define PMIX_CLI_SYS_SERVER_ONLY "system-server-only" // none #define PMIX_CLI_DO_NOT_CONNECT "do-not-connect" // none #define PMIX_CLI_WAIT_TO_CONNECT "wait-to-connect" // required #define PMIX_CLI_NUM_CONNECT_RETRIES "num-connect-retries" // required #define PMIX_CLI_PID "pid" // required #define PMIX_CLI_NAMESPACE "namespace" // required #define PMIX_CLI_NSPACE "nspace" // required #define PMIX_CLI_URI "uri" // required #define PMIX_CLI_TIMEOUT "timeout" // required #define PMIX_CLI_TMPDIR "tmpdir" // required #define PMIX_CLI_CONNECTION_ORDER "connect-order" // required #define PMIX_CLI_SYS_CONTROLLER "system-controller" // none // Allocation request options #define PMIX_CLI_REQ_ID "request-id" // required #define PMIX_CLI_QUEUE "queue" // required, short is 'q' #define PMIX_CLI_RESOURCES "resources" // required #define PMIX_CLI_NODES "nodes" // required, short is 'N' #define PMIX_CLI_IMAGE "image" // required, short is 'i' #define PMIX_CLI_EXCLUDE "exclude" // required, short is 'x' #define PMIX_CLI_WAIT_ALL_NODES "wait-all-nodes" // none #define PMIX_CLI_NODELIST "nodelist" // required, short is 'w' #define PMIX_CLI_UID "uid" // required #define PMIX_CLI_GID "gid" // required #define PMIX_CLI_TIME "time" // required, short is 't' #define PMIX_CLI_SIGNAL "signal" // required #define PMIX_CLI_SHARE "share" // none #define PMIX_CLI_EXTEND "extend" // none #define PMIX_CLI_SHRINK "shrink" // none #define PMIX_CLI_NO_SHELL "no-shell" // none #define PMIX_CLI_BEGIN "begin" // required #define PMIX_CLI_IMMEDIATE "immediate" // optional, short is 'I' #define PMIX_CLI_DEPENDENCY "dependency" // required, short is 'd' #define PMIX_CLI_DO_NOT_WAIT "do-not-wait" // none // Job control options #define PMIX_CLI_PAUSE "pause" // none #define PMIX_CLI_RESUME "resume" // none #define PMIX_CLI_CANCEL "cancel" // required #define PMIX_CLI_KILL "kill" // none #define PMIX_CLI_RESTART "restart" // required #define PMIX_CLI_CHKPT "checkpoint" // required #define PMIX_CLI_TARGETS "targets" // required #define PMIX_CLI_TERMINATE "terminate" // none #define PMIX_CLI_PSET_NAME "pset" // required #define PMIX_CLI_FWD_ENVAR "x" // required #define PMIX_CLI_SET_ENVAR "set-env" // required #define PMIX_CLI_PREPEND_ENVAR "prepend-env" // required #define PMIX_CLI_APPEND_ENVAR "append-env" // required #define PMIX_CLI_UNSET_ENVAR "unset-env" // required // Info options #define PMIX_CLI_INFO_ALL "all" // none #define PMIX_CLI_INFO_ARCH "arch" // none #define PMIX_CLI_INFO_CONFIG "config" // none #define PMIX_CLI_INFO_HOSTNAME "hostname" // none #define PMIX_CLI_INFO_INTERNAL "internal" // none #define PMIX_CLI_INFO_PARAM "param" // required #define PMIX_CLI_INFO_PARAMS "params" // required #define PMIX_CLI_INFO_PATH "path" // required #define PMIX_CLI_INFO_VERSION "show-version" // required #define PMIX_CLI_INFO_TYPES "type" // required #define PMIX_CLI_INFO_COLOR "color" // required #define PMIX_CLI_INFO_SHOW_FAILED "show-failed" //none #define PMIX_CLI_INFO_SELECTED_ONLY "selected-only" // none typedef void (*pmix_cmd_line_store_fn_t)(const char *name, const char *option, pmix_cli_result_t *results); PMIX_EXPORT int pmix_cmd_line_parse(char **argv, char *shorts, struct option myoptions[], pmix_cmd_line_store_fn_t storefn, pmix_cli_result_t *results, char *helpfile); static inline pmix_cli_item_t* pmix_cmd_line_get_param(pmix_cli_result_t *results, const char *key) { pmix_cli_item_t *opt; PMIX_LIST_FOREACH(opt, &results->instances, pmix_cli_item_t) { if (0 == strcmp(opt->key, key)) { return opt; } } return NULL; } static inline bool pmix_cmd_line_is_taken(pmix_cli_result_t *results, const char *key) { if (NULL == pmix_cmd_line_get_param(results, key)) { return false; } return true; } static inline int pmix_cmd_line_get_ninsts(pmix_cli_result_t *results, const char *key) { pmix_cli_item_t *opt; opt = pmix_cmd_line_get_param(results, key); if (NULL == opt) { return 0; } return PMIx_Argv_count(opt->values); } static inline char* pmix_cmd_line_get_nth_instance(pmix_cli_result_t *results, const char *key, int idx) { pmix_cli_item_t *opt; int ninst; opt = pmix_cmd_line_get_param(results, key); if (NULL == opt) { return NULL; } ninst = PMIx_Argv_count(opt->values); if (ninst < idx) { return NULL; } return opt->values[idx]; } /* USAGE: * param "a" is the input command line string * param "b" is the defined CLI option */ static inline bool pmix_check_cli_option(char *ain, char *bin) { size_t len1, len2, len, n; char *a, *b, *p; char **asplit, **bsplit; int match, acnt, bcnt; // protect the input a = strdup(ain); b = strdup(bin); /* if there is an '=' in the option, then we only * check up to that position in the option as * everything past it is the value the option * is being assigned */ p = strchr(a, '='); if (NULL != p) { *p = '\0'; } p = strchr(b, '='); if (NULL != p) { *p = '\0'; } /* if there exists a '-' in either argument, * then we are dealing with a multi-word * option. Parse those by checking each * word segment individually for a match * so the user doesn't have to spell it all * out unless necessary. We consider it a * valid match if all provided segments match * that of the target option */ if (NULL != strchr(b, '-') || NULL != strchr(a, '-')) { asplit = PMIx_Argv_split(a, '-'); bsplit = PMIx_Argv_split(b, '-'); acnt = PMIx_Argv_count(asplit); bcnt = PMIx_Argv_count(bsplit); if (acnt > bcnt) { PMIx_Argv_free(asplit); PMIx_Argv_free(bsplit); free(a); free(b); return false; } match = 0; for (n=0; NULL != asplit[n] && NULL != bsplit[n]; n++) { len1 = strlen(asplit[n]); len2 = strlen(bsplit[n]); len = len1 < len2 ? len1 : len2; if (0 == strncasecmp(asplit[n], bsplit[n], len)) { ++match; } else { PMIx_Argv_free(asplit); PMIx_Argv_free(bsplit); free(a); free(b); return false; } } PMIx_Argv_free(asplit); PMIx_Argv_free(bsplit); if (match == acnt) { /* all provided segments match */ free(a); free(b); return true; } free(a); free(b); return false; } /* if this is not a multi-word option, we just * check the strings */ len1 = strlen(a); len2 = strlen(b); len = (len1 < len2) ? len1 : len2; if (0 == strncasecmp(a, b, len)) { free(a); free(b); return true; } free(a); free(b); return false; } #define PMIX_CHECK_CLI_OPTION(a, b) \ pmix_check_cli_option(a, b) static inline unsigned int pmix_convert_string_to_time(const char *t) { char **tmp = PMIx_Argv_split(t, ':'); int sz = PMIx_Argv_count(tmp); unsigned int tm; /* work upwards from the bottom, where the * bottom represents seconds, then minutes, * then hours, and then days */ tm = strtoul(tmp[sz-1], NULL, 10); if (0 <= (sz-2) && NULL != tmp[sz-2]) { tm += 60 * strtoul(tmp[sz-2], NULL, 10); } if (0 <= (sz-3) && NULL != tmp[sz-3]) { tm += 60 * 60 * strtoul(tmp[sz-3], NULL, 10); } if (0 <= (sz-4) && NULL != tmp[sz-4]) { tm += 24 * 60 * 60 * strtoul(tmp[sz-4], NULL, 10); } PMIx_Argv_free(tmp); return tm; } #define PMIX_CONVERT_TIME(s) \ pmix_convert_string_to_time(s) #define PMIX_CLI_DEBUG_LIST(r) \ do { \ pmix_cli_item_t *_c; \ char *_tail; \ pmix_output(0, "\n[%s:%s:%d]", __FILE__, __func__, __LINE__); \ PMIX_LIST_FOREACH(_c, &(r)->instances, pmix_cli_item_t) { \ pmix_output(0, "KEY: %s", _c->key); \ if (NULL != _c->values) { \ for (int _n=0; NULL != _c->values[_n]; _n++) { \ pmix_output(0, " VAL[%d]: %s", _n, _c->values[_n]); \ } \ } \ } \ _tail = PMIx_Argv_join((r)->tail, ' '); \ pmix_output(0, "TAIL: %s", _tail); \ free(_tail); \ pmix_output(0, "\n"); \ } while(0) #define PMIX_CLI_REMOVE_DEPRECATED(r, o) \ do { \ pmix_list_remove_item(&(r)->instances, &(o)->super); \ PMIX_RELEASE(o); \ } while(0) END_C_DECLS #endif /* PMIX_CMD_LINE_H */ pmix-6.1.1~rc2/src/util/pmix_if.h0000664000175000017500000001631615203536752017054 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2013 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* @file */ #ifndef PMIX_PIF_UTIL_ #define PMIX_PIF_UTIL_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #include "pmix_common.h" #include "src/class/pmix_list.h" #define PMIX_IF_NAMESIZE 256 BEGIN_C_DECLS #define PMIX_PIF_FORMAT_ADDR(n) \ (((n) >> 24) & 0x000000FF), (((n) >> 16) & 0x000000FF), (((n) >> 8) & 0x000000FF), \ ((n) &0x000000FF) #define PMIX_PIF_ASSEMBLE_FABRIC(n1, n2, n3, n4) \ (((n1) << 24) & 0xFF000000) | (((n2) << 16) & 0x00FF0000) | (((n3) << 8) & 0x0000FF00) \ | ((n4) &0x000000FF) typedef struct pmix_pif_t { pmix_list_item_t super; char if_name[PMIX_IF_NAMESIZE + 1]; int if_index; uint16_t if_kernel_index; uint16_t af_family; int if_flags; int if_speed; struct sockaddr_storage if_addr; uint32_t if_mask; uint32_t if_bandwidth; uint8_t if_mac[6]; int ifmtu; /* Can't use if_mtu because of a #define collision on some BSDs */ } pmix_pif_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_pif_t); /* "global" list of available interfaces */ PMIX_EXPORT extern pmix_list_t pmix_if_list; /* global flags */ PMIX_EXPORT extern bool pmix_if_do_not_resolve; /** * Lookup an interface by address and return its name. * * @param if_addr (IN) Interface address (hostname or dotted-quad) * @param if_name (OUT) Interface name buffer * @param size (IN) Interface name buffer size */ PMIX_EXPORT int pmix_ifaddrtoname(const char *if_addr, char *if_name, int size); /** * Lookup an interface by name and return its pmix_list index. * * @param if_name (IN) Interface name * @return Interface pmix_list index */ PMIX_EXPORT int pmix_ifnametoindex(const char *if_name); /** * Lookup an interface by name and return its kernel index. * * @param if_name (IN) Interface name * @return Interface kernel index */ PMIX_EXPORT int16_t pmix_ifnametokindex(const char *if_name); /* * Attempt to resolve an address (given as either IPv4/IPv6 string * or hostname) and return the kernel index of the interface * that is on the same network as the specified address */ PMIX_EXPORT int16_t pmix_ifaddrtokindex(const char *if_addr); /** * Lookup an interface by pmix_list index and return its kernel index. * * @param if_name (IN) Interface pmix_list index * @return Interface kernel index */ PMIX_EXPORT int pmix_ifindextokindex(int if_index); /** * Returns the number of available interfaces. */ PMIX_EXPORT int pmix_ifcount(void); /** * Returns the index of the first available interface. */ PMIX_EXPORT int pmix_ifbegin(void); /** * Lookup the current position in the interface list by * index and return the next available index (if it exists). * * @param if_index Returns the next available index from the * current position. */ PMIX_EXPORT int pmix_ifnext(int if_index); /** * Lookup an interface by index and return its name. * * @param if_index (IN) Interface index * @param if_name (OUT) Interface name buffer * @param size (IN) Interface name buffer size */ PMIX_EXPORT int pmix_ifindextoname(int if_index, char *if_name, int); /** * Lookup an interface by kernel index and return its name. * * @param if_index (IN) Interface kernel index * @param if_name (OUT) Interface name buffer * @param size (IN) Interface name buffer size */ PMIX_EXPORT int pmix_ifkindextoname(int if_kindex, char *if_name, int); /** * Lookup an interface by index and return its primary address. * * @param if_index (IN) Interface index * @param if_name (OUT) Interface address buffer * @param size (IN) Interface address buffer size */ PMIX_EXPORT int pmix_ifindextoaddr(int if_index, struct sockaddr *, unsigned int); PMIX_EXPORT int pmix_ifkindextoaddr(int if_kindex, struct sockaddr *if_addr, unsigned int length); /** * Lookup an interface by index and return its network mask (in CIDR * notation -- NOT the actual netmask itself!). * * @param if_index (IN) Interface index * @param if_name (OUT) Interface address buffer * @param size (IN) Interface address buffer size */ PMIX_EXPORT int pmix_ifindextomask(int if_index, uint32_t *, int); /** * Lookup an interface by index and return its MAC address. * * @param if_index (IN) Interface index * @param if_mac (OUT) Interface's MAC address */ PMIX_EXPORT int pmix_ifindextomac(int if_index, uint8_t if_mac[6]); /** * Lookup an interface by index and return its MTU. * * @param if_index (IN) Interface index * @param if_mtu (OUT) Interface's MTU */ PMIX_EXPORT int pmix_ifindextomtu(int if_index, int *mtu); /** * Lookup an interface by index and return its flags. * * @param if_index (IN) Interface index * @param if_flags (OUT) Interface flags */ PMIX_EXPORT int pmix_ifindextoflags(int if_index, uint32_t *); /** * Determine if given hostname / IP address is a local address * * @param hostname (IN) Hostname (or stringified IP address) * @return true if \c hostname is local, false otherwise */ PMIX_EXPORT bool pmix_ifislocal(const char *hostname); /** * Convert a dot-delimited network tuple to an IP address * * @param addr (IN) character string tuple * @param net (IN) Pointer to returned network address * @param mask (IN) Pointer to returned netmask * @return PMIX_SUCCESS if no problems encountered * @return PMIX_ERROR if data could not be released */ PMIX_EXPORT int pmix_iftupletoaddr(const char *addr, uint32_t *net, uint32_t *mask); /** * Determine if given interface is loopback * * @param if_index (IN) Interface index */ PMIX_EXPORT bool pmix_ifisloopback(int if_index); /* * Determine if a specified interface is included in a NULL-terminated argv array */ PMIX_EXPORT int pmix_ifmatches(int kidx, char **nets); /* * Provide a list of strings that contain all known aliases for this node */ PMIX_EXPORT void pmix_ifgetaliases(char ***aliases); END_C_DECLS #endif pmix-6.1.1~rc2/src/util/pmix_argv.h0000664000175000017500000001561215203536752017413 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2008 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2007 Voltaire. All rights reserved. * Copyright (c) 2012 Los Alamos National Security, LLC. All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Generic routines for "argv"-like handling. Helpful for creating * arrays of strings, especially when creating command lines. */ #ifndef PMIX_ARGV_H #define PMIX_ARGV_H #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TYPES_H # include #endif #include "pmix.h" BEGIN_C_DECLS /** * Append a string (by value) to an new or existing NULL-terminated * argv array. * * @param argc Pointer to the length of the argv array. Must not be * NULL. * @param argv Pointer to an argv array. * @param str Pointer to the string to append. * * @retval PMIX_SUCCESS On success * @retval PMIX_ERROR On failure * * This function adds a string to an argv array of strings by value; * it is permissible to pass a string on the stack as the str * argument to this function. * * To add the first entry to an argv array, call this function with * (*argv == NULL). This function will allocate an array of length * 2; the first entry will point to a copy of the string passed in * arg, the second entry will be set to NULL. * * If (*argv != NULL), it will be realloc'ed to be 1 (char*) larger, * and the next-to-last entry will point to a copy of the string * passed in arg. The last entry will be set to NULL. * * Just to reinforce what was stated above: the string is copied by * value into the argv array; there is no need to keep the original * string (i.e., the arg parameter) after invoking this function. */ PMIX_EXPORT pmix_status_t pmix_argv_append(int *argc, char ***argv, const char *arg) __pmix_attribute_nonnull__(1) __pmix_attribute_nonnull__(3); /** * Append to an argv-style array, but only if the provided argument * doesn't already exist somewhere in the array. Ignore the size of the array. * Defines the index of the found/added item in the array. * * @param idx Index the found/added item in the array. * @param argv Pointer to an argv array. * @param str Pointer to the string to append. * * @retval PMIX_SUCCESS On success * @retval PMIX_ERROR On failure * * This function is identical to the PMIx_Argv_append_unique_nosize() function * but it has an extra argument defining the index of the item in the array. */ PMIX_EXPORT pmix_status_t pmix_argv_append_unique_idx(int *idx, char ***argv, const char *arg); PMIX_EXPORT char *pmix_argv_join_range(char **argv, size_t start, size_t end, int delimiter) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__; /** * Return the number of bytes consumed by an argv array. * * @param argv The input argv array. * * Count the number of bytes consumed by a NULL-terminated argv * array. This includes the number of bytes used by each of the * strings as well as the pointers used in the argv array. */ PMIX_EXPORT size_t pmix_argv_len(char **argv); /** * Delete one or more tokens from the middle of an argv. * * @param argv The argv to delete from * @param start The index of the first token to delete * @param num_to_delete How many tokens to delete * * @retval PMIX_SUCCESS Always * * Delete some tokens from within an existing argv. The start * parameter specifies the first token to delete, and will delete * (num_to_delete-1) tokens following it. argv will be realloc()ed * to *argc - num_deleted size. * * If start is beyond the end of the argv array, this function is * a no-op. * * If num_to_delete runs beyond the end of the argv array, this * function will delete all tokens starting with start to the end * of the array. * * All deleted items in the argv array will have their contents * free()ed (it is assumed that the argv "owns" the memory that * the pointer points to). */ PMIX_EXPORT pmix_status_t pmix_argv_delete(int *argc, char ***argv, int start, int num_to_delete); /** * Insert one argv array into the middle of another * * @param target The argv to insert tokens into * @param start Index where the first token will be placed in target * @param source The argv to copy tokens from * * @retval PMIX_SUCCESS upon success * @retval PMIX_BAD_PARAM if any parameters are non-sensical * * This function takes one arg and inserts it in the middle of * another. The first token in source will be inserted at index * start in the target argv; all other tokens will follow it. * Similar to pmix_argv_append(), the target may be realloc()'ed * to accommodate the new storage requirements. * * The source array is left unaffected -- its contents are copied * by value over to the target array (i.e., the strings that * source points to are strdup'ed into the new locations in * target). */ PMIX_EXPORT pmix_status_t pmix_argv_insert(char ***target, int start, char **source); /** * Insert one argv element in front of a specific position in an array * * @param target The argv to insert tokens into * @param location Index where the token will be placed in target * @param source The token to be inserted * * @retval PMIX_SUCCESS upon success * @retval PMIX_BAD_PARAM if any parameters are non-sensical * * This function takes one arg and inserts it in the middle of * another. The token will be inserted at the specified index * in the target argv; all other tokens will be shifted down. * Similar to pmix_argv_append(), the target may be realloc()'ed * to accommodate the new storage requirements. * * The source token is left unaffected -- its contents are copied * by value over to the target array (i.e., the string that * source points to is strdup'ed into the new location in * target). */ PMIX_EXPORT pmix_status_t pmix_argv_insert_element(char ***target, int location, char *source); PMIX_EXPORT char **pmix_argv_copy_strip(char **argv) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__; END_C_DECLS #endif /* PMIX_ARGV_H */ pmix-6.1.1~rc2/src/util/pmix_environ.h0000664000175000017500000001311715203536752020132 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2022 Amazon.com, Inc. or its affiliates. * All Rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Generic helper routines for environment manipulation. */ #ifndef PMIX_ENVIRON_H #define PMIX_ENVIRON_H #include #ifdef HAVE_CRT_EXTERNS_H # include #endif #include "pmix_common.h" #include "src/class/pmix_list.h" BEGIN_C_DECLS /** * Merge two environ-like arrays into a single, new array, ensuring * that there are no duplicate entries. * * @param minor Set 1 of the environ's to merge * @param major Set 2 of the environ's to merge * @retval New array of environ * * Merge two environ-like arrays into a single, new array, * ensuring that there are no duplicate entries. If there are * duplicates, entries in the \em major array are favored over * those in the \em minor array. * * Both \em major and \em minor are expected to be argv-style * arrays (i.e., terminated with a NULL pointer). * * The array that is returned is an unencumbered array that should * later be freed with a call to PMIx_Argv_free(). * * Either (or both) of \em major and \em minor can be NULL. If * one of the two is NULL, the other list is simply copied to the * output. If both are NULL, NULL is returned. */ PMIX_EXPORT char **pmix_environ_merge(char **minor, char **major) __pmix_attribute_warn_unused_result__; /** * Merge contents of an environ-like array into a second environ-like * array * * @param orig The environment to update * @param additions The environment to merge into orig * * Merge the contents of \em additions into \em orig. If a key from * \em additions is found in \em orig, then the value in orig is not * updated (ie, it is an additions-only merge). The original * environment cannot be environ, because pmix_argv_append is used to * extend the environment, and PMIx_Argv_append_nosize() may not be * safe to call on environ (for the same reason that realloc() may * note be safe to call on environ). * * New strings are allocated when copied, so both \em orig and \em * additions individually maintain their ability to be freed with * PMIx_Argv_free(). * * Note that on error, the \em orig array may be partially updated * with values from additions, but the array will still be a valid * argv-style array. */ PMIX_EXPORT pmix_status_t pmix_environ_merge_inplace(char ***orig, char **additions) __pmix_attribute_warn_unused_result__ __pmix_attribute_nonnull__(1); /** * Portable version of getenv(3), allowing searches of any key=value array * * @param name String name of the environment variable to look for * @param env The environment to use * * The return value will be a pointer to the start of the value * string. The string returned should not be free()ed or modified by * the caller, similar to getenv(). * * Unlike getenv(), pmix_getenv() will accept a \em name in key=value * format. In that case, only the key portion of \em name is used for * the search, and the return value of pmix_getenv() is the value of * the same key in \em env. */ PMIX_EXPORT char * pmix_getenv(const char *name, char **env) __pmix_attribute_nonnull__(1); /** * Portable version of unsetenv(3), allowing editing of any * environ-like array. * * @param name String name of the environment variable to look for * @param env The environment to use * * @retval PMIX_ERR_OUT_OF_RESOURCE If an internal malloc fails. * @retval PMIX_ERR_NOT_FOUND If \em name is not found in \em env. * @retval PMIX_SUCCESS If \em name is found and successfully deleted. * * If \em name is found in \em env, the string corresponding to * that entry is freed and its entry is eliminated from the array. */ PMIX_EXPORT pmix_status_t pmix_unsetenv(const char *name, char ***env) __pmix_attribute_nonnull__(1); /* A consistent way to retrieve the home and tmp directory on all supported * platforms. */ PMIX_EXPORT const char *pmix_home_directory(uid_t uid); PMIX_EXPORT const char *pmix_tmp_directory(void); /* Provide a utility for harvesting envars */ PMIX_EXPORT pmix_status_t pmix_util_harvest_envars(char **incvars, char **excvars, pmix_list_t *ilist); /* Some care is needed with environ on OS X when dealing with shared libraries. Handle that care here... */ #ifdef HAVE__NSGETENVIRON # define environ (*_NSGetEnviron()) #else extern char **environ; #endif END_C_DECLS #endif /* PMIX_ENVIRON */ pmix-6.1.1~rc2/src/util/pmix_context_fns.h0000664000175000017500000000275015203536752021005 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * */ #ifndef _PMIX_CONTEXT_FNS_H_ #define _PMIX_CONTEXT_FNS_H_ #include "src/include/pmix_config.h" #include "pmix_common.h" BEGIN_C_DECLS PMIX_EXPORT pmix_status_t pmix_util_check_context_cwd(char **incwd, bool want_chdir, bool user_cwd); PMIX_EXPORT pmix_status_t pmix_util_check_context_app(char **incmd, char *cwd, char **env); END_C_DECLS #endif pmix-6.1.1~rc2/src/util/pmix_output.c0000664000175000017500000006354515203536752020017 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2008 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2006 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2006 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include #include #include #ifdef HAVE_SYSLOG_H # include #endif #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" /* * Private data */ static int verbose_stream = -1; static pmix_output_stream_t verbose; static char *output_dir = NULL; static char *output_prefix = NULL; /* * Internal data structures and helpers for the generalized output * stream mechanism. */ /* * Private functions */ static void construct(pmix_object_t *stream); static void destruct(pmix_object_t *stream); static int do_open(int output_id, pmix_output_stream_t *lds); static int open_file(int i); static void free_descriptor(int output_id); static int make_string(char **out, char **no_newline_string, pmix_output_desc_t *ldi, const char *format, va_list arglist); static int output(int output_id, const char *format, va_list arglist); #if defined(HAVE_SYSLOG) # define USE_SYSLOG 1 #else # define USE_SYSLOG 0 #endif /* global state */ bool pmix_output_redirected_to_syslog = false; int pmix_output_redirected_syslog_pri = 0; pmix_output_desc_t pmix_output_info[PMIX_OUTPUT_MAX_STREAMS]; /* * Local state */ static bool initialized = false; static int default_stderr_fd = -1; #if defined(HAVE_SYSLOG) static bool syslog_opened = false; #endif static char *redirect_syslog_ident = NULL; PMIX_CLASS_INSTANCE(pmix_output_stream_t, pmix_object_t, construct, destruct); /* * Setup the output stream infrastructure */ bool pmix_output_init(void) { int i; char hostname[PMIX_MAXHOSTNAMELEN] = {0}; char *str; if (initialized) { return true; } str = getenv("PMIX_OUTPUT_STDERR_FD"); if (NULL != str) { default_stderr_fd = atoi(str); } str = getenv("PMIX_OUTPUT_REDIRECT"); if (NULL != str) { if (0 == strcasecmp(str, "syslog")) { pmix_output_redirected_to_syslog = true; } } str = getenv("PMIX_OUTPUT_SYSLOG_PRI"); #ifdef HAVE_SYSLOG_H if (NULL != str) { if (0 == strcasecmp(str, "info")) { pmix_output_redirected_syslog_pri = LOG_INFO; } else if (0 == strcasecmp(str, "error")) { pmix_output_redirected_syslog_pri = LOG_ERR; } else if (0 == strcasecmp(str, "warn")) { pmix_output_redirected_syslog_pri = LOG_WARNING; } else { pmix_output_redirected_syslog_pri = LOG_ERR; } } else { pmix_output_redirected_syslog_pri = LOG_ERR; } #endif str = getenv("PMIX_OUTPUT_SYSLOG_IDENT"); if (NULL != str) { redirect_syslog_ident = strdup(str); } PMIX_CONSTRUCT(&verbose, pmix_output_stream_t); if (pmix_output_redirected_to_syslog) { verbose.lds_want_syslog = true; verbose.lds_syslog_priority = pmix_output_redirected_syslog_pri; if (NULL != str) { verbose.lds_syslog_ident = strdup(redirect_syslog_ident); } verbose.lds_want_stderr = false; verbose.lds_want_stdout = false; } else { verbose.lds_want_stderr = true; } gethostname(hostname, sizeof(hostname) - 1); hostname[sizeof(hostname) - 1] = '\0'; if (0 > asprintf(&verbose.lds_prefix, "[%s:%05d] ", hostname, getpid())) { return PMIX_ERR_NOMEM; } for (i = 0; i < PMIX_OUTPUT_MAX_STREAMS; ++i) { pmix_output_info[i].ldi_used = false; pmix_output_info[i].ldi_enabled = false; pmix_output_info[i].ldi_syslog = pmix_output_redirected_to_syslog; pmix_output_info[i].ldi_file = false; pmix_output_info[i].ldi_file_suffix = NULL; pmix_output_info[i].ldi_file_want_append = false; pmix_output_info[i].ldi_fd = -1; pmix_output_info[i].ldi_file_num_lines_lost = 0; } initialized = true; /* Set some defaults */ if (0 > asprintf(&output_prefix, "pmix-output-pid%d-", getpid())) { return false; } output_dir = strdup(pmix_tmp_directory()); /* Open the default verbose stream */ verbose_stream = pmix_output_open(&verbose); return true; } /* * Open a stream */ int pmix_output_open(pmix_output_stream_t *lds) { return do_open(-1, lds); } /* * Reset the parameters on a stream */ int pmix_output_reopen(int output_id, pmix_output_stream_t *lds) { return do_open(output_id, lds); } /* * Enable and disable output streams */ bool pmix_output_switch(int output_id, bool enable) { bool ret = false; /* Setup */ if (!initialized) { pmix_output_init(); } if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS) { ret = pmix_output_info[output_id].ldi_enabled; pmix_output_info[output_id].ldi_enabled = enable; } return ret; } /* * Reopen all the streams; used during checkpoint/restart. */ void pmix_output_reopen_all(void) { char *str; char hostname[PMIX_MAXHOSTNAMELEN] = {0}; str = getenv("PMIX_OUTPUT_STDERR_FD"); if (NULL != str) { default_stderr_fd = atoi(str); } else { default_stderr_fd = -1; } gethostname(hostname, sizeof(hostname)); if (NULL != verbose.lds_prefix) { free(verbose.lds_prefix); verbose.lds_prefix = NULL; } if (0 > asprintf(&verbose.lds_prefix, "[%s:%05d] ", hostname, getpid())) { verbose.lds_prefix = NULL; return; } } /* * Close a stream */ void pmix_output_close(int output_id) { int i; /* Setup */ if (!initialized) { return; } /* If it's valid, used, enabled, and has an open file descriptor, * free the resources associated with the descriptor */ if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS && pmix_output_info[output_id].ldi_used && pmix_output_info[output_id].ldi_enabled) { free_descriptor(output_id); /* If no one has the syslog open, we should close it */ for (i = 0; i < PMIX_OUTPUT_MAX_STREAMS; ++i) { if (pmix_output_info[i].ldi_used && pmix_output_info[i].ldi_syslog) { break; } } #if defined(HAVE_SYSLOG) if (i >= PMIX_OUTPUT_MAX_STREAMS && syslog_opened) { closelog(); } #endif } } /* * Main function to send output to a stream */ PMIX_EXPORT void pmix_output(int output_id, const char *format, ...) { if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS) { va_list arglist; va_start(arglist, format); output(output_id, format, arglist); va_end(arglist); } } /* * Set the verbosity level of a stream */ void pmix_output_set_verbosity(int output_id, int level) { if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS) { pmix_output_info[output_id].ldi_verbose_level = level; } } /* * Control where output flies will go */ void pmix_output_set_output_file_info(const char *dir, const char *prefix, char **olddir, char **oldprefix) { if (NULL != olddir) { *olddir = strdup(output_dir); } if (NULL != oldprefix) { *oldprefix = strdup(output_prefix); } if (NULL != dir) { free(output_dir); output_dir = strdup(dir); } if (NULL != prefix) { free(output_prefix); output_prefix = strdup(prefix); } } void pmix_output_hexdump(int verbose_level, int output_id, void *ptr, int buflen) { unsigned char *buf = (unsigned char *) ptr; char out_buf[1024]; int ret = 0; int out_pos = 0; int i, j; if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS && pmix_output_info[output_id].ldi_verbose_level >= verbose_level) { pmix_output_verbose(verbose_level, output_id, "dump data at %p %d bytes\n", ptr, buflen); for (i = 0; i < buflen; i += 16) { out_pos = 0; ret = snprintf(out_buf + out_pos, 1024, "%06x: ", i); if (ret < 0) { return; } out_pos += ret; for (j = 0; j < 16; j++) { if (1023 < (out_pos+2)) { return; } if (i + j < buflen) { ret = snprintf(out_buf + out_pos, 1024, "%02x ", buf[i + j]); } else { ret = snprintf(out_buf + out_pos, 1024, " "); } if (ret < 0) { return; } out_pos += ret; } if (1023 < (out_pos+1)) { return; } ret = snprintf(out_buf + out_pos, 1024, " "); if (ret < 0) { return; } out_pos += ret; for (j = 0; j < 16; j++) { if (1023 < (out_pos+1)) { return; } if (i + j < buflen) { ret = snprintf(out_buf + out_pos, 1024, "%c", isprint(buf[i + j]) ? buf[i + j] : '.'); if (ret < 0) { return; } out_pos += ret; } } if (1023 < (out_pos+1)) { return; } ret = snprintf(out_buf + out_pos, 1024, "\n"); if (ret < 0) { return; } pmix_output_verbose(verbose_level, output_id, "%s", out_buf); } } } /* * Shut down the output stream system */ void pmix_output_finalize(void) { if (initialized) { if (verbose_stream != -1) { pmix_output_close(verbose_stream); } free(verbose.lds_prefix); verbose_stream = -1; free(output_prefix); free(output_dir); PMIX_DESTRUCT(&verbose); initialized = false; } } /************************************************************************/ /* * Constructor */ static void construct(pmix_object_t *obj) { pmix_output_stream_t *stream = (pmix_output_stream_t *) obj; stream->lds_verbose_level = 0; stream->lds_syslog_priority = 0; stream->lds_syslog_ident = NULL; stream->lds_prefix = NULL; stream->lds_suffix = NULL; stream->lds_is_debugging = false; stream->lds_want_syslog = false; stream->lds_want_stdout = false; stream->lds_want_stderr = false; stream->lds_want_file = false; stream->lds_want_file_append = false; stream->lds_file_suffix = NULL; } static void destruct(pmix_object_t *obj) { pmix_output_stream_t *stream = (pmix_output_stream_t *) obj; if (NULL != stream->lds_file_suffix) { free(stream->lds_file_suffix); stream->lds_file_suffix = NULL; } } /* * Back-end of open() and reopen(). */ static int do_open(int output_id, pmix_output_stream_t *lds) { int i; bool redirect_to_file = false; char *str, *sfx; /* Setup */ if (!initialized) { pmix_output_init(); } str = getenv("PMIX_OUTPUT_REDIRECT"); if (NULL != str && 0 == strcasecmp(str, "file")) { redirect_to_file = true; } sfx = getenv("PMIX_OUTPUT_SUFFIX"); /* If output_id == -1, find an available stream, or return * PMIX_ERROR */ if (-1 == output_id) { for (i = 0; i < PMIX_OUTPUT_MAX_STREAMS; ++i) { if (!pmix_output_info[i].ldi_used) { break; } } if (i >= PMIX_OUTPUT_MAX_STREAMS) { return PMIX_ERR_OUT_OF_RESOURCE; } } /* Otherwise, we're reopening, so we need to free all previous * resources, close files, etc. */ else { free_descriptor(output_id); i = output_id; } /* Special case: if we got NULL for lds, then just use the default * verbose */ if (NULL == lds) { lds = &verbose; } /* Got a stream -- now initialize it and open relevant outputs */ pmix_output_info[i].ldi_used = true; pmix_output_info[i].ldi_enabled = lds->lds_is_debugging ? (bool) PMIX_ENABLE_DEBUG : true; pmix_output_info[i].ldi_verbose_level = lds->lds_verbose_level; #if USE_SYSLOG # if defined(HAVE_SYSLOG) if (pmix_output_redirected_to_syslog) { pmix_output_info[i].ldi_syslog = true; pmix_output_info[i].ldi_syslog_priority = pmix_output_redirected_syslog_pri; if (NULL != redirect_syslog_ident) { pmix_output_info[i].ldi_syslog_ident = strdup(redirect_syslog_ident); openlog(redirect_syslog_ident, LOG_PID, LOG_USER); } else { pmix_output_info[i].ldi_syslog_ident = NULL; openlog("pmix", LOG_PID, LOG_USER); } syslog_opened = true; } else { # endif pmix_output_info[i].ldi_syslog = lds->lds_want_syslog; if (lds->lds_want_syslog) { # if defined(HAVE_SYSLOG) if (NULL != lds->lds_syslog_ident) { pmix_output_info[i].ldi_syslog_ident = strdup(lds->lds_syslog_ident); openlog(lds->lds_syslog_ident, LOG_PID, LOG_USER); } else { pmix_output_info[i].ldi_syslog_ident = NULL; openlog("pmix", LOG_PID, LOG_USER); } # endif syslog_opened = true; pmix_output_info[i].ldi_syslog_priority = lds->lds_syslog_priority; } # if defined(HAVE_SYSLOG) } # endif #else pmix_output_info[i].ldi_syslog = false; #endif if (NULL != lds->lds_prefix) { pmix_output_info[i].ldi_prefix = strdup(lds->lds_prefix); pmix_output_info[i].ldi_prefix_len = (int) strlen(lds->lds_prefix); } else { pmix_output_info[i].ldi_prefix = NULL; pmix_output_info[i].ldi_prefix_len = 0; } if (NULL != lds->lds_suffix) { pmix_output_info[i].ldi_suffix = strdup(lds->lds_suffix); pmix_output_info[i].ldi_suffix_len = (int) strlen(lds->lds_suffix); } else { pmix_output_info[i].ldi_suffix = NULL; pmix_output_info[i].ldi_suffix_len = 0; } if (pmix_output_redirected_to_syslog) { /* since all is redirected to syslog, ensure * we don't duplicate the output to the std places */ pmix_output_info[i].ldi_stdout = false; pmix_output_info[i].ldi_stderr = false; pmix_output_info[i].ldi_file = false; pmix_output_info[i].ldi_fd = -1; } else { /* since we aren't redirecting to syslog, use what was * given to us */ if (NULL != str && redirect_to_file) { pmix_output_info[i].ldi_stdout = false; pmix_output_info[i].ldi_stderr = false; pmix_output_info[i].ldi_file = true; } else { pmix_output_info[i].ldi_stdout = lds->lds_want_stdout; pmix_output_info[i].ldi_stderr = lds->lds_want_stderr; pmix_output_info[i].ldi_fd = -1; pmix_output_info[i].ldi_file = lds->lds_want_file; } if (NULL != sfx) { pmix_output_info[i].ldi_file_suffix = strdup(sfx); } else { pmix_output_info[i].ldi_file_suffix = (NULL == lds->lds_file_suffix) ? NULL : strdup(lds->lds_file_suffix); } pmix_output_info[i].ldi_file_want_append = lds->lds_want_file_append; pmix_output_info[i].ldi_file_num_lines_lost = 0; } /* Don't open a file in the session directory now -- do that lazily * so that if there's no output, we don't have an empty file */ return i; } static int open_file(int i) { int flags; char *filename; int n; /* first check to see if this file is already open * on someone else's stream - if so, we don't want * to open it twice */ for (n = 0; n < PMIX_OUTPUT_MAX_STREAMS; n++) { if (i == n) { continue; } if (!pmix_output_info[n].ldi_used) { continue; } if (!pmix_output_info[n].ldi_file) { continue; } if (NULL != pmix_output_info[i].ldi_file_suffix && NULL != pmix_output_info[n].ldi_file_suffix) { if (0 != strcmp(pmix_output_info[i].ldi_file_suffix, pmix_output_info[n].ldi_file_suffix)) { break; } } if (NULL == pmix_output_info[i].ldi_file_suffix && NULL != pmix_output_info[n].ldi_file_suffix) { break; } if (NULL != pmix_output_info[i].ldi_file_suffix && NULL == pmix_output_info[n].ldi_file_suffix) { break; } if (pmix_output_info[n].ldi_fd < 0) { break; } pmix_output_info[i].ldi_fd = pmix_output_info[n].ldi_fd; return PMIX_SUCCESS; } /* Setup the filename and open flags */ if (NULL != output_dir) { filename = (char *) malloc(PMIX_PATH_MAX); if (NULL == filename) { return PMIX_ERR_OUT_OF_RESOURCE; } pmix_strncpy(filename, output_dir, PMIX_PATH_MAX - 1); strcat(filename, "/"); if (NULL != output_prefix) { strcat(filename, output_prefix); } if (pmix_output_info[i].ldi_file_suffix != NULL) { strcat(filename, pmix_output_info[i].ldi_file_suffix); } else { pmix_output_info[i].ldi_file_suffix = NULL; strcat(filename, "output.txt"); } flags = O_CREAT | O_RDWR; if (!pmix_output_info[i].ldi_file_want_append) { flags |= O_TRUNC; } /* Actually open the file */ pmix_output_info[i].ldi_fd = open(filename, flags, 0644); free(filename); /* release the filename in all cases */ if (-1 == pmix_output_info[i].ldi_fd) { pmix_output_info[i].ldi_used = false; return PMIX_ERR_IN_ERRNO; } /* Make the file be close-on-exec to prevent child inheritance * problems */ if (-1 == fcntl(pmix_output_info[i].ldi_fd, F_SETFD, 1)) { return PMIX_ERR_IN_ERRNO; } } /* Return successfully even if the session dir did not exist yet; * we'll try opening it later */ return PMIX_SUCCESS; } /* * Free all the resources associated with a descriptor. */ static void free_descriptor(int output_id) { pmix_output_desc_t *ldi; if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS && pmix_output_info[output_id].ldi_used && pmix_output_info[output_id].ldi_enabled) { ldi = &pmix_output_info[output_id]; if (-1 != ldi->ldi_fd) { close(ldi->ldi_fd); } ldi->ldi_used = false; /* If we strduped a prefix, suffix, or syslog ident, free it */ if (NULL != ldi->ldi_prefix) { free(ldi->ldi_prefix); } ldi->ldi_prefix = NULL; if (NULL != ldi->ldi_suffix) { free(ldi->ldi_suffix); } ldi->ldi_suffix = NULL; if (NULL != ldi->ldi_file_suffix) { free(ldi->ldi_file_suffix); } ldi->ldi_file_suffix = NULL; if (NULL != ldi->ldi_syslog_ident) { free(ldi->ldi_syslog_ident); } ldi->ldi_syslog_ident = NULL; } } static int make_string(char **out, char **no_newline_string, pmix_output_desc_t *ldi, const char *format, va_list arglist) { size_t len, total_len, temp_str_len; bool want_newline = false; char *temp_str; /* Make the formatted string */ *out = NULL; if (0 > vasprintf(no_newline_string, format, arglist)) { return PMIX_ERR_NOMEM; } total_len = len = strlen(*no_newline_string); if ('\n' != (*no_newline_string)[len - 1]) { want_newline = true; ++total_len; } else if (NULL != ldi->ldi_suffix) { /* if we have a suffix, then we don't want a * newline to appear before it */ (*no_newline_string)[len - 1] = '\0'; want_newline = true; /* add newline to end after suffix */ /* total_len won't change since we just moved the newline * to appear after the suffix */ } if (NULL != ldi->ldi_prefix) { total_len += strlen(ldi->ldi_prefix); } if (NULL != ldi->ldi_suffix) { total_len += strlen(ldi->ldi_suffix); } temp_str = (char *) calloc((total_len * 2), sizeof(char)); if (NULL == temp_str) { return PMIX_ERR_OUT_OF_RESOURCE; } temp_str_len = total_len * 2; if (NULL != ldi->ldi_prefix && NULL != ldi->ldi_suffix) { if (want_newline) { pmix_snprintf(temp_str, temp_str_len, "%s%s%s\n", ldi->ldi_prefix, *no_newline_string, ldi->ldi_suffix); } else { pmix_snprintf(temp_str, temp_str_len, "%s%s%s", ldi->ldi_prefix, *no_newline_string, ldi->ldi_suffix); } } else if (NULL != ldi->ldi_prefix) { if (want_newline) { pmix_snprintf(temp_str, temp_str_len, "%s%s\n", ldi->ldi_prefix, *no_newline_string); } else { pmix_snprintf(temp_str, temp_str_len, "%s%s", ldi->ldi_prefix, *no_newline_string); } } else if (NULL != ldi->ldi_suffix) { if (want_newline) { pmix_snprintf(temp_str, temp_str_len, "%s%s\n", *no_newline_string, ldi->ldi_suffix); } else { pmix_snprintf(temp_str, temp_str_len, "%s%s", *no_newline_string, ldi->ldi_suffix); } } else { if (want_newline) { pmix_snprintf(temp_str, temp_str_len, "%s\n", *no_newline_string); } else { pmix_snprintf(temp_str, temp_str_len, "%s", *no_newline_string); } } *out = temp_str; return PMIX_SUCCESS; } /* * Do the actual output. Take a va_list so that we can be called from * multiple different places, even functions that took "..." as input * arguments. */ static int output(int output_id, const char *format, va_list arglist) { int rc = PMIX_SUCCESS; char *str = NULL, *out = NULL; pmix_output_desc_t *ldi; /* Setup */ if (!initialized) { pmix_output_init(); } /* If it's valid, used, and enabled, output */ if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS && pmix_output_info[output_id].ldi_used && pmix_output_info[output_id].ldi_enabled) { ldi = &pmix_output_info[output_id]; /* Make the strings */ if (PMIX_SUCCESS != (rc = make_string(&out, &str, ldi, format, arglist))) { goto cleanup; } /* Syslog output -- does not use the newline-appended string */ #if defined(HAVE_SYSLOG) if (ldi->ldi_syslog) { syslog(ldi->ldi_syslog_priority, "%s", str); } #endif /* stdout output */ if (ldi->ldi_stdout) { if (0 > write(fileno(stdout), out, (int) strlen(out))) { rc = PMIX_ERROR; goto cleanup; } fflush(stdout); } /* stderr output */ if (ldi->ldi_stderr) { if (0 > write((-1 == default_stderr_fd) ? fileno(stderr) : default_stderr_fd, out, (int) strlen(out))) { rc = PMIX_ERROR; goto cleanup; } fflush(stderr); } /* File output -- first check to see if the file opening was * delayed. If so, try to open it. If we failed to open it, * then just discard (there are big warnings in the * pmix_pmix_output.h docs about this!). */ if (ldi->ldi_file) { if (ldi->ldi_fd == -1) { if (PMIX_SUCCESS != open_file(output_id)) { ++ldi->ldi_file_num_lines_lost; } else if (ldi->ldi_file_num_lines_lost > 0 && 0 <= ldi->ldi_fd) { char buffer[BUFSIZ]; memset(buffer, 0, BUFSIZ); pmix_snprintf(buffer, BUFSIZ - 1, "[WARNING: %d lines lost because the PMIx process session directory " "did\n not exist when pmix_output() was invoked]\n", ldi->ldi_file_num_lines_lost); if (0 > write(ldi->ldi_fd, buffer, (int) strlen(buffer))) { rc = PMIX_ERROR; goto cleanup; } ldi->ldi_file_num_lines_lost = 0; } } if (ldi->ldi_fd != -1) { if (0 > write(ldi->ldi_fd, out, (int) strlen(out))) { rc = PMIX_ERROR; goto cleanup; } } } free(str); str = NULL; } cleanup: if (NULL != str) { free(str); } if (NULL != out) { free(out); } return rc; } int pmix_output_get_verbosity(int output_id) { if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS && pmix_output_info[output_id].ldi_used) { return pmix_output_info[output_id].ldi_verbose_level; } else { return -1; } } pmix-6.1.1~rc2/src/util/pmix_context_fns.c0000664000175000017500000001151615203536752021000 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2008 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_NETDB_H # include #endif #include #include "src/util/pmix_basename.h" #include "src/util/pmix_path.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_context_fns.h" pmix_status_t pmix_util_check_context_cwd(char **incwd, bool want_chdir, bool user_cwd) { bool good = true; const char *tmp; char *cwd = NULL; if (NULL == incwd) { return PMIX_ERR_BAD_PARAM; } if (NULL == *incwd) { return PMIX_SUCCESS; } cwd = *incwd; /* If we want to chdir and the chdir fails (for any reason -- such as if the dir doesn't exist, it isn't a dir, we don't have permissions, etc.), then return error. */ if (want_chdir && 0 != chdir(cwd)) { good = false; } /* If either of the above failed, go into this block */ if (!good) { /* See if the directory was a user-specified directory. If it was, barf because they specifically asked for something we can't provide. */ if (user_cwd) { /* does not exist, or we must lack permissions */ return PMIX_ERR_JOB_WDIR_NOT_ACCESSIBLE; } /* If the user didn't specifically ask for it, then it was a system-supplied default directory, so it's ok to not go there. Try to go to the $HOME directory instead. */ tmp = pmix_home_directory(-1); if (NULL != tmp) { /* Try $HOME. Same test as above. */ if (want_chdir && 0 != chdir(tmp)) { /* does not exist, or we must lack permissions */ return PMIX_ERR_JOB_WDIR_NOT_ACCESSIBLE; } /* Reset the pwd in this local copy of the context */ if (NULL != cwd) { free(cwd); } *incwd = strdup(tmp); } /* If we couldn't find $HOME, then just take whatever the default directory is -- assumedly there *is* one, or we wouldn't be running... */ } /* All happy */ return PMIX_SUCCESS; } pmix_status_t pmix_util_check_context_app(char **incmd, char *cwd, char **env) { char *tmp; char *cmd = *incmd; /* Here's the possibilities: 1. The caller specified an absolute pathname for the executable. We simply need to verify that it exists and we can run it. 2. The caller specified a relative pathname for the executable. Ditto with #1 -- based on the cwd, we need to verify that it exists and we can run it. 3. The caller specified a naked filename. We need to search the path, find a match, and verify that we can run it. */ tmp = pmix_basename(cmd); if (strlen(tmp) == strlen(cmd)) { /* If this is a naked executable -- no relative or absolute pathname -- then search the PATH for it */ free(tmp); tmp = pmix_path_findv(cmd, X_OK, env, cwd); if (NULL == tmp) { return PMIX_ERR_JOB_EXE_NOT_FOUND; } free(cmd); *incmd = tmp; } else { free(tmp); if (0 != access(cmd, X_OK)) { return PMIX_ERR_EXE_NOT_ACCESSIBLE; } } /* All was good */ return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/util/pmix_string_copy.c0000664000175000017500000000270115203536752021002 0ustar alastairalastair/* * Copyright (c) 2018-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include "src/util/pmix_string_copy.h" void pmix_string_copy(char *dest, const char *src, size_t dest_len) { size_t i; char *new_dest = dest; // PMIx does not do *giant* string copies. Hence, we use the // heuristic: if "dest_len" is too large, this is a programmer // error. We pseudo-arbitrarily pick a large value to be the max // allowable dest_len: 128K. If we ever need to increase this // value someday (because something has a legit reason to // pmix_string_copy() more than 128K), the core dumps that are // generated by the assert() failure should make this fairly // obvious. assert(dest_len <= PMIX_MAX_SIZE_ALLOWED_BY_PMIX_STRING_COPY); for (i = 0; i < dest_len; ++i, ++src, ++new_dest) { *new_dest = *src; if ('\0' == *src) { return; } } dest[dest_len - 1] = '\0'; } char *pmix_getline(FILE *fp) { char *ret, *buff; char input[1024]; ret = fgets(input, 1024, fp); if (NULL != ret) { input[strlen(input) - 1] = '\0'; /* remove newline */ buff = strdup(input); return buff; } return NULL; } pmix-6.1.1~rc2/src/util/pmix_error.h0000664000175000017500000000400715203536752017601 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_UTIL_ERROR_H #define PMIX_UTIL_ERROR_H #include "src/include/pmix_config.h" #include "pmix.h" #include "src/util/pmix_output.h" BEGIN_C_DECLS /* define a starting point for PMIx internal error codes * that are never exposed outside the library */ #define PMIX_INTERNAL_ERR_BASE -1330 /**** PMIX ERROR CONSTANTS ****/ /* internal error codes - never exposed outside of the library */ #define PMIX_ERR_FABRIC_NOT_PARSEABLE -1363 #define PMIX_ERR_TAKE_NEXT_OPTION -1366 #define PMIX_ERR_TEMP_UNAVAILABLE -1367 #define PMIX_INTERNAL_ERR_DONE -2000 #define PMIX_ERROR_LOG(r) \ do { \ if (PMIX_ERR_SILENT != (r)) { \ pmix_output(0, "PMIX ERROR: %s in file %s at line %d", PMIx_Error_string((r)), \ __FILE__, __LINE__); \ } \ } while (0) END_C_DECLS #endif /* PMIX_UTIL_ERROR_H */ pmix-6.1.1~rc2/src/util/pmix_basename.c0000664000175000017500000001024615203536752020220 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2009-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_STRING_H # include #endif /* HAVE_STRING_H */ #ifdef HAVE_LIBGEN_H # include #endif /* HAVE_LIBGEN_H */ #include "src/util/pmix_basename.h" #include "src/util/pmix_os_path.h" /** * Return a pointer into the original string where the last PATH delimiter * was found. It does not modify the original string. Moreover, it does not * scan the full string, but only the part allowed by the specified number * of characters. * If the last character on the string is a path separator, it will be skipped. */ static inline char *pmix_find_last_path_separator(const char *filename, size_t n) { char *p = (char *) filename + n; /* First skip the latest separators */ for (; p >= filename; p--) { if (*p != PMIX_PATH_SEP[0]) break; } for (; p >= filename; p--) { if (*p == PMIX_PATH_SEP[0]) return p; } return NULL; /* nothing found inside the filename */ } char *pmix_basename(const char *filename) { size_t i; char *tmp, *ret = NULL; const char sep = PMIX_PATH_SEP[0]; /* Check for the bozo case */ if (NULL == filename) { return NULL; } if (0 == strlen(filename)) { return strdup(""); } if (sep == filename[0] && '\0' == filename[1]) { return strdup(filename); } /* Remove trailing sep's (note that we already know that strlen > 0) */ tmp = strdup(filename); if (1 < strlen(tmp)) { for (i = strlen(tmp) - 1; i > 0; --i) { if (sep == tmp[i]) { tmp[i] = '\0'; } else { break; } } if (0 == i) { tmp[0] = sep; return tmp; } } /* Look for the final sep */ ret = pmix_find_last_path_separator(tmp, strlen(tmp)); if (NULL == ret) { return tmp; } ret = strdup(ret + 1); free(tmp); return ret; } char *pmix_dirname(const char *filename) { #if defined(HAVE_DIRNAME) || PMIX_HAVE_DIRNAME char *safe_tmp = strdup(filename), *result; result = strdup(dirname(safe_tmp)); free(safe_tmp); return result; #else const char *p = pmix_find_last_path_separator(filename, strlen(filename)); /* NOTE: p will be NULL if no path separator was in the filename - i.e., * if filename is just a local file */ for (; NULL != p && p != filename; p--) { if ((*p == '\\') || (*p == '/')) { /* If there are several delimiters remove them all */ for (--p; p != filename; p--) { if ((*p != '\\') && (*p != '/')) { p++; break; } } if (p != filename) { char *ret = (char *) calloc((p - filename + 1), sizeof(char)); pmix_strncpy(ret, filename, p - filename); ret[p - filename] = '\0'; return pmix_make_filename_os_friendly(ret); } break; /* return the duplicate of "." */ } } return strdup("."); #endif /* defined(HAVE_DIRNAME) || PMIX_HAVE_DIRNAME */ } pmix-6.1.1~rc2/src/util/pmix_few.c0000664000175000017500000000420715203536752017226 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include #ifdef HAVE_SYS_WAIT_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #include "pmix_common.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_few.h" int pmix_few(char *argv[], int *status) { #if defined(HAVE_FORK) && defined(HAVE_EXECVE) && defined(HAVE_WAITPID) pid_t pid, ret; if ((pid = fork()) < 0) { return PMIX_ERROR; } /* Child execs. If it fails to exec, exit. */ else if (0 == pid) { execvp(argv[0], argv); exit(errno); } /* Parent loops waiting for the child to die. */ else { do { /* If the child exited, return */ if (pid == (ret = waitpid(pid, status, 0))) { break; } /* If waitpid was interrupted, loop around again */ else if (ret < 0) { if (EINTR == errno) { continue; } /* Otherwise, some bad juju happened -- need to quit */ return PMIX_ERROR; } } while (true); } /* Return the status to the caller */ return PMIX_SUCCESS; #else return PMIX_ERR_NOT_SUPPORTED; #endif } pmix-6.1.1~rc2/src/util/help-cli.txt0000664000175000017500000000371215203536752017502 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2009-2020 Cisco Systems, Inc. All rights reserved # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2022-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English general help file for PRTE CLI options. # [help] Help can be requested in two ways: - a directive to the cmd. For example, the command "%s --help" or "%s -h" will provide the high-level help output giving a general description of each available option. - an option to the help directive. For example, the command "%s --help foo" or "%s -h foo" will provide detailed help about the "foo" command line directive. # [unknown-option] Help was requested for an unknown option: Option: %s Please use the "%s --help" command to obtain a list of all supported options. # [unrecognized-option] The help system for %s does not recognize the following: Option: %s This might require help from the developers. # [version] Print version and exit # [verbose] Enable debug options - number of times specified sets level of verbosity (e.g., -vvv => 3rd level of debug information) # [short-no-long] A short option was provided to %s and recognized by the parser, but has no matching long option: Short option: %c This might require help from the developers. # [unregistered-option] An unrecognized option was included on the %s command line: Option: %s Please use the "%s --help" command to obtain a list of all supported options. # [short-arg-error] A short option was provided to %s and recognized by the parser, but included an argument while the option does not support one: Short option: %c Given argument: %s Please correct the command line and try again. # [missing-argument] An option was included on the %s command line that requires an argument, but no argument was given: Option: %s Please use the "%s --help %s" command to learn more about this option. pmix-6.1.1~rc2/src/util/pmix_alfg.h0000664000175000017500000000165515203536752017367 0ustar alastairalastair/* * Copyright (c) 2014 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_ALFG_H #define PMIX_ALFG_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_stdint.h" struct pmix_rng_buff_t { uint32_t alfg[127]; int tap1; int tap2; }; typedef struct pmix_rng_buff_t pmix_rng_buff_t; /* NOTE: UNLIKE OTHER PMIX FUNCTIONS, THIS FUNCTION RETURNS A 1 IF * SUCCESSFUL INSTEAD OF PMIX_SUCCESS */ PMIX_EXPORT int pmix_srand(pmix_rng_buff_t *buff, uint32_t seed); PMIX_EXPORT uint32_t pmix_rand(pmix_rng_buff_t *buff); PMIX_EXPORT int pmix_random(void); #endif /* PMIX_ALFG_H */ pmix-6.1.1~rc2/src/util/pmix_keyval_parse.h0000664000175000017500000000417115203536752021137 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file */ #ifndef PMIX_UTIL_KEYVAL_PARSE_H #define PMIX_UTIL_KEYVAL_PARSE_H #include "src/include/pmix_config.h" BEGIN_C_DECLS PMIX_EXPORT extern int pmix_util_keyval_parse_lineno; /** * Callback triggered for each key = value pair * * Callback triggered from pmix_util_keyval_parse for each key = value * pair. Both key and value will be pointers into static buffers. * The buffers must not be free()ed and contents may be overwritten * immediately after the callback returns. */ typedef void (*pmix_keyval_parse_fn_t)(const char *file, int lineno, const char *name, const char *value); /** * Parse \c filename, made up of key = value pairs. * * Parse \c filename, made up of key = value pairs. For each line * that appears to contain a key = value pair, \c callback will be * called exactly once. In a multithreaded context, calls to * pmix_util_keyval_parse() will serialize multiple calls. */ PMIX_EXPORT int pmix_util_keyval_parse(const char *filename, pmix_keyval_parse_fn_t callback); PMIX_EXPORT int pmix_util_keyval_parse_init(void); PMIX_EXPORT void pmix_util_keyval_parse_finalize(void); PMIX_EXPORT int pmix_util_keyval_save_internal_envars(pmix_keyval_parse_fn_t callback); END_C_DECLS #endif pmix-6.1.1~rc2/src/util/pmix_vmem.c0000664000175000017500000001454515203536752017417 0ustar alastairalastair/* * Copyright (c) 2021-2022 Triad National Security, LLC. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/util/pmix_vmem.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_error.h" #include "src/util/pmix_string_copy.h" #ifdef HAVE_ERRNO_H #include "errno.h" #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #include #define PMIX_VMEM_ALIGN2MB (2 * 1024 * 1024UL) #define PMIX_VMEM_ALIGN64MB (64 * 1024 * 1024UL) typedef enum { VMEM_MAP_FILE = 0, VMEM_MAP_ANONYMOUS = 1, VMEM_MAP_HEAP = 2, VMEM_MAP_STACK = 3, /** vsyscall/vdso/vvar shouldn't occur since we stop after stack. */ VMEM_MAP_OTHER = 4 } pmix_vmem_map_kind_t; static int parse_map_line( const char *line, unsigned long *beginp, unsigned long *endp, pmix_vmem_map_kind_t *kindp ) { const char *tmp = line, *next; unsigned long value; /* "beginaddr-endaddr " */ value = strtoull(tmp, (char **) &next, 16); if (next == tmp) { return PMIX_ERROR; } *beginp = (unsigned long) value; if (*next != '-') { return PMIX_ERROR; } tmp = next + 1; value = strtoull(tmp, (char **) &next, 16); if (next == tmp) { return PMIX_ERROR; } *endp = (unsigned long) value; tmp = next; if (*next != ' ') { return PMIX_ERROR; } tmp = next + 1; /* look for ending absolute path */ next = strchr(tmp, '/'); if (next) { *kindp = VMEM_MAP_FILE; } else { /* look for ending special tag [foo] */ next = strchr(tmp, '['); if (next) { if (!strncmp(next, "[heap]", 6)) { *kindp = VMEM_MAP_HEAP; } else if (!strncmp(next, "[stack]", 7)) { *kindp = VMEM_MAP_STACK; } else { char *end; if ((end = strchr(next, '\n')) != NULL) { *end = '\0'; } *kindp = VMEM_MAP_OTHER; } } else { *kindp = VMEM_MAP_ANONYMOUS; } } return PMIX_SUCCESS; } static pmix_status_t use_hole( unsigned long holebegin, unsigned long holesize, unsigned long *addrp, unsigned long size ) { unsigned long aligned; unsigned long middle = holebegin + holesize / 2; if (holesize < size) { return PMIX_ERROR; } /* try to align the middle of the hole on 64MB for POWER's 64k-page PMD */ aligned = (middle + PMIX_VMEM_ALIGN64MB) & ~(PMIX_VMEM_ALIGN64MB - 1); if (aligned + size <= holebegin + holesize) { *addrp = aligned; return PMIX_SUCCESS; } /* try to align the middle of the hole on 2MB for x86 PMD */ aligned = (middle + PMIX_VMEM_ALIGN2MB) & ~(PMIX_VMEM_ALIGN2MB - 1); if (aligned + size <= holebegin + holesize) { *addrp = aligned; return PMIX_SUCCESS; } /* just use the end of the hole */ *addrp = holebegin + holesize - size; return PMIX_SUCCESS; } pmix_status_t pmix_vmem_find_hole( pmix_vmem_hole_kind_t hkind, size_t *addrp, size_t size ) { unsigned long biggestbegin = 0; unsigned long biggestsize = 0; unsigned long prevend = 0; pmix_vmem_map_kind_t prevmkind = VMEM_MAP_OTHER; int in_libs = 0; FILE *file; char line[96]; file = fopen("/proc/self/maps", "r"); if (!file) { return PMIX_ERROR; } while (fgets(line, sizeof(line), file) != NULL) { unsigned long begin = 0, end = 0; pmix_vmem_map_kind_t mkind = VMEM_MAP_OTHER; if (!parse_map_line(line, &begin, &end, &mkind)) { switch (hkind) { case VMEM_HOLE_BEGIN: fclose(file); return use_hole(0, begin, addrp, size); case VMEM_HOLE_AFTER_HEAP: if (prevmkind == VMEM_MAP_HEAP && mkind != VMEM_MAP_HEAP) { /* only use HEAP when there's no other HEAP after it * (there can be several of them consecutively). */ fclose(file); return use_hole(prevend, begin - prevend, addrp, size); } break; case VMEM_HOLE_BEFORE_STACK: if (mkind == VMEM_MAP_STACK) { fclose(file); return use_hole(prevend, begin - prevend, addrp, size); } break; case VMEM_HOLE_IN_LIBS: /* see if we are between heap and stack */ if (prevmkind == VMEM_MAP_HEAP) { in_libs = 1; } if (mkind == VMEM_MAP_STACK) { in_libs = 0; } if (!in_libs) { /* we're not in libs, ignore this entry */ break; } /* we're in libs, consider this entry for searching the biggest hole below */ /* fallthrough */ case VMEM_HOLE_BIGGEST: if (begin - prevend > biggestsize) { biggestbegin = prevend; biggestsize = begin - prevend; } break; default: assert(0); } } while (!strchr(line, '\n')) { if (!fgets(line, sizeof(line), file)) { goto done; } } if (mkind == VMEM_MAP_STACK) { /* Don't go beyond the stack. Other VMAs are special (vsyscall, vvar, vdso, etc), * There's no spare room there. And vsyscall is even above the userspace limit. */ break; } prevend = end; prevmkind = mkind; } done: fclose(file); if (hkind == VMEM_HOLE_IN_LIBS || hkind == VMEM_HOLE_BIGGEST) { return use_hole(biggestbegin, biggestsize, addrp, size); } return PMIX_ERROR; } pmix-6.1.1~rc2/src/util/pmix_os_dirpath.h0000664000175000017500000001074715203536752020614 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * Creates a directory tree set to the specified permissions. * * The pmix_os_dirpath_create() function creates a directory * tree, with each directory that is created in the tree having the specified * access permissions. Existing directories within the tree are left * untouched - however, if they do not permit the user to create a directory * within them, the function will return an error condition. * * If the specified full path name already exists, the * pmix_os_dirpath_create() function will check to ensure that * the final directory in the tree has at least the specified access permission. In other * words, if the directory has read-write-execute for all, and the user * has requested read-write access for just the user, then the function * will consider the directory acceptable. If the minimal permissions are * not currently provided, the function will attempt to change the * access permissions of the directory to add the specified * permissions. The function will return PMIX_ERROR if this cannot * be done. **/ #ifndef PMIX_OS_DIRPATH_CREATE_H #define PMIX_OS_DIRPATH_CREATE_H #include "src/include/pmix_config.h" #ifdef HAVE_SYS_STAT_H # include #endif BEGIN_C_DECLS /** * @param path A pointer to a string that contains the path name to be built. * @param mode A mode_t bit mask that specifies the access permissions for the * directories being constructed. * @retval PMIX_SUCCESS If the directory tree has been successfully created with * the specified access permissions. * @retval PMIX_ERROR If the directory tree could not be created with the * specified access permissions. */ PMIX_EXPORT int pmix_os_dirpath_create(const char *path, const mode_t mode); /** * Check to see if a directory is empty * * @param path A pointer to a string that contains the path name to be checked. * * @retval true If the directory is empty * @retval false If the directory is not empty */ PMIX_EXPORT bool pmix_os_dirpath_is_empty(const char *path); /** * Stale function left for PRRTE backward compatility */ PMIX_EXPORT int pmix_os_dirpath_access(const char *path, const mode_t mode); /** * Callback for pmix_os_dirpath_destroy(). Call for every file/directory before * taking action to remove/unlink it. * * @param root A pointer to a string that contains the base path name (e.g., /tmp/foo from * /tmp/foo/bar) * @param path A pointer to a string that contains the file or directory (e.g., bar from * /tmp/foo/bar) * * @retval true Allow the program to remove the file/directory * @retval false Do not allow the program to remove the file/directory */ typedef bool (*pmix_os_dirpath_destroy_callback_fn_t)(const char *root, const char *path); /** * Destroy a directory * * @param path A pointer to a string that contains the path name to be destroyed * @param recursive Recursively descend the directory removing all files and directories. * if set to 'false' then the directory must be empty to succeed. * @param cbfunc A function that will be called before removing a file or directory. * If NULL, then assume all remove. * * @retval PMIX_SUCCESS If the directory was successfully removed or removed to the * specification of the user (i.e., obeyed the callback function). * @retval PMIX_ERR_NOT_FOUND If directory does not exist. * @retval PMIX_ERROR If the directory cannot be removed, accessed properly, or contains * directories that could not be removed.. */ PMIX_EXPORT int pmix_os_dirpath_destroy(const char *path, bool recursive, pmix_os_dirpath_destroy_callback_fn_t cbfunc); END_C_DECLS #endif pmix-6.1.1~rc2/src/util/pmix_strnlen.h0000664000175000017500000000170615203536752020140 0ustar alastairalastair/* * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file * * Buffer strnlen function for portability to archaic platforms. */ #ifndef PMIX_STRNLEN_H #define PMIX_STRNLEN_H #include "src/include/pmix_config.h" #if defined(HAVE_STRNLEN) # define PMIX_STRNLEN(c, a, b) (c) = strnlen(a, b) #else # define PMIX_STRNLEN(c, a, b) \ do { \ size_t _x; \ (c) = 0; \ for (_x = 0; _x < (b); _x++) { \ if ('\0' == (a)[_x]) { \ break; \ } \ ++(c); \ } \ } while (0) #endif #endif /* PMIX_STRNLEN_H */ pmix-6.1.1~rc2/src/util/pmix_path.h0000664000175000017500000001276615203536752017417 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2016 University of Houston. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * @file */ #ifndef PMIX_PATH_H #define PMIX_PATH_H #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_UNISTD_H # include #endif BEGIN_C_DECLS /** * Locates a file with certain permissions * * @param fname File name * @param pathv Array of search directories * @param mode Permissions which must be satisfied (see access(2)) * @param envv Pointer to string containing environment * * @retval Full pathname of located file Success * @retval NULL Failure * * Environment variables can appear in the form $variable at the * start of a prefix path and will be replaced by the environment * value if it is defined; otherwise the whole prefix is ignored. * Environment variables must be followed by a path delimiter or * end-of-string. * * The caller is responsible for freeing the returned string. */ PMIX_EXPORT char *pmix_path_find(char *fname, char **pathv, int mode, char **envv) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__; /** * Locates a file with certain permissions from a list of search * paths * * @param fname File name * @param mode Target permissions which must be satisfied (see access(2)) * @param envv Pointer to environment list * @param wrkdir Working directory * * @retval Full pathname of located file Success * @retval NULL Failure * * Locates a file with certain permissions from the list of paths * given by the $PATH environment variable. Replaces "." in the * path with the working dir. * * The caller is responsible for freeing the returned string. */ PMIX_EXPORT char *pmix_path_findv(char *fname, int mode, char **envv, char *wrkdir) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__; /** * Detect if the requested path is absolute or relative. * * @param path File name * * @retval true if the path is absolute * @retval false otherwise * * Detect if a path is absolute or relative. Handle Windows * with special care as an absolute path on Windows starts * with [A-Za-z]: or \\ instead of the usual / on UNIX. */ PMIX_EXPORT bool pmix_path_is_absolute(const char *path); /** * Find the absolute path for an executable and return it. * * @param app_name Executable name * * @retval The absolute path if the application can be reached, * @retval NULL otherwise. * * Try to figure out the absolute path based on the application name * (usually argv[0]). If the path is already absolute return a copy, if * it start with . look into the current directory, if not dig into * the $PATH. * In case of error or if executable was not found (as an example if * the application did a cwd between the start and this call), the * function will return NULL. Otherwise, an newly allocated string * will be returned. */ PMIX_EXPORT char *pmix_find_absolute_path(char *app_name) __pmix_attribute_warn_unused_result__; /** * Forms a complete pathname and checks it for existence and * permissions * * @param fname File name * @param path Path prefix, if NULL then fname is an absolute path * @param mode Target permissions which must be satisfied (see access(2)) * * @retval NULL Failure * @retval Full pathname of the located file on Success * * The caller is responsible for freeing the returned string. */ PMIX_EXPORT char *pmix_path_access(char *fname, char *path, int mode) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__; /** * @brief Figure out whether fname is on network file system * and return fstype if known * * Try to figure out whether the file name specified through fname is * on any network file system (currently NFS, Lustre, GPFS, Panasas * and PVFS2 ). * * If the file is not created, the parent directory is checked. * This allows checking for NFS prior to opening the file. * * @fname[in] File name to check * @fstype[out] File system type if retval is true * * @retval true If fname is on NFS, Lustre or Panasas * @retval false otherwise */ PMIX_EXPORT bool pmix_path_nfs(char *fname, char **fstype) __pmix_attribute_warn_unused_result__; /** * @brief Returns the disk usage of path. * * @param[in] path Path to check * @out_avail[out] Amount of free space available on path (if successful) * * @retval PMIX_SUCCESS If the operation was successful * @retval PMIX_ERROR otherwise */ PMIX_EXPORT int pmix_path_df(const char *path, uint64_t *out_avail) __pmix_attribute_warn_unused_result__; END_C_DECLS #endif /* PMIX_PATH_H */ pmix-6.1.1~rc2/src/util/pmix_vmem.h0000664000175000017500000000167515203536752017424 0ustar alastairalastair/* * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_UTIL_VMEM_H #define PMIX_UTIL_VMEM_H #include "src/include/pmix_config.h" #include "include/pmix_common.h" typedef enum { VMEM_HOLE_NONE = -1, /** Use hole at the very beginning. */ VMEM_HOLE_BEGIN = 0, /** Use hole right after the heap. */ VMEM_HOLE_AFTER_HEAP = 1, /* Use hole right before stack. */ VMEM_HOLE_BEFORE_STACK = 2, /* Use the biggest hole. */ VMEM_HOLE_BIGGEST = 3, /* Use the biggest hole between heap and stack. */ VMEM_HOLE_IN_LIBS = 4, /* Use given address, if available. */ VMEM_HOLE_CUSTOM = 5 } pmix_vmem_hole_kind_t; PMIX_EXPORT pmix_status_t pmix_vmem_find_hole( pmix_vmem_hole_kind_t hkind, size_t *addrp, size_t size ); #endif pmix-6.1.1~rc2/src/util/pmix_shmem.h0000664000175000017500000000412415203536752017561 0ustar alastairalastair/* * Copyright (c) 2021-2023 Triad National Security, LLC. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_UTIL_SHMEM_H #define PMIX_UTIL_SHMEM_H #include "src/include/pmix_config.h" #include "include/pmix_common.h" #include "src/class/pmix_object.h" #include /** * Bitmap container for pmix_shmem flags. */ typedef uint8_t pmix_shmem_flags_t; typedef enum { /** * Indicates that during attach the requested address * must match the address returned by memory mapping. */ PMIX_SHMEM_MUST_MAP_AT_RADDR = 0x01 } pmix_shmem_flag_t; typedef struct pmix_shmem_t { /** Parent class. */ pmix_object_t super; /** Flag indicating if attached to segment. */ volatile bool attached; /** Size of shared-memory segment. */ size_t size; /** Address of shared memory segment header. */ void *hdr_address; /** Base data address of shared memory segment. */ void *data_address; /** Buffer holding path to backing store. */ char backing_path[PMIX_PATH_MAX]; } pmix_shmem_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_shmem_t); PMIX_EXPORT pmix_status_t pmix_shmem_segment_create( pmix_shmem_t *shmem, size_t size, const char *backing_path ); PMIX_EXPORT pmix_status_t pmix_shmem_segment_attach( pmix_shmem_t *shmem, uintptr_t desired_base_address, pmix_shmem_flags_t flags ); PMIX_EXPORT pmix_status_t pmix_shmem_segment_detach( pmix_shmem_t *shmem ); PMIX_EXPORT pmix_status_t pmix_shmem_segment_unlink( pmix_shmem_t *shmem ); /** * Change ownership of given shmem. Similar to chown(2). */ PMIX_EXPORT pmix_status_t pmix_shmem_segment_chown( pmix_shmem_t *shmem, uid_t owner, gid_t group ); /** * Change permissions of given shmem. Similar to chmod(2). */ PMIX_EXPORT pmix_status_t pmix_shmem_segment_chmod( pmix_shmem_t *shmem, mode_t mode ); /** * Returns size padded to page boundary. */ PMIX_EXPORT size_t pmix_shmem_utils_pad_to_page( size_t size ); #endif pmix-6.1.1~rc2/src/util/pmix_getid.h0000664000175000017500000000113515203536752017543 0ustar alastairalastair/* * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_GETID_H #define PMIX_GETID_H #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif BEGIN_C_DECLS /* lookup the effective uid and gid of a socket */ PMIX_EXPORT pmix_status_t pmix_util_getid(int sd, uid_t *uid, gid_t *gid); END_C_DECLS #endif /* PMIX_PRINTF_H */ pmix-6.1.1~rc2/src/util/pmix_keyval_parse.c0000664000175000017500000002500515203536752021131 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2016 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include "pmix_common.h" #include "src/util/keyval/keyval_lex.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_output.h" #include "src/util/pmix_string_copy.h" #include "src/threads/pmix_threads.h" int pmix_util_keyval_parse_lineno = 0; static char *key_buffer = NULL; static size_t key_buffer_len = 0; static pmix_mutex_t keyval_mutex; static int parse_line(const char *filename, pmix_keyval_parse_fn_t callback); static int parse_line_new(const char *filename, int first_val, pmix_keyval_parse_fn_t callback); static void parse_error(int num, const char *filename); static char *env_str = NULL; static int envsize = 1024; void pmix_util_keyval_parse_finalize(void) { free(key_buffer); key_buffer = NULL; key_buffer_len = 0; PMIX_DESTRUCT(&keyval_mutex); } int pmix_util_keyval_parse_init(void) { PMIX_CONSTRUCT(&keyval_mutex, pmix_mutex_t); return PMIX_SUCCESS; } int pmix_util_keyval_parse(const char *filename, pmix_keyval_parse_fn_t callback) { int val; int ret = PMIX_SUCCESS; ; pmix_mutex_lock(&keyval_mutex); /* Open the pmix */ pmix_util_keyval_yyin = fopen(filename, "r"); if (NULL == pmix_util_keyval_yyin) { ret = PMIX_ERR_NOT_FOUND; goto cleanup; } pmix_util_keyval_parse_done = false; pmix_util_keyval_yynewlines = 1; pmix_util_keyval_init_buffer(pmix_util_keyval_yyin); while (!pmix_util_keyval_parse_done) { val = pmix_util_keyval_yylex(); switch (val) { case PMIX_UTIL_KEYVAL_PARSE_DONE: /* This will also set pmix_util_keyval_parse_done to true, so just break here */ break; case PMIX_UTIL_KEYVAL_PARSE_NEWLINE: /* blank line! ignore it */ break; case PMIX_UTIL_KEYVAL_PARSE_SINGLE_WORD: parse_line(filename, callback); break; case PMIX_UTIL_KEYVAL_PARSE_MCAVAR: case PMIX_UTIL_KEYVAL_PARSE_ENVVAR: case PMIX_UTIL_KEYVAL_PARSE_ENVEQL: parse_line_new(filename, val, callback); break; default: /* anything else is an error */ parse_error(1, filename); break; } } fclose(pmix_util_keyval_yyin); pmix_util_keyval_yylex_destroy(); cleanup: pmix_mutex_unlock(&keyval_mutex); return ret; } static int parse_line(const char *filename, pmix_keyval_parse_fn_t callback) { int val; pmix_util_keyval_parse_lineno = pmix_util_keyval_yylineno; /* Save the name name */ if (key_buffer_len < strlen(pmix_util_keyval_yytext) + 1) { char *tmp; key_buffer_len = strlen(pmix_util_keyval_yytext) + 1; tmp = (char *) realloc(key_buffer, key_buffer_len); if (NULL == tmp) { free(key_buffer); key_buffer_len = 0; key_buffer = NULL; return PMIX_ERR_OUT_OF_RESOURCE; } key_buffer = tmp; } pmix_string_copy(key_buffer, pmix_util_keyval_yytext, key_buffer_len); /* The first thing we have to see is an "=" */ val = pmix_util_keyval_yylex(); if (pmix_util_keyval_parse_done || PMIX_UTIL_KEYVAL_PARSE_EQUAL != val) { parse_error(2, filename); return PMIX_ERROR; } /* Next we get the value */ val = pmix_util_keyval_yylex(); if (PMIX_UTIL_KEYVAL_PARSE_SINGLE_WORD == val || PMIX_UTIL_KEYVAL_PARSE_VALUE == val) { callback(filename, 0, key_buffer, pmix_util_keyval_yytext); /* Now we need to see the newline */ val = pmix_util_keyval_yylex(); if (PMIX_UTIL_KEYVAL_PARSE_NEWLINE == val || PMIX_UTIL_KEYVAL_PARSE_DONE == val) { return PMIX_SUCCESS; } } /* Did we get an EOL or EOF? */ else if (PMIX_UTIL_KEYVAL_PARSE_DONE == val || PMIX_UTIL_KEYVAL_PARSE_NEWLINE == val) { callback(filename, 0, key_buffer, NULL); return PMIX_SUCCESS; } /* Nope -- we got something unexpected. Bonk! */ parse_error(3, filename); return PMIX_ERROR; } static void parse_error(int num, const char *filename) { /* JMS need better error/warning message here */ pmix_output(0, "keyval parser: error %d reading file %s at line %d:\n %s\n", num, filename, pmix_util_keyval_yynewlines, pmix_util_keyval_yytext); } static void trim_name(char *buffer, const char *prefix, const char *suffix) { char *pchr, *echr; size_t buffer_len; if (NULL == buffer) { return; } buffer_len = strlen(buffer); pchr = buffer; if (NULL != prefix) { size_t prefix_len = strlen(prefix); if (0 == strncmp(buffer, prefix, prefix_len)) { pchr += prefix_len; } } /* trim spaces at the beginning */ while (isspace(*pchr)) { pchr++; } /* trim spaces at the end */ echr = buffer + buffer_len; while (echr > buffer && isspace(*(echr - 1))) { echr--; } echr[0] = '\0'; if (NULL != suffix && (uintptr_t)(echr - buffer) > strlen(suffix)) { size_t suffix_len = strlen(suffix); echr -= suffix_len; if (0 == strncmp(echr, suffix, strlen(suffix))) { do { echr--; } while (isspace(*echr)); echr[1] = '\0'; } } if (buffer != pchr) { /* move the trimmed string to the beginning of the buffer */ memmove(buffer, pchr, strlen(pchr) + 1); } } static int save_param_name(void) { if (key_buffer_len < strlen(pmix_util_keyval_yytext) + 1) { char *tmp; key_buffer_len = strlen(pmix_util_keyval_yytext) + 1; tmp = (char *) realloc(key_buffer, key_buffer_len); if (NULL == tmp) { free(key_buffer); key_buffer_len = 0; key_buffer = NULL; return PMIX_ERR_OUT_OF_RESOURCE; } key_buffer = tmp; } pmix_string_copy(key_buffer, pmix_util_keyval_yytext, key_buffer_len); return PMIX_SUCCESS; } static int add_to_env_str(char *var, char *val) { int sz, varsz = 0, valsz = 0, new_envsize; void *tmp; if (NULL == var) { return PMIX_ERR_BAD_PARAM; } varsz = strlen(var); if (NULL != val) { valsz = strlen(val); /* account for '=' */ valsz += 1; } sz = 0; if (NULL != env_str) { sz = strlen(env_str); /* account for ';' */ sz += 1; } /* add required new size incl NULL byte */ sz += varsz + valsz + 1; /* make sure we have sufficient space */ new_envsize = envsize; while (new_envsize <= sz) { new_envsize *= 2; } if (NULL != env_str) { if (new_envsize > envsize) { tmp = realloc(env_str, new_envsize); if (NULL == tmp) { return PMIX_ERR_OUT_OF_RESOURCE; } env_str = tmp; } strcat(env_str, ";"); } else { env_str = calloc(1, new_envsize); if (NULL == env_str) { return PMIX_ERR_OUT_OF_RESOURCE; } } envsize = new_envsize; strcat(env_str, var); if (NULL != val) { strcat(env_str, "="); strcat(env_str, val); } return PMIX_SUCCESS; } static int parse_line_new(const char *filename, int first_val, pmix_keyval_parse_fn_t callback) { int val; char *tmp; int rc; val = first_val; while (PMIX_UTIL_KEYVAL_PARSE_NEWLINE != val && PMIX_UTIL_KEYVAL_PARSE_DONE != val) { rc = save_param_name(); if (PMIX_SUCCESS != rc) { return rc; } if (PMIX_UTIL_KEYVAL_PARSE_MCAVAR == val) { trim_name(key_buffer, "-mca", NULL); trim_name(key_buffer, "--mca", NULL); val = pmix_util_keyval_yylex(); if (PMIX_UTIL_KEYVAL_PARSE_VALUE == val) { if (NULL != pmix_util_keyval_yytext) { tmp = strdup(pmix_util_keyval_yytext); if ('\'' == tmp[0] || '\"' == tmp[0]) { trim_name(tmp, "\'", "\'"); trim_name(tmp, "\"", "\""); } callback(filename, 0, key_buffer, tmp); free(tmp); } } else { parse_error(4, filename); return PMIX_ERROR; } } else if (PMIX_UTIL_KEYVAL_PARSE_ENVEQL == val) { trim_name(key_buffer, "-x", "="); trim_name(key_buffer, "--x", NULL); val = pmix_util_keyval_yylex(); if (PMIX_UTIL_KEYVAL_PARSE_VALUE == val) { add_to_env_str(key_buffer, pmix_util_keyval_yytext); } else { parse_error(5, filename); return PMIX_ERROR; } } else if (PMIX_UTIL_KEYVAL_PARSE_ENVVAR == val) { trim_name(key_buffer, "-x", "="); trim_name(key_buffer, "--x", NULL); add_to_env_str(key_buffer, NULL); } else { /* we got something unexpected. Bonk! */ parse_error(6, filename); return PMIX_ERROR; } val = pmix_util_keyval_yylex(); } return PMIX_SUCCESS; } int pmix_util_keyval_save_internal_envars(pmix_keyval_parse_fn_t callback) { if (NULL != env_str && 0 < strlen(env_str)) { callback(NULL, 0, "mca_base_env_list_internal", env_str); free(env_str); env_str = NULL; } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/util/pmix_fd.c0000664000175000017500000001667615203536752017053 0ustar alastairalastair/* * Copyright (c) 2008-2022 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2009 Sandia National Laboratories. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #include #include #include #include #ifdef HAVE_PWD_H # include #endif #ifdef HAVE_DIRENT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include #include "src/util/pmix_error.h" #include "src/util/pmix_fd.h" #include "src/util/pmix_string_copy.h" #include "src/runtime/pmix_rte.h" /* * Simple loop over reading from a fd */ pmix_status_t pmix_fd_read(int fd, int len, void *buffer) { size_t l2; ssize_t rc; char *b = buffer; if (0 > len) { return PMIX_ERR_BAD_PARAM; } else if (0 == len) { return PMIX_SUCCESS; } l2 = len; while (l2 > 0) { rc = read(fd, b, l2); if (rc < 0 && (EAGAIN == errno || EINTR == errno)) { continue; } else if (rc > 0) { l2 -= rc; b += rc; } else if (0 == rc) { return PMIX_ERR_TIMEOUT; } else { return PMIX_ERR_IN_ERRNO; } } return PMIX_SUCCESS; } /* * Simple loop over writing to an fd */ pmix_status_t pmix_fd_write(int fd, int len, const void *buffer) { size_t l2; ssize_t rc; const char *b = buffer; if (0 > len) { return PMIX_ERR_BAD_PARAM; } else if (0 == len) { return PMIX_SUCCESS; } l2 = len; while (l2 > 0) { rc = write(fd, b, l2); if (rc < 0 && (EAGAIN == errno || EINTR == errno)) { continue; } else if (rc > 0) { l2 -= rc; b += rc; } else { return PMIX_ERR_IN_ERRNO; } } return PMIX_SUCCESS; } pmix_status_t pmix_fd_set_cloexec(int fd) { #ifdef FD_CLOEXEC int flags; /* Stevens says that we should get the fd's flags before we set them. So say we all. */ flags = fcntl(fd, F_GETFD, 0); if (-1 == flags) { return PMIX_ERR_IN_ERRNO; } if (fcntl(fd, F_SETFD, FD_CLOEXEC | flags) == -1) { return PMIX_ERR_IN_ERRNO; } #endif return PMIX_SUCCESS; } bool pmix_fd_is_regular(int fd) { struct stat buf; /* coverity[TOCTOU] */ if (fstat(fd, &buf)) { return false; } return S_ISREG(buf.st_mode); } bool pmix_fd_is_chardev(int fd) { struct stat buf; /* coverity[TOCTOU] */ if (fstat(fd, &buf)) { return false; } return S_ISCHR(buf.st_mode); } bool pmix_fd_is_blkdev(int fd) { struct stat buf; /* coverity[TOCTOU] */ if (fstat(fd, &buf)) { return false; } return S_ISBLK(buf.st_mode); } #if PMIX_ENABLE_IPV6 static char str[INET6_ADDRSTRLEN]; #else static char str[INET_ADDRSTRLEN]; #endif const char *pmix_fd_get_peer_name(int fd) { const char *ret = NULL; struct sockaddr sa; socklen_t slt = (socklen_t) sizeof(sa); int rc; memset(str, 0, sizeof(str)); rc = getpeername(fd, &sa, &slt); if (0 != rc) { pmix_string_copy(str, "Unknown", sizeof(str) - 1); ret = str; return ret; } if (sa.sa_family == AF_INET) { struct sockaddr_in *si; si = (struct sockaddr_in *) &sa; ret = inet_ntop(AF_INET, &(si->sin_addr), str, INET_ADDRSTRLEN); } #if PMIX_ENABLE_IPV6 else if (sa.sa_family == AF_INET6) { struct sockaddr_in6 *si6; si6 = (struct sockaddr_in6 *) &sa; ret = inet_ntop(AF_INET6, &(si6->sin6_addr), str, INET6_ADDRSTRLEN); } #endif else { // This string is guaranteed to be <= INET_ADDRSTRLEN memset(str, 0, sizeof(str)); pmix_string_copy(str, "Unknown", sizeof(str) - 1); ret = str; } return ret; } static int fdmax = -1; /* close all open file descriptors w/ exception of stdin/stdout/stderr and the pipe up to the parent. */ void pmix_close_open_file_descriptors(int protected_fd) { #if defined(__OSX__) DIR *dir = opendir("/dev/fd"); #else /* Linux */ DIR *dir = opendir("/proc/self/fd"); #endif /* defined(__OSX__) */ struct dirent *files; int dir_scan_fd = -1; if (NULL == dir) { goto slow; } /* grab the fd of the opendir above so we don't close in the * middle of the scan. */ dir_scan_fd = dirfd(dir); if (dir_scan_fd < 0) { goto slow; } while (NULL != (files = readdir(dir))) { if (!isdigit(files->d_name[0])) { continue; } int fd = strtol(files->d_name, NULL, 10); if (errno == EINVAL || errno == ERANGE) { closedir(dir); goto slow; } if (fd >= 3 && (-1 == protected_fd || fd != protected_fd) && fd != dir_scan_fd) { close(fd); } } closedir(dir); return; slow: // close *all* file descriptors -- slow if (0 > fdmax) { fdmax = sysconf(_SC_OPEN_MAX); } // On some OS's (e.g., macOS), the value returned by // sysconf(_SC_OPEN_MAX) can be set by the user via "ulimit -n X", // where X can be -1 (unlimited) or a positive integer. On macOS // in particular, if the user does not set this value, it's // unclear how the default value is chosen. Some users have // reported seeing arbitrarily large default values (in the // billions), resulting in a very large loop over close() that can // take minutes/hours to complete, leading the user to think that // the app has hung. To avoid this, ensure that we cap the max FD // that we'll try to close. This is not a perfect scheme, and // there's uncertainty on how the macOS default value works, so we // provide the pmix_maxfd MCA var to allow the user to set the max // FD value if needed. if (-1 == fdmax || pmix_maxfd < fdmax) { fdmax = pmix_maxfd; } for (int fd = 3; fd < fdmax; fd++) { if (fd != protected_fd) { close(fd); } } } int pmix_fd_dup2(int src, int target) { int ret; #ifdef HAVE_FILENO_UNLOCKED if (0 == target) { ret = dup2(src, fileno_unlocked(stdin)); } else if (1 == target) { ret = dup2(src, fileno_unlocked(stdout)); } else if (2 == target) { ret = dup2(src, fileno_unlocked(stderr)); } else { ret = dup2(src, target); } #else if (0 == target) { ret = dup2(src, fileno(stdin)); } else if (1 == target) { ret = dup2(src, fileno(stdout)); } else if (2 == target) { ret = dup2(src, fileno(stderr)); } else { ret = dup2(src, target); } #endif return ret; } pmix-6.1.1~rc2/src/util/keyval/0000775000175000017500000000000015203536752016534 5ustar alastairalastairpmix-6.1.1~rc2/src/util/keyval/keyval_lex.l0000664000175000017500000001067215203536752021062 0ustar alastairalastair%option nounput %option noinput %option yylineno %{ /* -*- C -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2020 Intel, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H #include #endif #include "src/util/keyval/keyval_lex.h" /* * local functions */ BEGIN_C_DECLS int pmix_util_keyval_yywrap(void); END_C_DECLS /* * global variables */ int pmix_util_keyval_yynewlines = 1; bool pmix_util_keyval_parse_done = false; char *pmix_util_keyval_string = NULL; %} WHITE [\f\t\v ] CHAR [A-Za-z0-9_\-\.] %x VALUE %x comment %x MCA_VALUE %% {WHITE}*\n { pmix_util_keyval_yynewlines++; return PMIX_UTIL_KEYVAL_PARSE_NEWLINE; } #.*\n { pmix_util_keyval_yynewlines++; return PMIX_UTIL_KEYVAL_PARSE_NEWLINE; } "//".*\n { pmix_util_keyval_yynewlines++; return PMIX_UTIL_KEYVAL_PARSE_NEWLINE; } "/*" { BEGIN(comment); return PMIX_UTIL_KEYVAL_PARSE_NEWLINE; } [^*\n]* ; /* Eat up non '*'s */ "*"+[^*/\n]* ; /* Eat '*'s not followed by a '/' */ \n { pmix_util_keyval_yynewlines++; return PMIX_UTIL_KEYVAL_PARSE_NEWLINE; } "*"+"/" { BEGIN(INITIAL); /* Done with Block Comment */ return PMIX_UTIL_KEYVAL_PARSE_NEWLINE; } {WHITE}*"="{WHITE}* { BEGIN(VALUE); return PMIX_UTIL_KEYVAL_PARSE_EQUAL; } {WHITE}+ ; /* whitespace */ {CHAR}+ { return PMIX_UTIL_KEYVAL_PARSE_SINGLE_WORD; } {WHITE}*\n { BEGIN(INITIAL); return PMIX_UTIL_KEYVAL_PARSE_NEWLINE; } [^\n]*[^\t \n]/[\t ]* { return PMIX_UTIL_KEYVAL_PARSE_VALUE; } [^\n \t]+ { BEGIN(INITIAL); return PMIX_UTIL_KEYVAL_PARSE_VALUE; } "'"[^\n]*"'"{WHITE}+ { BEGIN(INITIAL); return PMIX_UTIL_KEYVAL_PARSE_VALUE; } "\""[^\n]*"\""{WHITE}+ { BEGIN(INITIAL); return PMIX_UTIL_KEYVAL_PARSE_VALUE; } {WHITE}*\n { BEGIN(INITIAL); BEGIN(INITIAL); return PMIX_UTIL_KEYVAL_PARSE_NEWLINE; } "-"?"-mca"{WHITE}+{CHAR}+{WHITE}+ {BEGIN(MCA_VALUE); return PMIX_UTIL_KEYVAL_PARSE_MCAVAR; } "-"?"-x"{WHITE}+{CHAR}+{WHITE}*"="{WHITE}* {BEGIN(MCA_VALUE); return PMIX_UTIL_KEYVAL_PARSE_ENVEQL; } "-"?"-x"{WHITE}+{CHAR}+{WHITE}*/[^=] { return PMIX_UTIL_KEYVAL_PARSE_ENVVAR; } . { return PMIX_UTIL_KEYVAL_PARSE_ERROR; } %% /* Old flex (2.5.4a? and older) does not define a destroy function */ #if !defined(YY_FLEX_SUBMINOR_VERSION) #define YY_FLEX_SUBMINOR_VERSION 0 #endif #if (YY_FLEX_MAJOR_VERSION < 2) || (YY_FLEX_MAJOR_VERSION == 2 && (YY_FLEX_MINOR_VERSION < 5 || (YY_FLEX_MINOR_VERSION == 5 && YY_FLEX_SUBMINOR_VERSION < 5))) int pmix_util_keyval_yylex_destroy(void) { if (NULL != YY_CURRENT_BUFFER) { yy_delete_buffer(YY_CURRENT_BUFFER); #if defined(YY_CURRENT_BUFFER_LVALUE) YY_CURRENT_BUFFER_LVALUE = NULL; #else YY_CURRENT_BUFFER = NULL; #endif /* YY_CURRENT_BUFFER_LVALUE */ } return YY_NULL; } #endif int pmix_util_keyval_yywrap(void) { pmix_util_keyval_parse_done = true; return 1; } /* * Ensure that we have a valid yybuffer to use. Specifically, if this * scanner is invoked a second time, finish_parsing() (above) will * have been executed, and the current buffer will have been freed. * Flex doesn't recognize this fact because as far as it's concerned, * its internal state was already initialized, so it thinks it should * have a valid buffer. Hence, here we ensure to give it a valid * buffer. */ int pmix_util_keyval_init_buffer(FILE *file) { YY_BUFFER_STATE buf = yy_create_buffer(file, YY_BUF_SIZE); yy_switch_to_buffer(buf); return 0; } pmix-6.1.1~rc2/src/util/keyval/Makefile.am0000664000175000017500000000221115203536752020564 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved # Copyright (c) 2021 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_LFLAGS = -Ppmix_util_keyval_yy # we do NOT want picky compilers down here CFLAGS = $(PMIX_CFLAGS_BEFORE_PICKY) LEX_OUTPUT_ROOT = lex.pmix_util_keyval_yy noinst_LTLIBRARIES = libpmixutilkeyval.la # Source code files libpmixutilkeyval_la_SOURCES = \ keyval_lex.h \ keyval_lex.l MAINTAINERCLEANFILES = keyval_lex.c pmix-6.1.1~rc2/src/util/keyval/keyval_lex.h0000664000175000017500000000414315203536752021052 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_UTIL_KEYVAL_LEX_H_ #define PMIX_UTIL_KEYVAL_LEX_H_ #include "src/include/pmix_config.h" #ifdef malloc # undef malloc #endif #ifdef realloc # undef realloc #endif #ifdef free # undef free #endif #include #define PMIX_UTIL_KEYVAL_PARSE_DONE 0 #define PMIX_UTIL_KEYVAL_PARSE_ERROR 1 #define PMIX_UTIL_KEYVAL_PARSE_NEWLINE 2 #define PMIX_UTIL_KEYVAL_PARSE_EQUAL 3 #define PMIX_UTIL_KEYVAL_PARSE_SINGLE_WORD 4 #define PMIX_UTIL_KEYVAL_PARSE_VALUE 5 #define PMIX_UTIL_KEYVAL_PARSE_MCAVAR 6 #define PMIX_UTIL_KEYVAL_PARSE_ENVVAR 7 #define PMIX_UTIL_KEYVAL_PARSE_ENVEQL 8 #define PMIX_UTIL_KEYVAL_PARSE_MAX 9 int pmix_util_keyval_yylex(void); int pmix_util_keyval_init_buffer(FILE *file); int pmix_util_keyval_yylex_destroy(void); extern FILE *pmix_util_keyval_yyin; extern bool pmix_util_keyval_parse_done; extern char *pmix_util_keyval_yytext; extern int pmix_util_keyval_yynewlines; extern int pmix_util_keyval_yylineno; /* * Make lex-generated files not issue compiler warnings */ #define YY_STACK_USED 0 #define YY_ALWAYS_INTERACTIVE 0 #define YY_NEVER_INTERACTIVE 0 #define YY_MAIN 0 #define YY_NO_UNPUT 1 #define YY_SKIP_YYWRAP 1 #endif pmix-6.1.1~rc2/src/util/pmix_net.c0000664000175000017500000002765415203536752017246 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include #include #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_SOCKIO_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_NET_IF_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_IFADDRS_H # include #endif #include "src/runtime/pmix_rte.h" #include "src/threads/pmix_tsd.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_net.h" #include "src/util/pmix_output.h" #include "src/util/pmix_show_help.h" char *pmix_hostname_unknown = "UNKNOWN"; /* this function doesn't depend on sockaddr_h */ bool pmix_net_isaddr(const char *name) { struct addrinfo hint, *res = NULL; /* initialize the hint */ memset(&hint, '\0', sizeof hint); /* indicate that we don't know the family */ hint.ai_family = PF_UNSPEC; hint.ai_flags = AI_NUMERICHOST; if (0 != getaddrinfo(name, NULL, &hint, &res)) { /* the input wasn't a recognizable address */ return false; } /* we don't care what family - all we care is that * it is indeed an address */ freeaddrinfo(res); return true; } #ifdef HAVE_STRUCT_SOCKADDR_IN typedef struct private_ipv4_t { in_addr_t addr; uint32_t netmask_bits; } private_ipv4_t; static private_ipv4_t *private_ipv4 = NULL; static pmix_tsd_key_t hostname_tsd_key; static void hostname_cleanup(void *value) { if (NULL != value) free(value); } static char *get_hostname_buffer(void) { void *buffer; int ret; ret = pmix_tsd_getspecific(hostname_tsd_key, &buffer); if (PMIX_SUCCESS != ret) return NULL; if (NULL == buffer) { buffer = (void *) calloc((NI_MAXHOST + 1), sizeof(char)); ret = pmix_tsd_setspecific(hostname_tsd_key, buffer); } return (char *) buffer; } int pmix_net_init(void) { char **args, *arg; uint32_t a, b, c, d, bits, addr; int i, count, found_bad = 0; args = PMIx_Argv_split(pmix_net_private_ipv4, ';'); if (NULL != args) { count = PMIx_Argv_count(args); private_ipv4 = (private_ipv4_t *) calloc((count + 1), sizeof(private_ipv4_t)); if (NULL == private_ipv4) { pmix_output(0, "Unable to allocate memory for the private addresses array"); PMIx_Argv_free(args); goto do_local_init; } for (i = 0; i < count; i++) { arg = args[i]; (void) sscanf(arg, "%u.%u.%u.%u/%u", &a, &b, &c, &d, &bits); if ((a > 255) || (b > 255) || (c > 255) || (d > 255) || (bits > 32)) { if (0 == found_bad) { pmix_show_help("help-pmix-util.txt", "malformed net_private_ipv4", true, args[i]); found_bad = 1; } continue; } addr = (a << 24) | (b << 16) | (c << 8) | d; private_ipv4[i].addr = htonl(addr); private_ipv4[i].netmask_bits = bits; } private_ipv4[i].addr = 0; private_ipv4[i].netmask_bits = 0; PMIx_Argv_free(args); } do_local_init: return pmix_tsd_key_create(&hostname_tsd_key, hostname_cleanup); } int pmix_net_finalize(void) { free(private_ipv4); private_ipv4 = NULL; return PMIX_SUCCESS; } /* convert a CIDR prefixlen to netmask (in network byte order) */ uint32_t pmix_net_prefix2netmask(uint32_t prefixlen) { return htonl(((1 << prefixlen) - 1) << (32 - prefixlen)); } bool pmix_net_islocalhost(const struct sockaddr *addr) { switch (addr->sa_family) { case AF_INET: { const struct sockaddr_in *inaddr = (struct sockaddr_in *) addr; /* if it's in the 127. domain, it shouldn't be routed (0x7f == 127) */ if (0x7F000000 == (0x7F000000 & ntohl(inaddr->sin_addr.s_addr))) { return true; } return false; } case AF_INET6: { const struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *) addr; if (IN6_IS_ADDR_LOOPBACK(&inaddr->sin6_addr)) { return true; /* Bug, FIXME: check for 127.0.0.1/8 */ } return false; } default: pmix_output(0, "unhandled sa_family %d passed to pmix_net_islocalhost", addr->sa_family); return false; } } bool pmix_net_samenetwork(const struct sockaddr_storage *addr1, const struct sockaddr_storage *addr2, uint32_t plen) { uint32_t prefixlen; struct sockaddr a1, a2; memcpy(&a1, addr1, sizeof(a1)); memcpy(&a2, addr2, sizeof(a2)); if (a1.sa_family != a2.sa_family) { return false; // address families must be equal } switch (a1.sa_family) { case AF_INET: { if (0 == plen) { prefixlen = 32; } else { prefixlen = plen; } struct sockaddr_in inaddr1, inaddr2; /* Use temporary variables and memcpy's so that we don't run into bus errors on Solaris/SPARC */ memcpy(&inaddr1, addr1, sizeof(inaddr1)); memcpy(&inaddr2, addr2, sizeof(inaddr2)); uint32_t netmask = pmix_net_prefix2netmask(prefixlen); if ((inaddr1.sin_addr.s_addr & netmask) == (inaddr2.sin_addr.s_addr & netmask)) { return true; } return false; } case AF_INET6: { struct sockaddr_in6 inaddr1, inaddr2; /* Use temporary variables and memcpy's so that we don't run into bus errors on Solaris/SPARC */ memcpy(&inaddr1, addr1, sizeof(inaddr1)); memcpy(&inaddr2, addr2, sizeof(inaddr2)); struct in6_addr *a6_1 = (struct in6_addr *) &inaddr1.sin6_addr; struct in6_addr *a6_2 = (struct in6_addr *) &inaddr2.sin6_addr; if (0 == plen) { prefixlen = 64; } else { prefixlen = plen; } if (64 == prefixlen) { /* prefixlen is always /64, any other case would be routing. Compare the first eight bytes (64 bits) and hope that endianness is not an issue on any system as long as addresses are always stored in network byte order. */ if (((const uint32_t *) (a6_1))[0] == ((const uint32_t *) (a6_2))[0] && ((const uint32_t *) (a6_1))[1] == ((const uint32_t *) (a6_2))[1]) { return true; } } return false; } default: pmix_output(0, "unhandled sa_family %d passed to pmix_samenetwork", a1.sa_family); } return false; } bool pmix_net_addr_isipv6linklocal(const struct sockaddr *addr) { # if PMIX_ENABLE_IPV6 struct sockaddr_in6 if_addr; # endif switch (addr->sa_family) { # if PMIX_ENABLE_IPV6 case AF_INET6: if_addr.sin6_family = AF_INET6; if (1 != inet_pton(AF_INET6, "fe80::0000", &if_addr.sin6_addr)) { return false; } return pmix_net_samenetwork((const struct sockaddr_storage *) addr, (const struct sockaddr_storage *) &if_addr, 64); # endif case AF_INET: return false; default: pmix_output(0, "unhandled sa_family %d passed to pmix_net_addr_isipv6linklocal\n", addr->sa_family); } return false; } /** * Returns true if the given address is a public IPv4 address. */ bool pmix_net_addr_isipv4public(const struct sockaddr *addr) { switch (addr->sa_family) { case AF_INET6: return false; case AF_INET: { const struct sockaddr_in *inaddr = (struct sockaddr_in *) addr; int i; if (NULL == private_ipv4) { return true; } for (i = 0; private_ipv4[i].addr != 0; i++) { if (private_ipv4[i].addr == (inaddr->sin_addr.s_addr & pmix_net_prefix2netmask(private_ipv4[i].netmask_bits))) return false; } } return true; default: pmix_output(0, "unhandled sa_family %d passed to pmix_net_addr_isipv4public\n", addr->sa_family); } return false; } char *pmix_net_get_hostname(const struct sockaddr *addr) { char *name = get_hostname_buffer(); int error; socklen_t addrlen; char *p; if (NULL == name) { pmix_output(0, "pmix_net_get_hostname: malloc() failed\n"); return pmix_hostname_unknown; } memset(name, 0, sizeof(*name)); switch (addr->sa_family) { case AF_INET: addrlen = sizeof(struct sockaddr_in); break; case AF_INET6: # if defined(__NetBSD__) /* hotfix for netbsd: on my netbsd machine, getnameinfo returns an unknown error code. */ if (NULL == inet_ntop(AF_INET6, &((struct sockaddr_in6 *) addr)->sin6_addr, name, NI_MAXHOST)) { pmix_output(0, "pmix_sockaddr2str failed with error code %d", errno); return pmix_hostname_unknown; } return name; # else addrlen = sizeof(struct sockaddr_in6); # endif break; default: return pmix_hostname_unknown; } error = getnameinfo(addr, addrlen, name, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (error) { int err = errno; pmix_output(0, "pmix_sockaddr2str failed:%s (return code %i)\n", gai_strerror(err), error); return pmix_hostname_unknown; } /* strip any trailing % data as it isn't pertinent */ if (NULL != (p = strrchr(name, '%'))) { *p = '\0'; } return name; } int pmix_net_get_port(const struct sockaddr *addr) { switch (addr->sa_family) { case AF_INET: return ntohs(((struct sockaddr_in *) addr)->sin_port); case AF_INET6: return ntohs(((struct sockaddr_in6 *) addr)->sin6_port); } return -1; } #else /* HAVE_STRUCT_SOCKADDR_IN */ int pmix_net_init(void) { return PMIX_SUCCESS; } int pmix_net_finalize(void) { return PMIX_SUCCESS; } uint32_t pmix_net_prefix2netmask(uint32_t prefixlen) { return 0; } bool pmix_net_islocalhost(const struct sockaddr *addr) { return false; } bool pmix_net_samenetwork(const struct sockaddr_storage *addr1, const struct sockaddr_storage *addr2, uint32_t prefixlen) { return false; } bool pmix_net_addr_isipv6linklocal(const struct sockaddr *addr) { return false; } bool pmix_net_addr_isipv4public(const struct sockaddr *addr) { return false; } char *pmix_net_get_hostname(const struct sockaddr *addr) { return NULL; } int pmix_net_get_port(const struct sockaddr *addr) { return -1; } #endif /* HAVE_STRUCT_SOCKADDR_IN */ pmix-6.1.1~rc2/src/util/pmix_getid.c0000664000175000017500000000556015203536752017544 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2013 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* * Buffer safe printf functions for portability to archaic platforms. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_socket_errno.h" #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include "src/include/pmix_globals.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_getid.h" pmix_status_t pmix_util_getid(int sd, uid_t *uid, gid_t *gid) { #if defined(SO_PEERCRED) # ifdef HAVE_STRUCT_SOCKPEERCRED_UID # define HAVE_STRUCT_UCRED_UID struct sockpeercred ucred; # else struct ucred ucred; # endif socklen_t crlen = sizeof(ucred); #endif #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID)) /* Ignore received 'cred' and validate ucred for socket instead. */ pmix_output_verbose(2, pmix_globals.debug_output, "getid: checking getsockopt for peer credentials"); if (getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &ucred, &crlen) < 0) { pmix_output_verbose(2, pmix_globals.debug_output, "getid: getsockopt SO_PEERCRED failed: %s", strerror(pmix_socket_errno)); return PMIX_ERR_INVALID_CRED; } # if defined(HAVE_STRUCT_UCRED_UID) *uid = ucred.uid; *gid = ucred.gid; # else *uid = ucred.cr_uid; *gid = ucred.cr_gid; # endif #elif defined(HAVE_GETPEEREID) pmix_output_verbose(2, pmix_globals.debug_output, "getid: checking getpeereid for peer credentials"); if (0 != getpeereid(sd, uid, gid)) { pmix_output_verbose(2, pmix_globals.debug_output, "getid: getsockopt getpeereid failed: %s", strerror(pmix_socket_errno)); return PMIX_ERR_INVALID_CRED; } #else PMIX_HIDE_UNUSED_PARAMS(sd, uid, gid); return PMIX_ERR_NOT_SUPPORTED; #endif return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/util/pmix_if.c0000664000175000017500000005410215203536752017042 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2010-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015-2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_SOCKIO_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_NET_IF_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_IFADDRS_H # include #endif #include #include "src/class/pmix_list.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_net.h" #include "src/util/pmix_output.h" #include "src/util/pmix_if.h" #include "src/util/pmix_show_help.h" #include "src/mca/pif/base/base.h" #ifdef HAVE_STRUCT_SOCKADDR_IN # ifndef MIN # define MIN(a, b) ((a) < (b) ? (a) : (b)) # endif /* * Look for interface by name and returns its * corresponding pmix_list index. */ int pmix_ifnametoindex(const char *if_name) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (*(intf->if_name) != '\0') { // required by gcc 13.0 - not sure why if (strncmp(intf->if_name, if_name, PMIX_IF_NAMESIZE-1) == 0) { return intf->if_index; } } } return -1; } /* * Look for interface by name and returns its * corresponding kernel index. */ int16_t pmix_ifnametokindex(const char *if_name) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (*(intf->if_name) != '\0') { // required by gcc 13.0 - not sure why if (strncmp(intf->if_name, if_name, PMIX_IF_NAMESIZE-1) == 0) { return intf->if_kernel_index; } } } return -1; } /* * Look for interface by pmix_list index and returns its * corresponding kernel index. */ int pmix_ifindextokindex(int if_index) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (if_index == intf->if_index) { return intf->if_kernel_index; } } return -1; } /* * Attempt to resolve the address (given as either IPv4/IPv6 string * or hostname) and lookup corresponding interface. */ int pmix_ifaddrtoname(const char *if_addr, char *if_name, int length) { pmix_pif_t *intf; int error; struct addrinfo hints, *res = NULL, *r; /* if the user asked us not to resolve interfaces, then just return */ if (pmix_if_do_not_resolve) { /* return not found so ifislocal will declare * the node to be non-local */ return PMIX_ERR_NOT_FOUND; } memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(if_addr, NULL, &hints, &res); if (error) { if (NULL != res) { freeaddrinfo(res); } return PMIX_ERR_NOT_FOUND; } memset(if_name, 0, length); for (r = res; r != NULL; r = r->ai_next) { for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (AF_INET == r->ai_family) { struct sockaddr_in ipv4; struct sockaddr_in *inaddr; inaddr = (struct sockaddr_in *) &intf->if_addr; memcpy(&ipv4, r->ai_addr, r->ai_addrlen); if (inaddr->sin_addr.s_addr == ipv4.sin_addr.s_addr) { pmix_strncpy(if_name, intf->if_name, length - 1); freeaddrinfo(res); return PMIX_SUCCESS; } } else { if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *) &intf->if_addr)->sin6_addr, &((struct sockaddr_in6 *) r->ai_addr)->sin6_addr)) { pmix_strncpy(if_name, intf->if_name, length - 1); freeaddrinfo(res); return PMIX_SUCCESS; } } } } if (NULL != res) { freeaddrinfo(res); } /* if we get here, it wasn't found */ return PMIX_ERR_NOT_FOUND; } /* * Attempt to resolve the address (given as either IPv4/IPv6 string * or hostname) and return the kernel index of the interface * on the same network as the specified address */ int16_t pmix_ifaddrtokindex(const char *if_addr) { pmix_pif_t *intf; int error; struct addrinfo hints, *res = NULL, *r; int if_kernel_index; size_t len; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(if_addr, NULL, &hints, &res); if (error) { if (NULL != res) { freeaddrinfo(res); } return PMIX_ERR_NOT_FOUND; } for (r = res; r != NULL; r = r->ai_next) { PMIX_LIST_FOREACH (intf, &pmix_if_list, pmix_pif_t) { if (AF_INET == r->ai_family && AF_INET == intf->af_family) { struct sockaddr_storage ipv4, intv4; len = (r->ai_addrlen < sizeof(struct sockaddr_in)) ? r->ai_addrlen : sizeof(struct sockaddr_in); memset(&ipv4, 0, sizeof(struct sockaddr_storage)); memcpy(&ipv4, r->ai_addr, len); memset(&intv4, 0, sizeof(struct sockaddr_storage)); memcpy(&intv4, &intf->if_addr, sizeof(struct sockaddr_in)); if (pmix_net_samenetwork(&ipv4, &intv4, intf->if_mask)) { if_kernel_index = intf->if_kernel_index; freeaddrinfo(res); return if_kernel_index; } } else if (AF_INET6 == r->ai_family && AF_INET6 == intf->af_family) { struct sockaddr_storage ipv6, intv6; len = (r->ai_addrlen < sizeof(struct sockaddr_in6)) ? r->ai_addrlen : sizeof(struct sockaddr_in6); memset(&ipv6, 0, sizeof(struct sockaddr_storage)); memcpy(&ipv6, r->ai_addr, len); memset(&intv6, 0, sizeof(struct sockaddr_storage)); memcpy(&intv6, &intf->if_addr, sizeof(struct sockaddr_in6)); if (pmix_net_samenetwork(&intv6, &ipv6, intf->if_mask)) { if_kernel_index = intf->if_kernel_index; freeaddrinfo(res); return if_kernel_index; } } } } if (NULL != res) { freeaddrinfo(res); } return PMIX_ERR_NOT_FOUND; } /* * Return the number of discovered interface. */ int pmix_ifcount(void) { return pmix_list_get_size(&pmix_if_list); } /* * Return the pmix_list interface index for the first * interface in our list. */ int pmix_ifbegin(void) { pmix_pif_t *intf; intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); if (NULL != intf) return intf->if_index; return (-1); } /* * Located the current position in the list by if_index and * return the interface index of the next element in our list * (if it exists). */ int pmix_ifnext(int if_index) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (intf->if_index == if_index) { do { pmix_pif_t *if_next = (pmix_pif_t *) pmix_list_get_next(intf); pmix_pif_t *if_end = (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); if (if_next == if_end) { return -1; } intf = if_next; } while (intf->if_index == if_index); return intf->if_index; } } return (-1); } /* * Lookup the interface by pmix_list index and return the * primary address assigned to the interface. */ int pmix_ifindextoaddr(int if_index, struct sockaddr *if_addr, unsigned int length) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (intf->if_index == if_index) { memcpy(if_addr, &intf->if_addr, MIN(length, sizeof(intf->if_addr))); return PMIX_SUCCESS; } } return PMIX_ERROR; } /* * Lookup the interface by pmix_list kindex and return the * primary address assigned to the interface. */ int pmix_ifkindextoaddr(int if_kindex, struct sockaddr *if_addr, unsigned int length) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (intf->if_kernel_index == if_kindex) { memcpy(if_addr, &intf->if_addr, MIN(length, sizeof(intf->if_addr))); return PMIX_SUCCESS; } } return PMIX_ERROR; } /* * Lookup the interface by pmix_list index and return the * network mask assigned to the interface. */ int pmix_ifindextomask(int if_index, uint32_t *if_mask, int length) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (intf->if_index == if_index) { memcpy(if_mask, &intf->if_mask, length); return PMIX_SUCCESS; } } return PMIX_ERROR; } /* * Lookup the interface by pmix_list index and return the * MAC assigned to the interface. */ int pmix_ifindextomac(int if_index, uint8_t mac[6]) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (intf->if_index == if_index) { memcpy(mac, &intf->if_mac, 6); return PMIX_SUCCESS; } } return PMIX_ERROR; } /* * Lookup the interface by pmix_list index and return the * MTU assigned to the interface. */ int pmix_ifindextomtu(int if_index, int *mtu) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (intf->if_index == if_index) { *mtu = intf->ifmtu; return PMIX_SUCCESS; } } return PMIX_ERROR; } /* * Lookup the interface by pmix_list index and return the * flags assigned to the interface. */ int pmix_ifindextoflags(int if_index, uint32_t *if_flags) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (intf->if_index == if_index) { memcpy(if_flags, &intf->if_flags, sizeof(uint32_t)); return PMIX_SUCCESS; } } return PMIX_ERROR; } /* * Lookup the interface by pmix_list index and return * the associated name. */ int pmix_ifindextoname(int if_index, char *if_name, int length) { pmix_pif_t *intf; memset(if_name, 0, length); for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (intf->if_index == if_index) { pmix_strncpy(if_name, intf->if_name, length - 1); return PMIX_SUCCESS; } } return PMIX_ERROR; } /* * Lookup the interface by kernel index and return * the associated name. */ int pmix_ifkindextoname(int if_kindex, char *if_name, int length) { pmix_pif_t *intf; memset(if_name, 0, length); for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (intf->if_kernel_index == if_kindex) { pmix_strncpy(if_name, intf->if_name, length - 1); return PMIX_SUCCESS; } } return PMIX_ERROR; } # define ADDRLEN 100 bool pmix_ifislocal(const char *hostname) { char addrname[NI_MAXHOST]; /* should be larger than ADDRLEN, but I think they really mean IFNAMESIZE */ if (PMIX_SUCCESS == pmix_ifaddrtoname(hostname, addrname, ADDRLEN)) { return true; } return false; } static int parse_ipv4_dots(const char *addr, uint32_t *net, int *dots) { const char *start = addr, *end; uint32_t n[] = {0, 0, 0, 0}; int i; /* now assemble the address */ for (i = 0; i < 4; i++) { n[i] = strtoul(start, (char **) &end, 10); if (end == start) { /* this is not an error, but indicates that * we were given a partial address - e.g., * 192.168 - usually indicating an IP range * in CIDR notation. So just return what we have */ break; } /* did we read something sensible? */ if (n[i] > 255) { return PMIX_ERR_FABRIC_NOT_PARSEABLE; } /* skip all the . */ for (start = end; '\0' != *start; start++) if ('.' != *start) break; } *dots = i; *net = PMIX_PIF_ASSEMBLE_FABRIC(n[0], n[1], n[2], n[3]); return PMIX_SUCCESS; } int pmix_iftupletoaddr(const char *inaddr, uint32_t *net, uint32_t *mask) { int pval, dots, rc = PMIX_SUCCESS; const char *ptr; /* if a mask was desired... */ if (NULL != mask) { /* set default */ *mask = 0xFFFFFFFF; /* if entry includes mask, split that off */ if (NULL != (ptr = strchr(inaddr, '/'))) { ptr = ptr + 1; /* skip the / */ /* is the mask a tuple? */ if (NULL != strchr(ptr, '.')) { /* yes - extract mask from it */ rc = parse_ipv4_dots(ptr, mask, &dots); } else { /* no - must be an int telling us how much of the addr to use: e.g., /16 * For more information please read http://en.wikipedia.org/wiki/Subnetwork. */ pval = strtol(ptr, NULL, 10); if ((pval > 31) || (pval < 1)) { pmix_output(0, "pmix_iftupletoaddr: unknown mask"); return PMIX_ERR_FABRIC_NOT_PARSEABLE; } *mask = 0xFFFFFFFF << (32 - pval); } } else { /* use the number of dots to determine it */ for (ptr = inaddr, pval = 0; '\0' != *ptr; ptr++) { if ('.' == *ptr) { pval++; } } /* if we have three dots, then we have four * fields since it is a full address, so the * default netmask is fine */ if (3 == pval) { *mask = 0xFFFFFFFF; } else if (2 == pval) { /* 2 dots */ *mask = 0xFFFFFF00; } else if (1 == pval) { /* 1 dot */ *mask = 0xFFFF0000; } else if (0 == pval) { /* no dots */ *mask = 0xFF000000; } else { pmix_output(0, "pmix_iftupletoaddr: unknown mask"); return PMIX_ERR_FABRIC_NOT_PARSEABLE; } } } /* if network addr is desired... */ if (NULL != net) { /* now assemble the address */ rc = parse_ipv4_dots(inaddr, net, &dots); } return rc; } /* * Determine if the specified interface is loopback */ bool pmix_ifisloopback(int if_index) { pmix_pif_t *intf; for (intf = (pmix_pif_t *) pmix_list_get_first(&pmix_if_list); intf != (pmix_pif_t *) pmix_list_get_end(&pmix_if_list); intf = (pmix_pif_t *) pmix_list_get_next(intf)) { if (intf->if_index == if_index) { if ((intf->if_flags & IFF_LOOPBACK) != 0) { return true; } } } return false; } /* Determine if an interface matches any entry in the given list, taking * into account that the list entries could be given as named interfaces, * IP addrs, or subnet+mask */ int pmix_ifmatches(int kidx, char **nets) { bool named_if; int i, rc; size_t j; int kindex; struct sockaddr_in inaddr; uint32_t addr, netaddr, netmask; /* get the address info for the given network in case we need it */ if (PMIX_SUCCESS != (rc = pmix_ifkindextoaddr(kidx, (struct sockaddr *) &inaddr, sizeof(inaddr)))) { return rc; } addr = ntohl(inaddr.sin_addr.s_addr); for (i = 0; NULL != nets[i]; i++) { /* if the specified interface contains letters in it, then it * was given as an interface name and not an IP tuple */ named_if = false; for (j = 0; j < strlen(nets[i]); j++) { if (isalpha(nets[i][j]) && '.' != nets[i][j]) { named_if = true; break; } } if (named_if) { if (0 > (kindex = pmix_ifnametokindex(nets[i]))) { continue; } if (kindex == kidx) { return PMIX_SUCCESS; } } else { if (PMIX_SUCCESS != (rc = pmix_iftupletoaddr(nets[i], &netaddr, &netmask))) { pmix_show_help("help-pmix-util.txt", "invalid-net-mask", true, nets[i]); return rc; } if (netaddr == (addr & netmask)) { return PMIX_SUCCESS; } } } /* get here if not found */ return PMIX_ERR_NOT_FOUND; } void pmix_ifgetaliases(char ***aliases) { pmix_pif_t *intf; char ipv4[INET_ADDRSTRLEN]; struct sockaddr_in *addr; # if PMIX_ENABLE_IPV6 char ipv6[INET6_ADDRSTRLEN]; struct sockaddr_in6 *addr6; # endif PMIX_LIST_FOREACH(intf, &pmix_if_list, pmix_pif_t) { addr = (struct sockaddr_in *) &intf->if_addr; /* ignore purely loopback interfaces */ if ((intf->if_flags & IFF_LOOPBACK) != 0) { continue; } /* ignore the obvious */ if (addr->sin_family == AF_INET) { inet_ntop(AF_INET, &(addr->sin_addr.s_addr), ipv4, INET_ADDRSTRLEN); if (0 == strcmp(ipv4, "localhost") || 0 == strcmp(ipv4, "127.0.0.1")) { continue; } PMIx_Argv_append_nosize(aliases, ipv4); } # if PMIX_ENABLE_IPV6 else { addr6 = (struct sockaddr_in6 *) &intf->if_addr; inet_ntop(AF_INET6, &(addr6->sin6_addr), ipv6, INET6_ADDRSTRLEN); PMIx_Argv_append_nosize(aliases, ipv6); } # endif } } #else /* HAVE_STRUCT_SOCKADDR_IN */ /* if we don't have struct sockaddr_in, we don't have traditional ethernet devices. Just make everything a no-op error call */ int pmix_ifaddrtoname(const char *if_addr, char *if_name, int size) { return PMIX_ERR_NOT_SUPPORTED; } int pmix_ifnametoindex(const char *if_name) { return PMIX_ERR_NOT_SUPPORTED; } int pmix_ifindextokindex(int if_index) { return PMIX_ERR_NOT_SUPPORTED; } int pmix_ifcount(void) { return PMIX_ERR_NOT_SUPPORTED; } int pmix_ifbegin(void) { return PMIX_ERR_NOT_SUPPORTED; } int pmix_ifnext(int if_index) { return PMIX_ERR_NOT_SUPPORTED; } int pmix_ifindextoname(int if_index, char *if_name, int length) { return PMIX_ERR_NOT_SUPPORTED; } int pmix_ifkindextoname(int kif_index, char *if_name, int length) { return PMIX_ERR_NOT_SUPPORTED; } int pmix_ifindextoaddr(int if_index, struct sockaddr *if_addr, unsigned int length) { return PMIX_ERR_NOT_SUPPORTED; } int pmix_ifindextomask(int if_index, uint32_t *if_addr, int length) { return PMIX_ERR_NOT_SUPPORTED; } bool pmix_ifislocal(const char *hostname) { return false; } int pmix_iftupletoaddr(const char *inaddr, uint32_t *net, uint32_t *mask) { return 0; } int pmix_ifmatches(int idx, char **nets) { return PMIX_ERR_NOT_SUPPORTED; } void pmix_ifgetaliases(char ***aliases) { return; } #endif /* HAVE_STRUCT_SOCKADDR_IN */ pmix-6.1.1~rc2/src/util/pmix_net.h0000664000175000017500000001135315203536752017240 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2017 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* @file */ #ifndef PMIX_UTIL_NET_H #define PMIX_UTIL_NET_H #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #include "pmix_common.h" BEGIN_C_DECLS /** * Initialize the network helper subsystem * * Initialize the network helper subsystem. Should be called exactly * once for any process that will use any function in the network * helper subsystem. * * @retval PMIX_SUCCESS Success * @retval PMIX_ERR_TEMP_OUT_OF_RESOURCE Not enough memory for static * buffer creation */ PMIX_EXPORT int pmix_net_init(void); /** * Finalize the network helper subsystem * * Finalize the network helper subsystem. Should be called exactly * once for any process that will use any function in the network * helper subsystem. * * @retval PMIX_SUCCESS Success */ PMIX_EXPORT int pmix_net_finalize(void); /** * Calculate netmask in network byte order from CIDR notation * * @param prefixlen (IN) CIDR prefixlen * @return netmask in network byte order */ PMIX_EXPORT uint32_t pmix_net_prefix2netmask(uint32_t prefixlen); /** * Determine if given IP address is in the localhost range * * Determine if the given IP address is in the localhost range * (127.0.0.0/8), meaning that it can't be used to connect to machines * outside the current host. * * @param addr struct sockaddr_in of IP address * @return true if \c addr is a localhost address, * false otherwise. */ PMIX_EXPORT bool pmix_net_islocalhost(const struct sockaddr *addr); /** * Are we on the same network? * * For IPv6, we only need to check for /64, there are no other * local netmasks. * * @param addr1 struct sockaddr of address * @param addr2 struct sockaddr of address * @param prefixlen netmask (either CIDR or IPv6 prefixlen) * @return true if \c addr1 and \c addr2 are on the * same net, false otherwise. */ PMIX_EXPORT bool pmix_net_samenetwork(const struct sockaddr_storage *addr1, const struct sockaddr_storage *addr2, uint32_t prefixlen); /** * Is the given address a link-local IPv6 address? Returns false for IPv4 * address. * * @param addr address as struct sockaddr * @return true, if \c addr is IPv6 link-local, false otherwise */ PMIX_EXPORT bool pmix_net_addr_isipv6linklocal(const struct sockaddr *addr); /** * Is the given address a public IPv4 address? Returns false for IPv6 * address. * * @param addr address as struct sockaddr * @return true, if \c addr is IPv4 public, false otherwise */ PMIX_EXPORT bool pmix_net_addr_isipv4public(const struct sockaddr *addr); /** * Get string version of address * * Return the un-resolved address in a string format. The string will * be returned in a per-thread static buffer and should not be freed * by the user. * * @param addr struct sockaddr of address * @return literal representation of \c addr */ PMIX_EXPORT char *pmix_net_get_hostname(const struct sockaddr *addr); /** * Get port number from struct sockaddr * * Return the port number (as an integr) from either a struct * sockaddr_in or a struct sockaddr_in6. * * @param addr struct sockaddr containing address * @return port number from \addr */ PMIX_EXPORT int pmix_net_get_port(const struct sockaddr *addr); /** * Test if a string is actually an IP address * * Returns true if the string is of IPv4 or IPv6 address form */ PMIX_EXPORT bool pmix_net_isaddr(const char *name); END_C_DECLS #endif /* PMIX_UTIL_NET_H */ pmix-6.1.1~rc2/src/util/pmix_getcwd.c0000664000175000017500000000400415203536752017715 0ustar alastairalastair/* * Copyright (c) 2007-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #include #include "src/util/pmix_basename.h" #include "src/util/pmix_getcwd.h" #include "src/util/pmix_string_copy.h" /* * Use $PWD instead of getcwd() a) if $PWD exists and b) is a valid * synonym for the results from getcwd(). If both of these conditions * are not met, just fall back and use the results of getcwd(). */ int pmix_getcwd(char *buf, size_t size) { char cwd[PMIX_PATH_MAX]; char *pwd = getenv("PWD"); char *shortened; /* Bozo checks (e.g., if someone accidentally passed -1 to the unsigned "size" param) */ if (NULL == buf || size > INT_MAX) { return PMIX_ERR_BAD_PARAM; } /* Call getcwd() to get a baseline result */ if (NULL == getcwd(cwd, sizeof(cwd))) { return PMIX_ERR_IN_ERRNO; } if (NULL == pwd) { pwd = cwd; } else { if (0 != strcmp(pwd, cwd)) { // fallback to getcwd value pwd = cwd; } } /* pwd is pointing to the result that we want to give. Ensure the user's buffer is long enough. If it is, copy in the value and be done. */ if (strlen(pwd) > size) { /* if it isn't big enough, give them as much * of the basename as possible */ shortened = pmix_basename(pwd); pmix_string_copy(buf, shortened, size); free(shortened); /* indicate that it isn't the full path */ return PMIX_ERR_OUT_OF_RESOURCE; } pmix_string_copy(buf, pwd, size); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/util/pmix_path.c0000664000175000017500000003265015203536752017404 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2009-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 IBM Corporation. All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 University of Houston. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SHLWAPI_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #ifdef HAVE_SYS_MOUNT_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_SYS_VFS_H # include #endif #ifdef HAVE_SYS_STATFS_H # include #endif #ifdef HAVE_SYS_STATVFS_H # include #endif #ifdef HAVE_MNTENT_H # include #endif #ifdef HAVE_PATHS_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef _PATH_MOUNTED # define MOUNTED_FILE _PATH_MOUNTED #else # define MOUNTED_FILE "/etc/mtab" #endif #include "src/include/pmix_globals.h" #include "src/include/pmix_stdint.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_output.h" #include "src/util/pmix_path.h" /* * Sanity check to ensure we have either statfs or statvfs */ #if !defined(HAVE_STATFS) && !defined(HAVE_STATVFS) # error Must have either statfs() or statvfs() #endif /* * Note that some OS's (e.g., NetBSD and Solaris) have statfs(), but * no struct statfs (!). So check to make sure we have struct statfs * before allowing the use of statfs(). */ #if defined(HAVE_STATFS) \ && (defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || defined(HAVE_STRUCT_STATFS_F_TYPE)) # define USE_STATFS 1 #endif static void path_env_load(char *path, int *pargc, char ***pargv); static char *list_env_get(char *var, char **list); bool pmix_path_is_absolute(const char *path) { if (PMIX_PATH_SEP[0] == *path) { return true; } return false; } /** * Locates a file with certain permissions */ char *pmix_path_find(char *fname, char **pathv, int mode, char **envv) { char *fullpath; char *delimit; char *env; char *pfix; int i; /* If absolute path is given, return it without searching. */ if (pmix_path_is_absolute(fname)) { return pmix_path_access(fname, NULL, mode); } /* Initialize. */ fullpath = NULL; i = 0; /* Consider each directory until the file is found. Thus, the order of directories is important. */ while (pathv[i] && NULL == fullpath) { /* Replace environment variable at the head of the string. */ if ('$' == *pathv[i]) { delimit = strchr(pathv[i], PMIX_PATH_SEP[0]); if (delimit) { *delimit = '\0'; } env = list_env_get(pathv[i] + 1, envv); if (delimit) { *delimit = PMIX_PATH_SEP[0]; } if (NULL != env) { if (!delimit) { fullpath = pmix_path_access(fname, env, mode); } else { pfix = (char *) calloc((strlen(env) + strlen(delimit) + 1), sizeof(char)); if (NULL == pfix) { return NULL; } strcpy(pfix, env); strcat(pfix, delimit); fullpath = pmix_path_access(fname, pfix, mode); free(pfix); } } } else { fullpath = pmix_path_access(fname, pathv[i], mode); } i++; } return pmix_make_filename_os_friendly(fullpath); } /* * Locates a file with certain permissions from a list of search paths */ char *pmix_path_findv(char *fname, int mode, char **envv, char *wrkdir) { char **dirv; char *fullpath; char *path; int dirc; int i; bool found_dot = false; /* Set the local search paths. */ dirc = 0; dirv = NULL; if (NULL != (path = list_env_get("PATH", envv))) { path_env_load(path, &dirc, &dirv); } /* Replace the "." path by the working directory. */ if (NULL != wrkdir) { for (i = 0; i < dirc; ++i) { if (0 == strcmp(dirv[i], ".")) { found_dot = true; free(dirv[i]); dirv[i] = strdup(wrkdir); if (NULL == dirv[i]) { return NULL; } } } } /* If we didn't find "." in the path and we have a wrkdir, append the wrkdir to the end of the path */ if (!found_dot && NULL != wrkdir) { pmix_argv_append(&dirc, &dirv, wrkdir); } if (NULL == dirv) { return NULL; } fullpath = pmix_path_find(fname, dirv, mode, envv); PMIx_Argv_free(dirv); return fullpath; } /** * Forms a complete pathname and checks it for existence and * permissions * * Accepts: * -fname File name * -path Path prefix * -mode Target permissions which must be satisfied * * Returns: * -Full pathname of located file Success * -NULL Failure */ char *pmix_path_access(char *fname, char *path, int mode) { char *fullpath = NULL; /* Allocate space for the full pathname. */ if (NULL == path) { fullpath = pmix_os_path(false, fname, NULL); } else { fullpath = pmix_os_path(false, path, fname, NULL); } if (NULL == fullpath) return NULL; if (0 != access(fullpath, mode)) { free(fullpath); return NULL; } /* must have met all criteria! */ return fullpath; } /** * * Loads argument array with $PATH env var. * * Accepts * -path String containing the $PATH * -argc Pointer to argc * -argv Pointer to list of argv */ static void path_env_load(char *path, int *pargc, char ***pargv) { char *p; char saved; if (NULL == path) { *pargc = 0; return; } /* Loop through the paths (delimited by PATHENVSEP), adding each one to argv. */ while ('\0' != *path) { /* Locate the delimiter. */ for (p = path; *p && (*p != PMIX_ENV_SEP); ++p) { continue; } /* Add the path. */ if (p != path) { saved = *p; *p = '\0'; pmix_argv_append(pargc, pargv, path); *p = saved; path = p; } /* Skip past the delimiter, if present. */ if (*path) { ++path; } } } /** * Gets value of variable in list or environment. Looks in the list first * * Accepts: * -var String variable * -list Pointer to environment list * * Returns: * -List Pointer to environment list Success * -NULL Failure */ static char *list_env_get(char *var, char **list) { size_t n; if (NULL != list) { n = strlen(var); while (NULL != *list) { if ((0 == strncmp(var, *list, n)) && ('=' == (*list)[n])) { return (*list + n + 1); } ++list; } } return getenv(var); } /** * Try to figure out the absolute path based on the application name * (usually argv[0]). If the path is already absolute return a copy, if * it start with . look into the current directory, if not dig into * the $PATH. * In case of error or if executable was not found (as an example if * the application did a cwd between the start and this call), the * function will return NULL. Otherwise, an newly allocated string * will be returned. */ char *pmix_find_absolute_path(char *app_name) { char *abs_app_name; char cwd[PMIX_PATH_MAX], *pcwd; if (pmix_path_is_absolute(app_name)) { /* already absolute path */ abs_app_name = app_name; } else if ('.' == app_name[0] || NULL != strchr(app_name, PMIX_PATH_SEP[0])) { /* the app is in the current directory or below it */ pcwd = getcwd(cwd, PMIX_PATH_MAX); if (NULL == pcwd) { /* too bad there is no way we can get the app absolute name */ return NULL; } abs_app_name = pmix_os_path(false, pcwd, app_name, NULL); } else { /* Otherwise try to search for the application in the PATH ... */ abs_app_name = pmix_path_findv(app_name, X_OK, NULL, NULL); } if (NULL != abs_app_name) { char *resolved_path = (char *) malloc(PMIX_PATH_MAX); if (NULL == realpath(abs_app_name, resolved_path)) { free(resolved_path); free(abs_app_name); return NULL; } if (abs_app_name != app_name) { free(abs_app_name); } return resolved_path; } return NULL; } /** * @brief Figure out whether fname is on network file system * * Try to figure out whether the file name specified through fname is * on any network file system (currently NFS, Lustre, Panasas and GPFS). * * @fname[in] File name to check * @fstype[out] File system type if retval is true * * @retval true If fname is on NFS, Lustre, Panasas or GPFS * @retval false otherwise * */ bool pmix_path_nfs(char *fname, char **fstype) { #ifdef HAVE_MNTENT_H struct stat s; struct mntent mnt; FILE *fp; dev_t dev; char buf[1024]; int fd, n; char* fs_types[] = { "lustre", "nfs", "autofs", "panfs", "gpfs", "pvfs2", NULL }; char *parent; fd = open(fname, O_RDONLY); if (0 > fd) { // try the parent parent = pmix_dirname(fname); fd = open(parent, O_RDONLY); free(parent); if (0 > fd) { // give up return false; } } if (fstat(fd, &s) != 0) { close(fd); return false; } close(fd); // retain the inode of the file dev = s.st_dev; // try a couple of possible locations for the // mount table if ((fp = setmntent("/proc/mounts", "r")) == NULL) { if ((fp = setmntent("/etc/mtab", "r")) == NULL) { return false; } } // search the mount table for an entry with // matching inode while (getmntent_r(fp, &mnt, buf, sizeof(buf))) { fd = open(mnt.mnt_dir, O_RDONLY); if (0 > fd) { // probably lack permissions continue; } if (fstat(fd, &s) != 0) { close(fd); continue; } if (s.st_dev == dev) { *fstype = strdup(mnt.mnt_type); close(fd); endmntent(fp); // check if this is a file system of concern for (n=0; NULL != fs_types[n]; n++) { if (0 == strcmp(fs_types[n], mnt.mnt_type)) { // yep, this is a shared file system return true; } } // if we get here, then this is not a file // system of concern return false; } close(fd); } endmntent(fp); // Should never reach here. return false; #else // cannot do anything PMIX_HIDE_UNUSED_PARAMS(fname, fstype); *fstype = strdup("unknown"); return false; #endif } int pmix_path_df(const char *path, uint64_t *out_avail) { int rc = -1; int trials = 5; int err = 0; #if defined(USE_STATFS) struct statfs buf; #elif defined(HAVE_STATVFS) struct statvfs buf; #endif if (NULL == path || NULL == out_avail) { return PMIX_ERROR; } *out_avail = 0; do { #if defined(USE_STATFS) rc = statfs(path, &buf); #elif defined(HAVE_STATVFS) rc = statvfs(path, &buf); #endif err = errno; } while (-1 == rc && ESTALE == err && (--trials > 0)); if (-1 == rc) { pmix_output_verbose(10, 2, "pmix_path_df: stat(v)fs on " "path: %s failed with errno: %d (%s)\n", path, err, strerror(err)); return PMIX_ERROR; } /* now set the amount of free space available on path */ /* sometimes buf.f_bavail is negative */ *out_avail = buf.f_bsize * ((int) buf.f_bavail < 0 ? 0 : buf.f_bavail); pmix_output_verbose(10, 2, "pmix_path_df: stat(v)fs states " "path: %s has %" PRIu64 " B of free space.", path, *out_avail); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/util/pmix_printf.h0000664000175000017500000001232415203536752017753 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2007 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file * * Buffer safe printf functions for portability to archaic platforms. */ #ifndef PMIX_PRINTF_H #define PMIX_PRINTF_H #include "src/include/pmix_config.h" #include #include #include "pmix_common.h" BEGIN_C_DECLS /** * Writes to a string under the control of a format string * that specifies how subsequent arguments are converted for output. * * @param str Output string buffer * @param size Size of string buffer * @param fmt Output format * @return Length of output string * * At most size-1 characters are printed into the output string (the * size'th character then gets the terminating `\0'); if the return * value is greater than or equal to the size argument, the string was * too short and some of the printed characters were discarded. The * output is always null-terminated. * * Returns the number of characters that would have been printed if * the size were unlimited (again, not including the final `\0'). * * THIS IS A PORTABILITY FEATURE: USE snprintf() in CODE. */ PMIX_EXPORT int pmix_snprintf(char *str, size_t size, const char *fmt, ...) __pmix_attribute_format__(__printf__, 3, 4); /** * Writes to a string under the control of a format string that * specifies how arguments accessed via the variable-length argument * facilities of stdarg(3) are converted for output. * * @param str Output string buffer * @param size Size of string buffer * @param fmt Output format * @param ap Variable argument list pointer * @return Length of output string * * At most size-1 characters are printed into the output string (the * size'th character then gets the terminating `\0'); if the return * value is greater than or equal to the size argument, the string was * too short and some of the printed characters were discarded. The * output is always null-terminated. * * Returns the number of characters that would have been printed if * the size were unlimited (again, not including the final `\0'). * * THIS IS A PORTABILITY FEATURE: USE vsnprintf() in CODE. */ PMIX_EXPORT int pmix_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) __pmix_attribute_format__(__printf__, 3, 0); /** * Allocates and writes to a string under the control of a format * string that specifies how subsequent arguments are converted for * output. * * @param *ptr Pointer to output string buffer * @param fmt Output format * @return Length of output string * * Sets *ptr to be a pointer to a buffer sufficiently large to hold * the formatted string. This pointer should be passed to free(3) to * release the allocated storage when it is no longer needed. If * sufficient space cannot be allocated, asprintf() and vasprintf() * will return -1 and set ret to be a NULL pointer. * * Returns the number of characters printed. * * Unlike pmix_snprintf and pmix_vsnprintf, pmix_asprintf() is always * available and guarantees that *ptr is NULL when the underlying * asprintf fails. The standard does not require *ptr be set to NULL * on error and some implementations (modern Linux) do not guarantee * such behavior. * */ PMIX_EXPORT int pmix_asprintf(char **ptr, const char *fmt, ...) __pmix_attribute_format__(__printf__, 2, 3); /** * Allocates and writes to a string under the control of a format * string that specifies how arguments accessed via the * variable-length argument facilities of stdarg(3) are converted for * output. * * @param *ptr Pointer to output string buffer * @param fmt Output format * @param ap Variable argument list pointer * @return Length of output string * * Sets *ptr to be a pointer to a buffer sufficiently large to hold * the formatted string. This pointer should be passed to free(3) to * release the allocated storage when it is no longer needed. If * sufficient space cannot be allocated, asprintf() and vasprintf() * will return -1 and set ret to be a NULL pointer. * * Returns the number of characters printed. * * Unlike pmix_snprintf and pmix_vsnprintf, pmix_vasprintf() is always * available and guarantees that *ptr is NULL when the underlying * asprintf fails. The standard does not require *ptr be set to NULL * on error and some implementations (modern Linux) do not guarantee * such behavior. * */ PMIX_EXPORT int pmix_vasprintf(char **ptr, const char *fmt, va_list ap) __pmix_attribute_format__(__printf__, 2, 0); END_C_DECLS #endif /* PMIX_PRINTF_H */ pmix-6.1.1~rc2/src/util/pmix_os_path.h0000664000175000017500000000662615203536752020116 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * Creates an operating system-acceptable path name. * * The pmix_os_path() function takes a variable number of string arguments and * concatenates them into a path name using the path separator character appropriate * to the local operating system. NOTE: the string returned by this function has been * malloc'd - thus, the user is responsible for free'ing the memory used by * the string. * * CRITICAL NOTE: The input variable list MUST be terminated by a NULL value. Failure * to do this will cause the program to suffer a catastrophic failure - usually a * segmentation violation or bus error. * * The function calls orte_sys_info() to ensure that the path separator character * has been identified. If that value cannot be identified for some reason, * the function will return a NULL value. Likewise, specifying a path name that * exceeds the maximum allowable path name length on the local system will result * in the return of a NULL value. * * */ #ifndef PMIX_OS_PATH_H #define PMIX_OS_PATH_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include BEGIN_C_DECLS /** * @param relative A boolean that specifies if the path name is to be constructed * relative to the current directory or as an absolute path. If no path * elements are included in the function call, then the function returns * "." for a relative path name and "" - * the top of the directory tree - for an absolute path name. * @param elem1,elem2,... A variable number of (char *)path_elements * can be provided to the function, terminated by a NULL value. These * elements will be concatenated, each separated by the path separator * character, into a path name and returned. * @retval path_name A pointer to a fully qualified path name composed of the * provided path elements, separated by the path separator character * appropriate to the local operating system. The path_name string has been malloc'd * and therefore the user is responsible for free'ing the field. * * Note that the "relative" argument is int instead of bool, because * passing a parameter that undergoes default argument promotion to * va_start() has undefined behavior (according to clang warnings on * MacOS High Sierra). */ PMIX_EXPORT char *pmix_os_path(int relative, ...) __pmix_attribute_malloc__ __pmix_attribute_sentinel__ __pmix_attribute_warn_unused_result__; /** * Convert the path to be OS friendly. On UNIX this function will * be empty. */ #define pmix_make_filename_os_friendly(PATH) (PATH) END_C_DECLS #endif /* PMIX_OS_PATH_H */ pmix-6.1.1~rc2/src/util/pmix_parse_options.c0000664000175000017500000001045515203536752021334 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2008 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include "pmix.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_parse_options.h" void pmix_util_parse_range_options(char *inp, char ***output) { char **r1 = NULL, **r2 = NULL; int i, vint; int start, end, n; char nstr[32]; char *input, *bang; bool bang_option = false; /* protect against null input */ if (NULL == inp) { return; } /* protect the provided input */ input = strdup(inp); /* check for the special '!' operator */ if (NULL != (bang = strchr(input, '!'))) { bang_option = true; *bang = '\0'; } /* split on commas */ r1 = PMIx_Argv_split(input, ','); /* for each resulting element, check for range */ for (i = 0; i < PMIx_Argv_count(r1); i++) { r2 = PMIx_Argv_split(r1[i], '-'); if (1 < PMIx_Argv_count(r2)) { /* given range - get start and end */ start = strtol(r2[0], NULL, 10); end = strtol(r2[1], NULL, 10); } else { /* check for wildcard - have to do this here because * the -1 would have been caught in the split */ vint = strtol(r1[i], NULL, 10); if (-1 == vint) { PMIx_Argv_free(*output); *output = NULL; PMIx_Argv_append_nosize(output, "-1"); PMIx_Argv_free(r2); goto cleanup; } start = strtol(r2[0], NULL, 10); end = start; } for (n = start; n <= end; n++) { pmix_snprintf(nstr, 32, "%d", n); PMIx_Argv_append_nosize(output, nstr); } PMIx_Argv_free(r2); } cleanup: if (bang_option) { PMIx_Argv_append_nosize(output, "BANG"); } free(input); PMIx_Argv_free(r1); } void pmix_util_get_ranges(char *inp, char ***startpts, char ***endpts) { char **r1 = NULL, **r2 = NULL; int i; char *input; /* protect against null input */ if (NULL == inp) { return; } /* protect the provided input */ input = strdup(inp); /* split on commas */ r1 = PMIx_Argv_split(input, ','); /* for each resulting element, check for range */ for (i = 0; i < PMIx_Argv_count(r1); i++) { r2 = PMIx_Argv_split(r1[i], '-'); if (2 == PMIx_Argv_count(r2)) { /* given range - get start and end */ PMIx_Argv_append_nosize(startpts, r2[0]); PMIx_Argv_append_nosize(endpts, r2[1]); } else if (1 == PMIx_Argv_count(r2)) { /* only one value provided, so it is both the start * and the end */ PMIx_Argv_append_nosize(startpts, r2[0]); PMIx_Argv_append_nosize(endpts, r2[0]); } else { /* no idea how to parse this */ pmix_output(0, "Unknown parse error on string: %s(%s)", inp, r1[i]); } PMIx_Argv_free(r2); } free(input); PMIx_Argv_free(r1); } pmix-6.1.1~rc2/src/util/pmix_string_copy.h0000664000175000017500000000555715203536752021023 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_STRING_COPY_H #define PMIX_STRING_COPY_H #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_UNISTD_H # include #endif BEGIN_C_DECLS /** * Do a "safe" string copy (i.e., guarantee to \0-terminate the * destination string), and assert() fail if the copy length is too * large (because we assume it is a programmer error). * * @param dest Destination string buffer. * @param src Source string buffer. * @param dest_len Length of the destination string buffer. * * This function is similar to, but different than, strcpy() and * strncpy(). * * It is invalid to pass NULL for either dest or src. * * If dest_len is larger than * PMIX_MAX_SIZE_ALLOWED_BY_PMIX_STRING_COPY, we assume that this is * a programmer error (because PMIX does not generally need to do * large string copies), and will assert() fail / abort. * * There is no return value. * * This function will essentially do the same thing as strncpy(), * except that a) it will guarantee to to terminate the destination * string with a \0, and b) it will not \0-pad to the right. * Specifically: * * - If the length of the source string is less than (len), the entire * source string will be copied to the destination, including the * \0. * - If the length of the source string is greater than (len), then * (len-1) characters of the source string will be copied to the * destination, and dest[len-1] will be set to '\0'. */ PMIX_EXPORT void pmix_string_copy(char *dest, const char *src, size_t dest_len) __pmix_attribute_nonnull__(1) __pmix_attribute_nonnull__(2); /** * Max dest_size allowed by pmix_string_copy(). * * See the description of pmix_string_copy() for an explanation. */ #define PMIX_MAX_SIZE_ALLOWED_BY_PMIX_STRING_COPY (128 * 1024) PMIX_EXPORT char *pmix_getline(FILE *fp); END_C_DECLS #endif /* PMIX_STRING_COPY_H */ pmix-6.1.1~rc2/src/util/pmix_hash.h0000664000175000017500000001316615203536752017401 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_HASH_H #define PMIX_HASH_H #include "src/include/pmix_config.h" #include "src/class/pmix_hash_table.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/bfrops_types.h" BEGIN_C_DECLS /* store a value in the given hash table for the specified * rank index.*/ PMIX_EXPORT pmix_status_t pmix_hash_store(pmix_hash_table_t *table, pmix_rank_t rank, pmix_kval_t *kin, pmix_info_t *qualifiers, size_t nquals, pmix_keyindex_t *kidx); /* Fetch the value for a specified key and rank from within * the given hash_table */ PMIX_EXPORT pmix_status_t pmix_hash_fetch(pmix_hash_table_t *table, pmix_rank_t rank, const char *key, pmix_info_t *qualifiers, size_t nquals, pmix_list_t *kvals, pmix_keyindex_t *kidx); /* remove the specified key-value from the given hash_table. * A NULL key will result in removal of all data for the * given rank. A rank of PMIX_RANK_WILDCARD indicates that * the specified key is to be removed from the data for all * ranks in the table. Combining key=NULL with rank=PMIX_RANK_WILDCARD * will therefore result in removal of all data from the * table */ PMIX_EXPORT pmix_status_t pmix_hash_remove_data(pmix_hash_table_t *table, pmix_rank_t rank, const char *key, pmix_keyindex_t *kidx); PMIX_EXPORT void pmix_hash_register_key(uint32_t inid, pmix_regattr_input_t *ptr, pmix_keyindex_t *kidx); PMIX_EXPORT pmix_regattr_input_t* pmix_hash_lookup_key(uint32_t inid, const char *key, pmix_keyindex_t *kidx); #define PMIX_HASH_TRACE_KEY_ACTUAL(s, r, k, id, tbl, v) \ do { \ const char *_k; \ char *_v; \ pmix_regattr_input_t *_p; \ if (NULL == (k) && UINT32_MAX != id) { \ _p = pmix_hash_lookup_key((id), NULL, NULL); \ if (NULL == _p) { \ _k = "KEY NOT FOUND"; \ } else { \ _k = _p->string; \ } \ } else if (NULL != (k)) { \ _k = (k); \ } else { \ _k = NULL; \ } \ if (NULL != _k) { \ if (0 == strcmp((s), _k)) { \ if (NULL != (v)) { \ _v = PMIx_Value_string(v); \ } else { \ _v = strdup("\tValue is NULL"); \ } \ pmix_output(0, "[%s:%s:%d] %s: Rank %s Key %s\n%s\n\n", \ __FILE__, __func__, __LINE__, \ (tbl)->ht_label, PMIX_RANK_PRINT(r), \ PMIx_Get_attribute_name(_k), _v); \ free(_v); \ } \ } \ } while(0) #define PMIX_HASH_TRACE_KEY(c, r, s, k, id, v, tbl) \ do { \ if (0 == strcasecmp(c, "SERVER") && \ PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { \ PMIX_HASH_TRACE_KEY_ACTUAL(s, r, k, id, tbl, v); \ } else if (0 == strcasecmp(c, "CLIENT") && \ !PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { \ PMIX_HASH_TRACE_KEY_ACTUAL(s, r, k, id, tbl, v); \ } \ } while (0) END_C_DECLS #endif /* PMIX_HASH_H */ pmix-6.1.1~rc2/src/util/pmix_printf.c0000664000175000017500000002336115203536752017751 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2013 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2018 Amazon.com, Inc. or its affiliates. All Rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* * Buffer safe printf functions for portability to archaic platforms. */ #include "src/include/pmix_config.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include #include #include #include #ifndef HAVE_VASPRINTF /* * Make a good guess about how long a printf-style varargs formatted * string will be once all the % escapes are filled in. We don't * handle every % escape here, but we handle enough, and then add a * fudge factor in at the end. */ static int guess_strlen(const char *fmt, va_list ap) { #if HAVE_VSNPRINTF char dummy[1]; /* vsnprintf() returns the number of bytes that would have been copied if the provided buffer were infinite. */ return 1 + vsnprintf(dummy, sizeof(dummy), fmt, ap); #else char *sarg, carg; double darg; float farg; size_t i; int iarg; int len; long larg; /* Start off with a fudge factor of 128 to handle the % escapes that we aren't calculating here */ len = (int) strlen(fmt) + 128; for (i = 0; i < strlen(fmt); ++i) { if ('%' == fmt[i] && i + 1 < strlen(fmt) && '%' != fmt[i + 1]) { ++i; switch (fmt[i]) { case 'c': carg = va_arg(ap, int); len += 1; /* let's suppose it's a printable char */ (void) carg; /* prevent compiler from complaining about set but not used variables */ break; case 's': sarg = va_arg(ap, char *); /* If there's an arg, get the strlen, otherwise we'll * use (null) */ if (NULL != sarg) { len += (int) strlen(sarg); } else { #if PMIX_ENABLE_DEBUG pmix_output(0, "PMIX DEBUG WARNING: Got a NULL argument to pmix_vasprintf!\n"); #endif len += 5; } break; case 'd': case 'i': iarg = va_arg(ap, int); /* Alloc for minus sign */ if (iarg < 0) ++len; /* Now get the log10 */ do { ++len; iarg /= 10; } while (0 != iarg); break; case 'x': case 'X': iarg = va_arg(ap, int); /* Now get the log16 */ do { ++len; iarg /= 16; } while (0 != iarg); break; case 'f': farg = (float) va_arg(ap, int); /* Alloc for minus sign */ if (farg < 0) { ++len; farg = -farg; } /* Alloc for 3 decimal places + '.' */ len += 4; /* Now get the log10 */ do { ++len; farg /= 10.0; } while (0 != farg); break; case 'g': darg = va_arg(ap, int); /* Alloc for minus sign */ if (darg < 0) { ++len; darg = -darg; } /* Alloc for 3 decimal places + '.' */ len += 4; /* Now get the log10 */ do { ++len; darg /= 10.0; } while (0 != darg); break; case 'l': /* Get %ld %lx %lX %lf */ if (i + 1 < strlen(fmt)) { ++i; switch (fmt[i]) { case 'x': case 'X': larg = va_arg(ap, int); /* Now get the log16 */ do { ++len; larg /= 16; } while (0 != larg); break; case 'f': darg = va_arg(ap, int); /* Alloc for minus sign */ if (darg < 0) { ++len; darg = -darg; } /* Alloc for 3 decimal places + '.' */ len += 4; /* Now get the log10 */ do { ++len; darg /= 10.0; } while (0 != darg); break; case 'd': default: larg = va_arg(ap, int); /* Now get the log10 */ do { ++len; larg /= 10; } while (0 != larg); break; } } default: break; } } } return len; #endif } #endif /* #ifndef HAVE_VASPRINTF */ int pmix_asprintf(char **ptr, const char *fmt, ...) { int length; va_list ap; va_start(ap, fmt); /* pmix_vasprintf guarantees that *ptr is set to NULL on error */ length = pmix_vasprintf(ptr, fmt, ap); va_end(ap); return length; } int pmix_vasprintf(char **ptr, const char *fmt, va_list ap) { #ifdef HAVE_VASPRINTF int length; length = vasprintf(ptr, fmt, ap); if (length < 0) { *ptr = NULL; } return length; #else int length; va_list ap2; /* va_list might have pointer to internal state and using it twice is a bad idea. So make a copy for the second use. Copy order taken from Autoconf docs. */ #if PMIX_HAVE_VA_COPY va_copy(ap2, ap); #elif PMIX_HAVE_UNDERSCORE_VA_COPY __va_copy(ap2, ap); #else memcpy(&ap2, &ap, sizeof(va_list)); #endif /* guess the size */ length = guess_strlen(fmt, ap); /* allocate a buffer */ *ptr = (char *) calloc(((size_t) length + 1), sizeof(char)); if (NULL == *ptr) { errno = ENOMEM; va_end(ap2); return -1; } /* fill the buffer */ length = vsprintf(*ptr, fmt, ap2); #if PMIX_HAVE_VA_COPY || PMIX_HAVE_UNDERSCORE_VA_COPY va_end(ap2); #endif /* PMIX_HAVE_VA_COPY || PMIX_HAVE_UNDERSCORE_VA_COPY */ /* realloc */ *ptr = (char *) realloc(*ptr, (size_t) length + 1); if (NULL == *ptr) { errno = ENOMEM; return -1; } return length; #endif } int pmix_snprintf(char *str, size_t size, const char *fmt, ...) { int length; va_list ap; va_start(ap, fmt); length = pmix_vsnprintf(str, size, fmt, ap); va_end(ap); return length; } int pmix_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) { int length; char *buf; length = pmix_vasprintf(&buf, fmt, ap); if (length < 0) { return length; } /* return the length when given a null buffer (C99) */ if (str && size > 0) { if ((size_t) length < size) { strcpy(str, buf); } else { memcpy(str, buf, size - 1); str[size - 1] = '\0'; } } /* free allocated buffer */ free(buf); return length; } #ifdef TEST int main(int argc, char *argv[]) { char a[10]; char b[173]; char *s; int length; puts("test for NULL buffer in snprintf:"); length = pmix_snprintf(NULL, 0, "this is a string %d", 1004); printf("length = %d\n", length); puts("test of snprintf to an undersize buffer:"); length = pmix_snprintf(a, sizeof(a), "this is a string %d", 1004); printf("string = %s\n", a); printf("length = %d\n", length); printf("strlen = %d\n", (int) strlen(a)); puts("test of snprintf to an oversize buffer:"); length = pmix_snprintf(b, sizeof(b), "this is a string %d", 1004); printf("string = %s\n", b); printf("length = %d\n", length); printf("strlen = %d\n", (int) strlen(b)); puts("test of asprintf:"); length = pmix_asprintf(&s, "this is a string %d", 1004); printf("string = %s\n", s); printf("length = %d\n", length); printf("strlen = %d\n", (int) strlen(s)); free(s); return 0; } #endif pmix-6.1.1~rc2/src/util/pmix_parse_options.h0000664000175000017500000000233315203536752021335 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2016 Intel, Inc. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * */ #ifndef _PMIX_PARSE_OPTIONS_H_ #define _PMIX_PARSE_OPTIONS_H_ #include "src/include/pmix_config.h" BEGIN_C_DECLS PMIX_EXPORT void pmix_util_parse_range_options(char *input, char ***output); PMIX_EXPORT void pmix_util_get_ranges(char *inp, char ***startpts, char ***endpts); END_C_DECLS #endif pmix-6.1.1~rc2/src/util/pmix_tty.c0000664000175000017500000000757215203536752017275 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2018 Cisco Systems, Inc. All rights reserved * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_CDEFS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_TERMIOS_H # include #else # ifdef HAVE_TERMIO_H # include # endif #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_UTIL_H # include #endif #include #include #include #include "src/util/pmix_output.h" #include "src/util/pmix_tty.h" pmix_status_t pmix_gettermios(int fd, struct termios *terms) { int rc; rc = tcgetattr(fd, terms); if (0 == rc) { return PMIX_SUCCESS; } return PMIX_ERROR; } pmix_status_t pmix_getwinsz(int fd, struct winsize *ws) { int rc; rc = ioctl(fd, TIOCGWINSZ, (char*) ws); if (0 == rc) { return PMIX_SUCCESS; } return PMIX_ERROR; } pmix_status_t pmix_settermios(int fd, struct termios *terms) { struct termios old, check; int rc, err; rc = pmix_gettermios(fd, &old); if (0 != rc) { return PMIX_ERROR; } rc = tcsetattr(fd, TCSANOW, terms); if (0 != rc) { // attempt to reset it err = errno; // preserve original error tcsetattr(fd, TCSANOW, &old); errno = err; } else { /* check that it was fully successful - tcsetattr returns * success if ANY change succeeded */ rc = pmix_gettermios(fd, &check); if (0 != rc) { return PMIX_ERROR; } rc = memcmp(terms, &check, sizeof(struct termios)); if (0 != rc) { errno = EINVAL; return PMIX_ERROR; } } return PMIX_SUCCESS; } pmix_status_t pmix_setwinsz(int fd, struct winsize *ws) { int rc; rc = ioctl(fd, TIOCSWINSZ, (char*) ws); if (0 == rc) { return PMIX_SUCCESS; } return PMIX_ERROR; } pmix_status_t pmix_setraw(int fd, struct termios *prior) { struct termios terms; int rc; rc = pmix_gettermios(fd, &terms); if (0 != rc) { return PMIX_ERROR; } if (NULL != prior) { memcpy(prior, &terms, sizeof(struct termios)); } terms.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO); /* Noncanonical mode, disable signals, extended input processing, and echoing */ terms.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR | INPCK | ISTRIP | IXON | PARMRK); /* Disable special handling of CR, NL, and BREAK. No 8th-bit stripping or parity error handling. Disable START/STOP output flow control. */ terms.c_oflag &= ~OPOST; /* Disable all output processing */ terms.c_cc[VMIN] = 1; /* Character-at-a-time input */ terms.c_cc[VTIME] = 0; /* with blocking */ rc = pmix_settermios(fd, &terms); return rc; } pmix-6.1.1~rc2/src/util/pmix_error.c0000664000175000017500000000323715203536752017600 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2012 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_event_strings.h" #include "src/util/pmix_error.h" PMIX_EXPORT const char *PMIx_Error_string(pmix_status_t errnum) { size_t n; for (n=0; n < PMIX_EVENT_INDEX_BOUNDARY; n++) { if (errnum == pmix_event_strings[n].code) { return pmix_event_strings[n].name; } } return "ERROR STRING NOT FOUND"; } PMIX_EXPORT pmix_status_t PMIx_Error_code(const char *errname) { size_t n; for (n=0; n < PMIX_EVENT_INDEX_BOUNDARY; n++) { if (0 == strcasecmp(pmix_event_strings[n].name, errname)) { return pmix_event_strings[n].code; } } return INT32_MIN; } pmix-6.1.1~rc2/src/util/pmix_environ.c0000664000175000017500000002255115203536752020127 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2007-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2022 Amazon.com, Inc. or its affiliates. * All Rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include #include #include #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #define PMIX_DEFAULT_TMPDIR "/tmp" #define PMIX_MAX_ENVAR_LENGTH 100000 /* * Merge two environ-like char arrays, ensuring that there are no * duplicate entries */ char **pmix_environ_merge(char **minor, char **major) { int i; char **ret = NULL; char *name, *value; /* Check for bozo cases */ if (NULL == major) { if (NULL == minor) { return NULL; } else { return PMIx_Argv_copy(minor); } } /* First, copy major */ ret = PMIx_Argv_copy(major); /* Do we have something in minor? */ if (NULL == minor) { return ret; } /* Now go through minor and call PMIx_Setenv(), but with overwrite as false */ for (i = 0; NULL != minor[i]; ++i) { value = strchr(minor[i], '='); if (NULL == value) { PMIx_Setenv(minor[i], NULL, false, &ret); } else { /* strdup minor[i] in case it's a constant string */ name = strdup(minor[i]); value = name + (value - minor[i]); *value = '\0'; PMIx_Setenv(name, value + 1, false, &ret); free(name); } } /* All done */ return ret; } pmix_status_t pmix_environ_merge_inplace(char ***orig, char **adders) { pmix_status_t ret; assert(*orig != environ); for (size_t adders_idx = 0 ; adders[adders_idx] != NULL ; adders_idx++) { const char *adder_string = adders[adders_idx]; /* See if the addr is in the original, because we only add. * Don't use setenv, to avoid having to split the string, * which is kind of expensive as we can't modify the strings * in adders (and setenv is going to do this same search loop * anyway). */ if (NULL == pmix_getenv(adder_string, *orig)) { /* note that append_nosize strdup()s the added argument, so both orig and adders can later be freed */ ret = PMIx_Argv_append_nosize(orig, adder_string); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } char * pmix_getenv(const char *name, char **env) { /* bozo case */ if (NULL == env) { return NULL; } for (size_t env_idx = 0 ; env[env_idx] != NULL ; env_idx++) { size_t str_idx = 0; while (true) { if (name[str_idx] == '\0') { /* if name is a bare key, then finding an equals sign * in the env string at the same position as the * terminator is a match. */ if (env[env_idx][str_idx] == '=') { return &(env[env_idx][str_idx + 1]); } break; } if (env[env_idx][str_idx] == '\0') { break; } if (name[str_idx] != env[env_idx][str_idx]) { break; } if (name[str_idx] == '=') { /* we know that env[env_idx][str_idx] is also '=', * from the inequality check above, so this is a match */ return &(env[env_idx][str_idx + 1]); } str_idx++; } } return NULL; } /* * Portable version of unsetenv(), allowing editing of any * environ-like array */ pmix_status_t pmix_unsetenv(const char *name, char ***env) { int i; char *compare; size_t len; bool found; /* Check for bozo case */ if (NULL == *env) { return PMIX_SUCCESS; } /* Make something easy to compare to */ i = asprintf(&compare, "%s=", name); if (NULL == compare || 0 > i) { return PMIX_ERR_OUT_OF_RESOURCE; } len = strlen(compare); /* Look for a duplicate that's already set in the env. If we find it, free it, and then start shifting all elements down one in the array. */ found = false; for (i = 0; (*env)[i] != NULL; ++i) { if (0 != strncmp((*env)[i], compare, len)) continue; if (environ != *env) { free((*env)[i]); } for (; (*env)[i] != NULL; ++i) (*env)[i] = (*env)[i + 1]; found = true; break; } free(compare); /* All done */ return (found) ? PMIX_SUCCESS : PMIX_ERR_NOT_FOUND; } const char *pmix_tmp_directory(void) { const char *str; if (NULL == (str = getenv("TMPDIR"))) if (NULL == (str = getenv("TEMP"))) if (NULL == (str = getenv("TMP"))) str = PMIX_DEFAULT_TMPDIR; return str; } const char *pmix_home_directory(uid_t uid) { const char *home = NULL; if (UINT_MAX == uid || uid == geteuid()) { home = getenv("HOME"); } if (NULL == home) { struct passwd *pw = getpwuid(uid); home = pw->pw_dir; } return home; } pmix_status_t pmix_util_harvest_envars(char **incvars, char **excvars, pmix_list_t *ilist) { int i, j; size_t len; pmix_kval_t *kv, *next; char *cs_env, *string_key; bool duplicate; /* harvest envars to pass along */ for (j = 0; NULL != incvars[j]; j++) { len = strlen(incvars[j]); if ('*' == incvars[j][len - 1]) { --len; } for (i = 0; NULL != environ[i]; ++i) { if (0 == strncmp(environ[i], incvars[j], len)) { cs_env = strdup(environ[i]); string_key = strchr(cs_env, '='); if (NULL == string_key) { free(cs_env); return PMIX_ERR_BAD_PARAM; } *string_key = '\0'; ++string_key; /* see if we already have this envar on the list */ duplicate = false; PMIX_LIST_FOREACH (kv, ilist, pmix_kval_t) { if (PMIX_ENVAR != kv->value->type) { continue; } if (0 == strcmp(kv->value->data.envar.envar, cs_env)) { /* if the value is the same, then ignore it */ if (0 != strcmp(kv->value->data.envar.value, string_key)) { /* otherwise, overwrite the value */ free(kv->value->data.envar.value); kv->value->data.envar.value = strdup(string_key); } duplicate = true; break; } } if (duplicate) { free(cs_env); continue; } PMIX_KVAL_NEW(kv, PMIX_SET_ENVAR); if (NULL == kv) { free(cs_env); return PMIX_ERR_NOMEM; } if (NULL == kv->value) { PMIX_RELEASE(kv); free(cs_env); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_ENVAR; PMIX_ENVAR_LOAD(&kv->value->data.envar, cs_env, string_key, ':'); pmix_list_append(ilist, &kv->super); free(cs_env); } } } /* now check the exclusions and remove any that match */ if (NULL != excvars) { for (j = 0; NULL != excvars[j]; j++) { len = strlen(excvars[j]); if ('*' == excvars[j][len - 1]) { --len; } PMIX_LIST_FOREACH_SAFE (kv, next, ilist, pmix_kval_t) { if (0 == strncmp(kv->value->data.envar.envar, excvars[j], len)) { pmix_list_remove_item(ilist, &kv->super); PMIX_RELEASE(kv); } } } } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/util/pmix_alfg.c0000664000175000017500000000656115203536752017363 0ustar alastairalastair/* * Copyright (c) 2014 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include "pmix_alfg.h" /* Mask corresponding to the primitive polynomial *--------------------------------------------------- * * p(x) = 1 + x^25 + x^27 + x^29 + x^30 + x^31 + x^32 * *--------------------------------------------------- */ #define MASK 0x80000057U /* Additive lagged Fibonacci parameters: *--------------------------------------------------- * * x_n = (x_(n - TAP1) + x_(n - TAP2) ) mod M * *--------------------------------------------------- */ #define TAP1 127 #define TAP2 97 #define CBIT 21 /* Canonical bit */ /** * @brief Galois shift register: Used to seed the ALFG's * canonical rectangle * * @param[in] unsigned int *seed: used to seed the Galois register * @param[out] uint32_t lsb: least significant bit of the Galois * register after shift */ static uint32_t galois(unsigned int *seed) { uint32_t lsb; lsb = (*seed & 1) ? 1 : 0; *seed >>= 1; /* tap it with the mask */ *seed = *seed ^ (lsb * MASK); return lsb; } /* PMIX global rng buffer */ static pmix_rng_buff_t alfg_buffer; /** * @brief Routine to seed the ALFG register * * @param[in] uint32_t seed * @param[out] pmix_rng_buff_t *buff: handle to ALFG buffer state */ int pmix_srand(pmix_rng_buff_t *buff, uint32_t seed) { int i, j; uint32_t seed_cpy = seed; buff->tap1 = TAP1 - 1; buff->tap2 = TAP2 - 1; /* zero out the register */ for (i = 0; i < TAP1; i++) { buff->alfg[i] = 0; } /* set the canonical bit */ buff->alfg[CBIT] = 1; /* seed the ALFG register by blasting * the canonical rectangle with bits */ for (j = 1; j < TAP1; j++) { for (i = 1; i < 32; i++) { buff->alfg[j] = buff->alfg[j] ^ ((galois(&seed_cpy)) << i); } } /* copy the ALFG to the global buffer */ memcpy(&alfg_buffer, buff, sizeof(alfg_buffer)); return 1; } /** * @brief The additive lagged Fibonnaci PRNG * * @param[in] pmix_rng_buff_t *buff: handle to ALFG buffer state * @param[out] 32-bit unsigned random integer */ uint32_t pmix_rand(pmix_rng_buff_t *buff) { int *tap1 = &(buff->tap1); int *tap2 = &(buff->tap2); uint64_t overflow; uint32_t temp; /* prevent overflow */ overflow = (uint64_t) buff->alfg[*tap1] + (uint64_t) buff->alfg[*tap2]; /* circular buffer arithmetic */ temp = (*tap1 + 1) == TAP1 ? 0 : (*tap1 + 1); /* Division modulo 2^32 */ buff->alfg[temp] = (uint32_t)(overflow & ((1ULL << 32) - 1)); /* increment tap points */ *tap1 = (*tap1 + 1) % TAP1; *tap2 = (*tap2 + 1) % TAP1; return buff->alfg[temp]; } /** * @brief A wrapper for pmix_rand() with our global ALFG buffer; * * @param[in] none * @param[out] int, the same as normal rand(3) */ int pmix_random(void) { /* always return a positive int */ return (int) (pmix_rand(&alfg_buffer) & 0x7FFFFFFF); } pmix-6.1.1~rc2/src/util/pmix_tty.h0000664000175000017500000000303615203536752017271 0ustar alastairalastair/* * Copyright (c) 2004-2006 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_UTIL_TTY_H #define PMIX_UTIL_TTY_H #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_TERMIOS_H # include #else # ifdef HAVE_TERMIO_H # include # endif #endif #ifdef HAVE_SYS_IOCTL_H # include #endif BEGIN_C_DECLS PMIX_EXPORT pmix_status_t pmix_gettermios(int fd, struct termios *terms); PMIX_EXPORT pmix_status_t pmix_getwinsz(int fd, struct winsize *ws); PMIX_EXPORT pmix_status_t pmix_settermios(int fd, struct termios *terms); PMIX_EXPORT pmix_status_t pmix_setwinsz(int fd, struct winsize *ws); PMIX_EXPORT pmix_status_t pmix_setraw(int fd, struct termios *prior); END_C_DECLS #endif /* PMIX_UTIL_TTY_H */ pmix-6.1.1~rc2/src/util/Makefile.am0000664000175000017500000000720215203536752017276 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2007-2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2013 NVIDIA Corporation. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2016 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021-2026 Nanook Consulting All rights reserved. # Copyright (c) 2022 Triad National Security, LLC. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # Source code files AM_CPPFLAGS = \ $(LTDLINCL) include $(top_srcdir)/Makefile.openpmix-rules noinst_LTLIBRARIES = libpmix_util.la EXTRA_DIST = \ help-pmix-util.txt \ help-cli.txt \ convert-help.py headers = \ pmix_alfg.h \ pmix_argv.h \ pmix_cmd_line.h \ pmix_error.h \ pmix_printf.h \ pmix_output.h \ pmix_environ.h \ pmix_fd.h \ pmix_timings.h \ pmix_os_dirpath.h \ pmix_os_path.h \ pmix_basename.h \ pmix_keyval_parse.h \ pmix_show_help.h \ pmix_path.h \ pmix_getid.h \ pmix_strnlen.h \ pmix_shmem.h \ pmix_vmem.h \ pmix_hash.h \ pmix_name_fns.h \ pmix_net.h \ pmix_if.h \ pmix_parse_options.h \ pmix_context_fns.h \ pmix_pty.h \ pmix_few.h \ pmix_string_copy.h \ pmix_getcwd.h \ pmix_tty.h sources = \ pmix_alfg.c \ pmix_argv.c \ pmix_cmd_line.c \ pmix_error.c \ pmix_printf.c \ pmix_output.c \ pmix_environ.c \ pmix_fd.c \ pmix_timings.c \ pmix_os_dirpath.c \ pmix_os_path.c \ pmix_basename.c \ pmix_keyval_parse.c \ pmix_show_help.c \ pmix_show_help_content.c \ pmix_path.c \ pmix_getid.c \ pmix_shmem.c \ pmix_vmem.c \ pmix_hash.c \ pmix_name_fns.c \ pmix_net.c \ pmix_if.c \ pmix_parse_options.c \ pmix_context_fns.c \ pmix_pty.c \ pmix_few.c \ pmix_string_copy.c \ pmix_getcwd.c \ pmix_tty.c pmix_show_help_content.c: convert-help.py if PMIX_PICKY_COMPILERS $(PMIX_V_GEN) $(PYTHON) $(abs_srcdir)/convert-help.py \ --root $(abs_top_srcdir) \ --out pmix_show_help_content.c \ --purge --verbose else $(PMIX_V_GEN) $(PYTHON) $(abs_srcdir)/convert-help.py \ --root $(abs_top_srcdir) \ --out pmix_show_help_content.c endif libpmix_util_la_SOURCES = $(headers) $(sources) libpmix_util_la_LIBADD = \ keyval/libpmixutilkeyval.la libpmix_util_la_DEPENDENCIES = \ keyval/libpmixutilkeyval.la # Unconditionally install the header files pmixdir = $(pmixincludedir)/$(subdir) pmix_HEADERS = $(headers) clean-local: rm -f pmix_show_help_content.c pmix_show_help_content.lo MAINTAINERCLEANFILES = \ pmix_show_help_content.c distclean-local: rm -f pmix_show_help_content.c pmix-6.1.1~rc2/src/util/pmix_cmd_line.c0000664000175000017500000005351515203536752020225 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2013 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012-2017 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2012-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2015-2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2017 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" // Local functions static int endswith(const char *str, const char *suffix) { size_t lenstr, lensuffix; if (NULL == str || NULL == suffix) { return PMIX_ERR_BAD_PARAM; } lenstr = strlen(str); lensuffix = strlen(suffix); if (lensuffix > lenstr) { return PMIX_ERR_BAD_PARAM; } if (0 == strncmp(str + lenstr - lensuffix, suffix, lensuffix)) { return PMIX_SUCCESS; } return PMIX_ERR_BAD_PARAM; } static void check_store(const char *name, const char *option, pmix_cli_result_t *results) { pmix_cli_item_t *opt; PMIX_LIST_FOREACH(opt, &results->instances, pmix_cli_item_t) { if (0 == strcmp(opt->key, name)) { /* if the name is NULL, then this is just setting * a boolean value - the presence of the option in * the results is considered "true" */ if (NULL != option) { PMIx_Argv_append_nosize(&opt->values, option); } return; } } // get here if this is new option opt = PMIX_NEW(pmix_cli_item_t); opt->key = strdup(name); pmix_list_append(&results->instances, &opt->super); /* if the name is NULL, then this is just setting * a boolean value - the presence of the option in * the results is considered "true" */ if (NULL != option) { PMIx_Argv_append_nosize(&opt->values, option); } return; } int pmix_cmd_line_parse(char **pargv, char *shorts, struct option myoptions[], pmix_cmd_line_store_fn_t storefn, pmix_cli_result_t *results, char *helpfile) { int option_index = 0; /* getopt_long stores the option index here. */ int n, m, opt, argc, argind; bool found; char *ptr, *str, **argv; pmix_cmd_line_store_fn_t mystore; /* the getopt_long parser reorders the input argv array, so * we have to protect it here */ argv = PMIx_Argv_copy(pargv); argc = PMIx_Argv_count(argv); // assign a default store_fn if one isn't provided if (NULL == storefn) { mystore = check_store; } else { mystore = storefn; } /* reset the parser - must be done each time we use it * to avoid hysteresis */ optind = 0; opterr = 0; optopt = 0; optarg = NULL; if (1 == argc) { // nothing to parse goto done; } // run the parser while (1) { argind = optind; if (optind == argc || (optind > 0 && '-' != argv[optind][0])) { // This is the executable, or we are at the last argument. // Don't process any further. break; } opt = getopt_long(argc, argv, shorts, myoptions, &option_index); switch (opt) { case 0: /* if this is an MCA param of some type, store it */ if (0 == endswith(myoptions[option_index].name, "mca")) { /* format mca params as param:value - the optind value * will have been incremented since the MCA param options * require an argument */ if (NULL == argv[optind] || '-' == argv[optind][1]) { // missing the required second argument str = pmix_show_help_string("help-cli.txt", "not-enough-arguments", true, pmix_tool_basename, myoptions[option_index].name, argv[optind-1], (NULL == argv[optind]) ? "missing" : argv[optind], pmix_tool_basename, myoptions[option_index].name); if (NULL != str) { fprintf(stderr, "%s", str); fflush(stderr); free(str); } PMIx_Argv_free(argv); return PMIX_ERR_SILENT; } pmix_asprintf(&str, "%s=%s", argv[optind-1], argv[optind]); mystore(myoptions[option_index].name, str, results); free(str); ++optind; break; } // if this is a "-env" option, then there can be three entries // that describe what to do if (0 == strcmp(myoptions[option_index].name, PMIX_CLI_PREPEND_ENVAR) || 0 == strcmp(myoptions[option_index].name, PMIX_CLI_APPEND_ENVAR)) { mystore(myoptions[option_index].name, argv[optind-1], results); mystore(myoptions[option_index].name, argv[optind], results); ++optind; break; } if (0 == strcmp(myoptions[option_index].name, PMIX_CLI_UNSET_ENVAR)) { // unset-env option only takes one argument mystore(myoptions[option_index].name, optarg, results); break; } if (0 == strcmp(myoptions[option_index].name, PMIX_CLI_INFO_VERSION)) { if (NULL == argv[optind] || '-' == argv[optind][1]) { // --show-version option with no args mystore(myoptions[option_index].name, optarg, results); break; } else if (NULL != argv[optind]) { if (NULL == argv[optind+1]) { // one arg mystore(myoptions[option_index].name, argv[optind], results); } else { // two args mystore(myoptions[option_index].name, argv[optind], results); mystore(myoptions[option_index].name, argv[optind+1], results); ++optind; } } break; } /* otherwise, store actual option */ mystore(myoptions[option_index].name, optarg, results); break; case 'h': /* the "help" option can optionally take an argument. Since * the argument _is_ optional, getopt will _NOT_ increment * optind, so argv[optind] is the potential argument */ if (NULL == optarg && NULL != argv[optind]) { /* strip any leading dashes */ ptr = argv[optind]; while ('-' == *ptr) { ++ptr; } // check for standard options if (0 == strcmp(ptr, "version") || 0 == strcmp(ptr, "V")) { str = pmix_show_help_string("help-cli.txt", "version", false); if (NULL != str) { printf("%s\n", str); fflush(stdout); free(str); } PMIx_Argv_free(argv); return PMIX_OPERATION_SUCCEEDED; } if (0 == strcmp(ptr, "verbose") || 0 == strcmp(ptr, "v")) { str = pmix_show_help_string("help-cli.txt", "verbose", false); if (NULL != str) { printf("%s\n", str); fflush(stdout); free(str); } PMIx_Argv_free(argv); return PMIX_OPERATION_SUCCEEDED; } if (0 == strcmp(ptr, "help") || 0 == strcmp(ptr, "h")) { // they requested help on the "help" option itself str = pmix_show_help_string("help-cli.txt", "help", false, pmix_tool_basename, pmix_tool_basename, pmix_tool_basename, pmix_tool_basename, pmix_tool_basename, pmix_tool_basename, pmix_tool_basename, pmix_tool_basename); if (NULL != str) { printf("%s\n", str); fflush(stdout); free(str); } PMIx_Argv_free(argv); return PMIX_OPERATION_SUCCEEDED; } /* see if we have help on that subject */ str = pmix_show_help_string(helpfile, ptr, false); if (NULL == str) { // let the user know we don't recognize that topic str = pmix_show_help_string("help-cli.txt", "unknown-option", true, ptr, pmix_tool_basename); if (NULL != str) { fprintf(stderr, "%s", str); fflush(stderr); free(str); } } else { printf("%s\n", str); fflush(stdout); free(str); } PMIx_Argv_free(argv); return PMIX_OPERATION_SUCCEEDED; } else if (NULL == optarg) { // high-level help request str = pmix_show_help_string(helpfile, "usage", false, pmix_tool_basename, pmix_tool_org, pmix_tool_version, pmix_tool_basename, pmix_tool_msg); if (NULL != str) { printf("%s\n", str); fflush(stdout); free(str); } PMIx_Argv_free(argv); return PMIX_OPERATION_SUCCEEDED; } else { // unrecognized option str = pmix_show_help_string("help-cli.txt", "unrecognized-option", true, pmix_tool_basename, optarg); if (NULL != str) { fprintf(stderr, "%s", str); fflush(stderr); free(str); } } PMIx_Argv_free(argv); return PMIX_ERR_SILENT; case 'V': str = pmix_show_help_string(helpfile, "version", false, pmix_tool_basename, pmix_tool_org, pmix_tool_version, pmix_tool_msg); if (NULL != str) { printf("%s\n", str); fflush(stdout); free(str); } // if they ask for the version, that is all we do PMIx_Argv_free(argv); return PMIX_OPERATION_SUCCEEDED; case 'v': /* if the argv at this point is not pointing at a string * starting with "-v", then we just ignore it - the user * has passed a string with multiple 'v's in it and we * need to wait until the end */ if (0 != strncmp(argv[optind-1], "-v", 2)) { break; } /* we store the 'v' option with a value equal to the * number of 'v's the user provided */ n = strlen(&argv[optind-1][1]); pmix_asprintf(&str, "%d", n); mystore(myoptions[option_index].name, str, results); free(str); break; default: found = false; for (n=0; '\0' != shorts[n]; n++) { int ascii = shorts[n]; if (opt == ascii) { /* found it - now search for matching option. The * getopt fn will have already incremented optind * to point at the next argument. * If this short option required an argument, then * it will be indicated by a ':' in the next shorts * spot and the argument will be in optarg. * * If the short option takes an optional argument, then * it will be indicated by two ':' after the option - in * this case optarg will contain the argument if given. * Note that the proper form of the optional argument * option is "-zfoo", where 'z' is the option and "foo" * is the argument. Putting a space between the option * and the argument is forbidden and results in reporting * of 'z' without an argument - usually followed by * incorrectly marking "foo" as the beginning of the * command "tail" */ if (':' == shorts[n+1]) { // could be an optional arg if (':' == shorts[n+2]) { /* in this case, the argument (if given) must be immediately * attached to the option */ ptr = argv[optind-1]; ptr += 2; // step over the '-' and option } else { ptr = optarg; } } else { ptr = NULL; } for (m=0; NULL != myoptions[m].name; m++) { if (ascii == myoptions[m].val) { if (PMIX_ARG_NONE == myoptions[m].has_arg) { /* if ptr isn't NULL, then that means we were given * an argument to an option that doesn't take one. * Report the error */ if (NULL != ptr) { str = pmix_show_help_string("help-cli.txt", "short-arg-error", true, pmix_tool_basename, shorts[n], ptr); if (NULL != str) { fprintf(stderr, "%s", str); fflush(stderr); free(str); } PMIx_Argv_free(argv); return PMIX_ERR_SILENT; } ptr = NULL; } else if (0 == strcmp(myoptions[m].name, "np") && (NULL != optarg && 0 == strcmp(optarg, "p"))) { /* we special-case the very common "-np" option */ ptr = argv[optind]; ++optind; } mystore(myoptions[m].name, ptr, results); found = true; break; } } if (found) { break; } /* this could be one of the short options other than 'h' or 'V', so * we have to check */ if (0 != argind && '-' != argv[argind][0]) { // this was not an option goto done; } if (0 == strcmp(argv[optind-1], "--")) { // double-dash indicates separator between launcher // directives and the application results->tail = PMIx_Argv_copy(&argv[optind]); PMIx_Argv_free(argv); return PMIX_SUCCESS; } str = pmix_show_help_string("help-cli.txt", "short-no-long", true, pmix_tool_basename, shorts[n]); if (NULL != str) { fprintf(stderr, "%s", str); fflush(stderr); free(str); } PMIx_Argv_free(argv); return PMIX_ERR_SILENT; } } if (found) { break; } /* see if the option is in the list - if it is, then it is a * "recognized" option but may be missing an argument. The * getopt_long function declares these as "unrecognized", but * we would like to provide a more user-friendly error message */ for (n=0; NULL != myoptions[n].name; n++) { /* skip the "--" prefix */ if (0 == strcmp(&argv[optind-1][2], myoptions[n].name)) { /* the option is recognized - probably misssing * an argument */ str = pmix_show_help_string("help-cli.txt", "missing-argument", true, pmix_tool_basename, argv[optind-1], pmix_tool_basename, &argv[optind-1][2]); if (NULL != str) { fprintf(stderr, "%s", str); fflush(stderr); free(str); } PMIx_Argv_free(argv); return PMIX_ERR_SILENT; } } if (0 == strcmp(argv[optind-1], "--")) { // double-dash indicates separator between launcher // directives and the application goto done; } if (1 == optind) { // command without any options goto done; } str = pmix_show_help_string("help-cli.txt", "unregistered-option", true, pmix_tool_basename, argv[optind-1], pmix_tool_basename); if (NULL != str) { fprintf(stderr, "%s", str); fflush(stderr); free(str); } PMIx_Argv_free(argv); return PMIX_ERR_SILENT; } } done: if (optind < argc) { /* if this is an '&', it simply indicates that the executable * was being pushed into the background - ignore it */ if (0 != strcmp(argv[optind], "&")) { results->tail = PMIx_Argv_copy(&argv[optind]); } } PMIx_Argv_free(argv); return PMIX_SUCCESS; } static void icon(pmix_cli_item_t *p) { p->key = NULL; p->values = NULL; } static void ides(pmix_cli_item_t *p) { if (NULL != p->key) { free(p->key); } if (NULL != p->values) { PMIx_Argv_free(p->values); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_cli_item_t, pmix_list_item_t, icon, ides); static void ocon(pmix_cli_result_t *p) { PMIX_CONSTRUCT(&p->instances, pmix_list_t); p->tail = NULL; } static void odes(pmix_cli_result_t *p) { PMIX_LIST_DESTRUCT(&p->instances); if (NULL != p->tail) { PMIx_Argv_free(p->tail); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_cli_result_t, pmix_object_t, ocon, odes); pmix-6.1.1~rc2/src/util/pmix_pty.h0000664000175000017500000000407115203536752017265 0ustar alastairalastair/* * Copyright (c) 2004-2006 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_UTIL_PTY_H #define PMIX_UTIL_PTY_H #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_UTIL_H # include #endif #ifdef HAVE_LIBUTIL_H # include #endif #ifdef HAVE_TERMIOS_H # include #else # ifdef HAVE_TERMIO_H # include # endif #endif BEGIN_C_DECLS #if PMIX_ENABLE_PTY_SUPPORT PMIX_EXPORT int pmix_openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp); PMIX_EXPORT int pmix_ptymopen(char *pts_name, size_t maxlen); PMIX_EXPORT int pmix_ptysopen(int fdm, char *pts_name); PMIX_EXPORT pid_t pmix_forkpty(int *master, char *slave, const struct termios *sterm, const struct winsize *sws); #else PMIX_EXPORT int pmix_openpty(int *amaster, int *aslave, char *name, void *termp, void *winpp); PMIX_EXPORT int pmix_ptymopen(char *pts_name, size_t maxlen); PMIX_EXPORT int pmix_ptysopen(int fdm, char *pts_name); PMIX_EXPORT pid_t pmix_forkpty(int *master, char *slave, const void *sterm, const void *sws); #endif END_C_DECLS #endif /* PMIX_UTIL_PTY_H */ pmix-6.1.1~rc2/src/util/pmix_hash.c0000664000175000017500000007214615203536752017377 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2011-2014 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022-2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ // TODO(skg) Assert that the tma from the table and keyindex match in all // relevant places. #include "src/include/pmix_config.h" #include "src/include/pmix_hash_string.h" #include "src/include/pmix_stdint.h" #include #include "src/class/pmix_hash_table.h" #include "src/class/pmix_pointer_array.h" #include "src/include/pmix_dictionary.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_hash_string.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/bfrops/base/bfrop_base_tma.h" #include "src/mca/gds/base/base.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_hash.h" /** * Utility function that takes a pointer to a pmix_keyindex_t and returns the * global keyindex if NULL, returns the input otherwise. */ static inline pmix_keyindex_t *get_keyindex_ptr(pmix_keyindex_t *input) { return input ? input : &pmix_globals.keyindex; } /** * Data for a particular pmix process * The name association is maintained in the * proc_data hash table. */ typedef struct { pmix_object_t super; /** * Array of pmix_dstor_t structures containing all data received from this * process. Note that these are pointers because the shared-memory TMA * requires that these structures and their data reside on the heap. */ pmix_pointer_array_t *data; pmix_pointer_array_t *quals; } pmix_proc_data_t; static void pdcon(pmix_proc_data_t *p) { pmix_tma_t *const tma = pmix_obj_get_tma(&p->super); p->data = PMIX_NEW(pmix_pointer_array_t, tma); pmix_pointer_array_init(p->data, 128, INT_MAX, 128); p->quals = PMIX_NEW(pmix_pointer_array_t, tma); pmix_pointer_array_init(p->quals, 1, INT_MAX, 1); } static void pddes(pmix_proc_data_t *p) { int n; size_t nq; pmix_dstor_t *d; pmix_qual_t *q; pmix_data_array_t *darray; pmix_tma_t *const tma = pmix_obj_get_tma(&p->super); for (n=0; n < p->data->size; n++) { d = (pmix_dstor_t*)pmix_pointer_array_get_item(p->data, n); if (NULL != d) { pmix_dstor_release_tma(d, tma); pmix_pointer_array_set_item(p->data, n, NULL); } } PMIX_RELEASE(p->data); for (n=0; n < p->quals->size; n++) { darray = (pmix_data_array_t*)pmix_pointer_array_get_item(p->quals, n); if (NULL != darray) { q = (pmix_qual_t*)darray->array; for (nq=0; nq < darray->size; nq++) { if (NULL != q[nq].value) { pmix_bfrops_base_tma_value_release(&q[nq].value, tma); } } pmix_tma_free(tma, darray->array); pmix_tma_free(tma, darray); } pmix_pointer_array_set_item(p->quals, n, NULL); } PMIX_RELEASE(p->quals); } static PMIX_CLASS_INSTANCE(pmix_proc_data_t, pmix_object_t, pdcon, pddes); static pmix_dstor_t *lookup_keyval(pmix_proc_data_t *proc, uint32_t kid, pmix_info_t *qualifiers, size_t nquals, pmix_keyindex_t *kidx); static pmix_proc_data_t *lookup_proc(pmix_hash_table_t *jtable, uint32_t id, bool create); static void erase_qualifiers(pmix_proc_data_t *proc, uint32_t index); pmix_status_t pmix_hash_store(pmix_hash_table_t *table, pmix_rank_t rank, pmix_kval_t *kin, pmix_info_t *qualifiers, size_t nquals, pmix_keyindex_t *kidx) { pmix_proc_data_t *proc_data; uint32_t kid; pmix_dstor_t *hv; pmix_regattr_input_t *p; pmix_status_t rc; pmix_data_array_t *darray; pmix_qual_t *qarray; size_t n, m = 0; pmix_tma_t *const tma = pmix_obj_get_tma(&table->super); pmix_keyindex_t *const keyindex = get_keyindex_ptr(kidx); pmix_output_verbose(10, pmix_gds_base_framework.framework_output, "%s HASH:STORE:QUAL table %s rank %s key %s", PMIX_NAME_PRINT(&pmix_globals.myid), (NULL == table->ht_label) ? "UNKNOWN" : table->ht_label, PMIX_RANK_PRINT(rank), (NULL == kin) ? "NULL KVAL" : kin->key); if (PMIX_UNLIKELY(NULL == kin)) { return PMIX_ERR_BAD_PARAM; } /* lookup the key's corresponding index - this should be * moved to the periphery of the PMIx library so we can * refer to the key numerically throughout the internals */ p = pmix_hash_lookup_key(UINT32_MAX, kin->key, keyindex); if (PMIX_UNLIKELY(NULL == p)) { /* we don't know this key */ pmix_output_verbose(10, pmix_gds_base_framework.framework_output, "%s UNKNOWN KEY: %s", PMIX_NAME_PRINT(&pmix_globals.myid), kin->key); return PMIX_ERR_BAD_PARAM; } kid = p->index; /* lookup the proc data object for this proc - create * it if we don't already have it */ if (PMIX_UNLIKELY(NULL == (proc_data = lookup_proc(table, rank, true)))) { return PMIX_ERR_NOMEM; } /* see if we already have this key-value */ hv = lookup_keyval(proc_data, kid, qualifiers, nquals, keyindex); if (NULL != hv) { if (PMIX_UNLIKELY(9 < pmix_output_get_verbosity(pmix_gds_base_framework.framework_output))) { // Note that this doesn't have to use a TMA because it is just a // temporary value. char *tmp; tmp = PMIx_Value_string(hv->value); pmix_output(0, "%s PREEXISTING ENTRY FOR PROC %s KEY %s: %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_RANK_PRINT(rank), kin->key, tmp); free(tmp); } /* yes we do - so just replace the current value if it changed */ if (NULL != hv->value) { if (PMIX_EQUAL == PMIx_Value_compare(hv->value, kin->value)) { pmix_output_verbose(10, pmix_gds_base_framework.framework_output, "EQUAL VALUE - IGNORING"); return PMIX_SUCCESS; } if (PMIX_UNLIKELY(9 < pmix_output_get_verbosity(pmix_gds_base_framework.framework_output))) { // Note that this doesn't have to use a TMA because it is just a // temporary value. char *tmp; tmp = PMIx_Value_string(kin->value); pmix_output(0, "%s KEY %s VALUE UPDATING TO: %s", PMIX_NAME_PRINT(&pmix_globals.myid), kin->key, tmp); free(tmp); } pmix_bfrops_base_tma_value_release(&hv->value, tma); } /* TODO(skg) eventually, we want to eliminate this copy */ rc = pmix_bfrops_base_tma_copy_value(&hv->value, kin->value, PMIX_VALUE, tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } return PMIX_SUCCESS; } /* we don't already have it, so create it */ hv = pmix_dstor_new_tma(kid, tma); if (PMIX_UNLIKELY(NULL == hv)) { return PMIX_ERR_NOMEM; } if (NULL != qualifiers) { /* count the number of actual qualifiers */ for (n=0, m=0; n < nquals; n++) { if (PMIX_INFO_IS_QUALIFIER(&qualifiers[n])) { ++m; } } if (0 < m) { darray = (pmix_data_array_t*)pmix_tma_malloc(tma, sizeof(pmix_data_array_t)); darray->array = (pmix_qual_t*)pmix_tma_malloc(tma, m * sizeof(pmix_qual_t)); darray->size = m; hv->qualindex = pmix_pointer_array_add(proc_data->quals, darray); qarray = (pmix_qual_t*)darray->array; for (n=0, m=0; n < nquals; n++) { if (PMIX_INFO_IS_QUALIFIER(&qualifiers[n])) { p = pmix_hash_lookup_key(UINT32_MAX, qualifiers[n].key, keyindex); if (PMIX_UNLIKELY(NULL == p)) { /* we don't know this key */ pmix_output_verbose(10, pmix_gds_base_framework.framework_output, "%s UNKNOWN KEY: %s", PMIX_NAME_PRINT(&pmix_globals.myid), kin->key); erase_qualifiers(proc_data, hv->qualindex); pmix_dstor_release_tma(hv, tma); return PMIX_ERR_BAD_PARAM; } qarray[n].index = p->index; rc = pmix_bfrops_base_tma_copy_value(&qarray[m].value, &qualifiers[n].value, PMIX_VALUE, tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); erase_qualifiers(proc_data, hv->qualindex); pmix_dstor_release_tma(hv, tma); return rc; } ++m; } } } } /* TODO(skg) eventually, we want to eliminate this copy */ rc = pmix_bfrops_base_tma_copy_value(&hv->value, kin->value, PMIX_VALUE, tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); if (UINT32_MAX != hv->qualindex) { /* release the associated qualifiers */ erase_qualifiers(proc_data, hv->qualindex); } pmix_dstor_release_tma(hv, tma); return rc; } if (PMIX_UNLIKELY(9 < pmix_output_get_verbosity(pmix_gds_base_framework.framework_output))) { // Note that this doesn't have to use a TMA because it is just a // temporary value. char *v = PMIx_Value_string(kin->value); pmix_output(0, "%s ADDING KEY %s VALUE %s FOR RANK %s WITH %u QUALS TO TABLE %s", PMIX_NAME_PRINT(&pmix_globals.myid), kin->key, v, PMIX_RANK_PRINT(rank), (unsigned)m, (NULL == table->ht_label) ? "UNKNOWN" : table->ht_label); free(v); } pmix_pointer_array_add(proc_data->data, hv); return PMIX_SUCCESS; } static pmix_status_t make_copy(pmix_regattr_input_t *p, pmix_dstor_t *hv, pmix_list_t *kvals, pmix_proc_data_t *proc_data, pmix_keyindex_t *const keyindex) { pmix_kval_t *kv; pmix_data_array_t *darray; pmix_qual_t *quals; pmix_info_t *iptr; size_t nq, m; if (UINT32_MAX != hv->qualindex) { /* this is a qualified value - need to return it as such */ PMIX_KVAL_NEW(kv, PMIX_QUALIFIED_VALUE); darray = (pmix_data_array_t*)pmix_pointer_array_get_item(proc_data->quals, hv->qualindex); if (NULL == darray) { PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND); return PMIX_ERR_NOT_FOUND; } quals = (pmix_qual_t*)darray->array; nq = darray->size; PMIX_DATA_ARRAY_CREATE(darray, nq+1, PMIX_INFO); iptr = (pmix_info_t*)darray->array; /* the first location is the actual value */ PMIX_LOAD_KEY(iptr[0].key, p->string); PMIx_Value_xfer(&iptr[0].value, hv->value); /* now add the qualifiers */ for (m=0; m < nq; m++) { p = pmix_hash_lookup_key(quals[m].index, NULL, keyindex); if (NULL == p) { /* should never happen */ PMIX_RELEASE(kv); PMIX_DATA_ARRAY_FREE(darray); return PMIX_ERR_BAD_PARAM; } PMIX_LOAD_KEY(iptr[m+1].key, p->string); PMIx_Value_xfer(&iptr[m+1].value, quals[m].value); PMIX_INFO_SET_QUALIFIER(&iptr[m+1]); } kv->value->type = PMIX_DATA_ARRAY; kv->value->data.darray = darray; pmix_list_append(kvals, &kv->super); } else { PMIX_KVAL_NEW(kv, p->string); PMIx_Value_xfer(kv->value, hv->value); pmix_list_append(kvals, &kv->super); } return PMIX_SUCCESS; } // TODO(skg) We may have to provide a different fetch entry point with different // semantics for gds shmem to further reduce memory usage. For now this seems to // work for our current use case. pmix_status_t pmix_hash_fetch(pmix_hash_table_t *table, pmix_rank_t rank, const char *key, pmix_info_t *qualifiers, size_t nquals, pmix_list_t *kvals, pmix_keyindex_t *kidx) { pmix_status_t rc; pmix_proc_data_t *proc_data; pmix_dstor_t *hv; uint32_t id, kid=UINT32_MAX; char *node; pmix_regattr_input_t *p; int n; bool fullsearch = false; pmix_keyindex_t *const keyindex = get_keyindex_ptr(kidx); pmix_output_verbose(10, pmix_gds_base_framework.framework_output, "%s HASH:FETCH table %s id %s key %s", PMIX_NAME_PRINT(&pmix_globals.myid), (NULL == table->ht_label) ? "UNKNOWN" : table->ht_label, PMIX_RANK_PRINT(rank), (NULL == key) ? "NULL" : key); /* - PMIX_RANK_UNDEF should return following statuses * PMIX_ERR_NOT_FOUND | PMIX_SUCCESS * - specified rank can return following statuses * PMIX_ERR_NOT_FOUND | PMIX_ERR_NOT_FOUND | PMIX_SUCCESS * special logic is basing on these statuses on a client and a server */ if (PMIX_RANK_UNDEF == rank) { rc = pmix_hash_table_get_first_key_uint32(table, &id, (void **) &proc_data, (void **) &node); if (PMIX_SUCCESS != rc) { pmix_output_verbose(10, pmix_gds_base_framework.framework_output, "HASH:FETCH[%s:%d] proc data for rank %s not found", __func__, __LINE__, PMIX_RANK_PRINT(rank)); return PMIX_ERR_NOT_FOUND; } fullsearch = true; } else { id = rank; } if (NULL != key) { /* lookup the key's corresponding index - this should be * moved to the periphery of the PMIx library so we can * refer to the key numerically throughout the internals */ p = pmix_hash_lookup_key(UINT32_MAX, key, keyindex); if (NULL == p) { /* we don't know this key */ return PMIX_ERR_BAD_PARAM; } kid = p->index; } rc = PMIX_SUCCESS; while (PMIX_SUCCESS == rc) { proc_data = lookup_proc(table, id, false); if (NULL == proc_data) { pmix_output_verbose(10, pmix_gds_base_framework.framework_output, "HASH:FETCH[%s:%d] proc data for rank %s not found - key %s", __func__, __LINE__, PMIX_RANK_PRINT(rank), key); return PMIX_ERR_NOT_FOUND; } /* if the key is NULL, then the user wants -all- data * put by the specified rank */ if (NULL == key) { /* copy the data */ for (n=0; n < proc_data->data->size; n++) { hv = (pmix_dstor_t*)pmix_pointer_array_get_item(proc_data->data, n); if (NULL != hv) { p = pmix_hash_lookup_key(hv->index, NULL, keyindex); if (NULL == p) { return PMIX_ERR_NOT_FOUND; } pmix_output_verbose(10, pmix_gds_base_framework.framework_output, "%s FETCH NULL LOOKING AT %s", PMIX_NAME_PRINT(&pmix_globals.myid), p->name); /* if the rank is UNDEF, we ignore reserved keys */ if (PMIX_RANK_UNDEF == rank && PMIX_CHECK_RESERVED_KEY(p->string)) { continue; } if (9 < pmix_output_get_verbosity(pmix_gds_base_framework.framework_output)) { char *_tmp = PMIx_Value_string(hv->value); pmix_output(0, "%s INCLUDE %s VALUE %s FROM TABLE %s FOR RANK %s", PMIX_NAME_PRINT(&pmix_globals.myid), p->name, _tmp, (NULL == table->ht_label) ? "UNKNOWN" : table->ht_label, PMIX_RANK_PRINT(rank)); free(_tmp); } rc = make_copy(p, hv, kvals, proc_data, keyindex); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { return rc; } } } return PMIX_SUCCESS; } else { /* find the value from within this data object */ hv = lookup_keyval(proc_data, kid, qualifiers, nquals, keyindex); if (NULL != hv) { rc = make_copy(p, hv, kvals, proc_data, keyindex); break; } else if (!fullsearch) { pmix_output_verbose(10, pmix_gds_base_framework.framework_output, "HASH:FETCH data for key %s not found", key); return PMIX_ERR_NOT_FOUND; } } rc = pmix_hash_table_get_next_key_uint32(table, &id, (void **) &proc_data, node, (void **) &node); if (PMIX_SUCCESS != rc) { pmix_output_verbose(10, pmix_gds_base_framework.framework_output, "%s:%d HASH:FETCH data for key %s not found", __func__, __LINE__, key); return PMIX_ERR_NOT_FOUND; } } return rc; } pmix_status_t pmix_hash_remove_data(pmix_hash_table_t *table, pmix_rank_t rank, const char *key, pmix_keyindex_t *kidx) { pmix_status_t rc = PMIX_SUCCESS; pmix_proc_data_t *proc_data; pmix_dstor_t *d; uint32_t id, kid=UINT32_MAX; int n; char *node; pmix_regattr_input_t *p; pmix_tma_t *const tma = pmix_obj_get_tma(&table->super); pmix_keyindex_t *const keyindex = get_keyindex_ptr(kidx); if (NULL != key) { p = pmix_hash_lookup_key(UINT32_MAX, key, keyindex); if (PMIX_UNLIKELY(NULL == p)) { /* we don't know this key */ return PMIX_ERR_BAD_PARAM; } kid = p->index; } /* if the rank is wildcard, we want to apply this to * all rank entries */ if (PMIX_RANK_WILDCARD == rank) { rc = pmix_hash_table_get_first_key_uint32(table, &id, (void **) &proc_data, (void **) &node); while (PMIX_SUCCESS == rc) { if (NULL != proc_data) { if (NULL == key) { PMIX_RELEASE(proc_data); } else { for (n=0; n < proc_data->data->size; n++) { d = (pmix_dstor_t*)pmix_pointer_array_get_item(proc_data->data, n); if (NULL != d && kid == d->index) { if (NULL != d->value) { pmix_bfrops_base_tma_value_release(&d->value, tma); } if (UINT32_MAX != d->qualindex) { erase_qualifiers(proc_data, d->qualindex); } pmix_tma_free(tma, d); pmix_pointer_array_set_item(proc_data->data, n, NULL); break; } } } } rc = pmix_hash_table_get_next_key_uint32(table, &id, (void **) &proc_data, node, (void **) &node); } return PMIX_SUCCESS; } /* lookup the specified proc */ if (NULL == (proc_data = lookup_proc(table, rank, false))) { /* no data for this proc */ return PMIX_SUCCESS; } /* if key is NULL, remove all data for this proc */ if (NULL == key) { for (n=0; n < proc_data->data->size; n++) { d = (pmix_dstor_t*)pmix_pointer_array_get_item(proc_data->data, n); if (NULL != d) { if (NULL != d->value) { pmix_bfrops_base_tma_value_release(&d->value, tma); } if (UINT32_MAX != d->qualindex) { erase_qualifiers(proc_data, d->qualindex); } pmix_tma_free(tma, d); pmix_pointer_array_set_item(proc_data->data, n, NULL); } } /* remove the proc_data object itself from the jtable */ pmix_hash_table_remove_value_uint32(table, rank); /* cleanup */ PMIX_RELEASE(proc_data); return PMIX_SUCCESS; } /* remove this item */ for (n=0; n < proc_data->data->size; n++) { d = (pmix_dstor_t*)pmix_pointer_array_get_item(proc_data->data, n); if (NULL != d && kid == d->index) { if (NULL != d->value) { pmix_bfrops_base_tma_value_release(&d->value, tma); } if (UINT32_MAX != d->qualindex) { erase_qualifiers(proc_data, d->qualindex); } pmix_tma_free(tma, d); pmix_pointer_array_set_item(proc_data->data, n, NULL); break; } } return PMIX_SUCCESS; } /** * Find data for a given key in a given pmix_list_t. */ static pmix_dstor_t *lookup_keyval(pmix_proc_data_t *proc_data, uint32_t kid, pmix_info_t *qualifiers, size_t nquals, pmix_keyindex_t *kidx) { pmix_dstor_t *d; pmix_data_array_t *darray; pmix_qual_t *qarray; pmix_regattr_input_t *p; size_t m, numquals = 0, nq, nfound; int n; pmix_keyindex_t *const keyindex = get_keyindex_ptr(kidx); p = pmix_hash_lookup_key(kid, NULL, keyindex); if (NULL != qualifiers) { /* count the qualifiers */ for (m=0; m < nquals; m++) { /* if this isn't marked as a qualifier, skip it */ if (PMIX_INFO_IS_QUALIFIER(&qualifiers[m])) { ++numquals; } } } for (n=0; n < proc_data->data->size; n++) { d = (pmix_dstor_t*)pmix_pointer_array_get_item(proc_data->data, n); if (NULL == d) { continue; } if (kid == d->index) { if (0 < numquals) { if (UINT32_MAX == d->qualindex) { continue; } darray = (pmix_data_array_t*)pmix_pointer_array_get_item(proc_data->quals, d->qualindex); if (NULL == darray) { continue; } qarray = (pmix_qual_t*)darray->array; nfound = 0; /* check the qualifiers */ for (m=0; m < nquals; m++) { /* if this isn't marked as a qualifier, skip it */ if (!PMIX_INFO_IS_QUALIFIER(&qualifiers[m])) { continue; } p = pmix_hash_lookup_key(UINT32_MAX, qualifiers[m].key, keyindex); if (NULL == p) { /* we don't know this key */ return NULL; } for (nq=0; nq < darray->size; nq++) { /* see if the keys match */ if (qarray[nq].index == p->index) { /* if the values don't match, then we reject * this entry */ if (PMIX_EQUAL == PMIx_Value_compare(&qualifiers[m].value, qarray[nq].value)) { /* match! */ ++nfound; break; } } } } /* did we get a complete match? */ if (nfound == numquals) { return d; } } else { /* if the stored key is also "unqualified", * then return it */ if (UINT32_MAX == d->qualindex) { return d; } } } } return NULL; } /** * Find proc_data_t container associated with given * pmix_identifier_t. */ static pmix_proc_data_t *lookup_proc(pmix_hash_table_t *jtable, uint32_t id, bool create) { pmix_proc_data_t *proc_data = NULL; pmix_tma_t *const tma = pmix_obj_get_tma(&jtable->super); pmix_hash_table_get_value_uint32(jtable, id, (void **) &proc_data); if (NULL == proc_data && create) { /* The proc clearly exists, so create a data structure for it */ proc_data = PMIX_NEW(pmix_proc_data_t, tma); if (PMIX_UNLIKELY(NULL == proc_data)) { return NULL; } pmix_hash_table_set_value_uint32(jtable, id, proc_data); } return proc_data; } void pmix_hash_register_key(uint32_t inid, pmix_regattr_input_t *ptr, pmix_keyindex_t *kidx) { pmix_regattr_input_t *p = NULL; pmix_keyindex_t *const keyindex = get_keyindex_ptr(kidx); if (UINT32_MAX == inid) { /* store the pointer in the array */ pmix_pointer_array_set_item(keyindex->table, (int)keyindex->next_id, ptr); ptr->index = keyindex->next_id; keyindex->next_id += 1; return; } /* check to see if this key was already registered */ p = pmix_pointer_array_get_item(keyindex->table, inid); if (NULL != p) { /* already have this one */ return; } /* store the pointer in the table */ pmix_pointer_array_set_item(keyindex->table, inid, ptr); } // skg: Note that one may have to add a TMA wrapper for this call if changes are // made to how pmix_hash operates. Something for developers to keep in mind. pmix_regattr_input_t* pmix_hash_lookup_key(uint32_t inid, const char *key, pmix_keyindex_t *kidx) { int id; pmix_regattr_input_t *ptr = NULL; pmix_keyindex_t *const keyindex = get_keyindex_ptr(kidx); if (UINT32_MAX == inid) { if (NULL == key) { /* they have to give us something! */ return NULL; } for (id = 0; id < keyindex->table->size; id++) { ptr = pmix_pointer_array_get_item(keyindex->table, id); if (NULL != ptr) { if (0 == strcmp(key, ptr->string)) { return ptr; } } } /* we didn't find it - register it */ ptr = (pmix_regattr_input_t*)pmix_malloc(sizeof(pmix_regattr_input_t)); ptr->name = strdup(key); ptr->string = strdup(key); ptr->type = PMIX_UNDEF; // we don't know what type the user will set ptr->description = (char**)pmix_malloc(2 * sizeof(char*)); ptr->description[0] = strdup("USER DEFINED"); ptr->description[1] = NULL; pmix_hash_register_key(UINT32_MAX, ptr, keyindex); return ptr; } /* get the pointer from the table - if it is a reserved key, then * it had to be registered at the beginning of time. If it is a * non-reserved key, then it had to be registered or else the caller * would not have an index to pass us. Thus, the pointer is either * found or not - we don't register it if not found. */ ptr = pmix_pointer_array_get_item(keyindex->table, inid); return ptr; } static void erase_qualifiers(pmix_proc_data_t *proc, uint32_t index) { pmix_data_array_t *darray; pmix_qual_t *qarray; size_t n; pmix_tma_t *const tma = pmix_obj_get_tma(&proc->super); darray = (pmix_data_array_t*)pmix_pointer_array_get_item(proc->quals, index); if (NULL == darray || NULL == darray->array) { return; } qarray = (pmix_qual_t*)darray->array; for (n=0; n < darray->size; n++) { if (NULL != qarray[n].value) { pmix_bfrops_base_tma_value_release(&qarray[n].value, tma); } } pmix_tma_free(tma, qarray); pmix_tma_free(tma, darray); pmix_pointer_array_set_item(proc->quals, index, NULL); } pmix-6.1.1~rc2/src/util/pmix_fd.h0000664000175000017500000000606315203536752017045 0ustar alastairalastair/* * Copyright (c) 2008-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2009 Sandia National Laboratories. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* @file */ #ifndef PMIX_UTIL_FD_H_ #define PMIX_UTIL_FD_H_ #include "src/include/pmix_config.h" #include "pmix_common.h" BEGIN_C_DECLS /** * Read a complete buffer from a file descriptor. * * @param fd File descriptor * @param len Number of bytes to read * @param buffer Pre-allocated buffer (large enough to hold len bytes) * * @returns PMIX_SUCCESS upon success. * @returns PMIX_ERR_TIMEOUT if the fd closes before reading the full amount. * @returns PMIX_ERR_IN_ERRNO otherwise. * * Loop over reading from the fd until len bytes are read or an error * occurs. EAGAIN and EINTR are transparently handled. */ PMIX_EXPORT pmix_status_t pmix_fd_read(int fd, int len, void *buffer); /** * Write a complete buffer to a file descriptor. * * @param fd File descriptor * @param len Number of bytes to write * @param buffer Buffer to write from * * @returns PMIX_SUCCESS upon success. * @returns PMIX_ERR_IN_ERRNO otherwise. * * Loop over writing to the fd until len bytes are written or an error * occurs. EAGAIN and EINTR are transparently handled. */ PMIX_EXPORT pmix_status_t pmix_fd_write(int fd, int len, const void *buffer); /** * Convenience function to set a file descriptor to be close-on-exec. * * @param fd File descriptor * * @returns PMIX_SUCCESS upon success (or if the system does not * support close-on-exec behavior). * @returns PMIX_ERR_IN_ERRNO otherwise. * * This is simply a convenience function because there's a few steps * to setting a file descriptor to be close-on-exec. */ PMIX_EXPORT pmix_status_t pmix_fd_set_cloexec(int fd); /** * Convenience function to check if fd point to an accessible regular file. * * @param fd File descriptor * * @returns true if "fd" points to a regular file. * @returns false otherwise. */ PMIX_EXPORT bool pmix_fd_is_regular(int fd); /** * Convenience function to check if fd point to an accessible character device. * * @param fd File descriptor * * @returns true if "fd" points to a regular file. * @returns false otherwise. */ PMIX_EXPORT bool pmix_fd_is_chardev(int fd); /** * Convenience function to check if fd point to an accessible block device. * * @param fd File descriptor * * @returns true if "fd" points to a regular file. * @returns false otherwise. */ PMIX_EXPORT bool pmix_fd_is_blkdev(int fd); /** * Close all open sockets other than stdin/out/err prior to * exec'ing a new binary */ PMIX_EXPORT void pmix_close_open_file_descriptors(int protected_fd); PMIX_EXPORT const char *pmix_fd_get_peer_name(int fd); PMIX_EXPORT int pmix_fd_dup2(int src, int target); END_C_DECLS #endif pmix-6.1.1~rc2/src/util/pmix_name_fns.h0000664000175000017500000000425115203536752020237 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014-2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef _PMIX_NAME_FNS_H_ #define _PMIX_NAME_FNS_H_ #include "src/include/pmix_config.h" #ifdef HAVE_STDINT_h # include #endif #include "pmix_common.h" BEGIN_C_DECLS /* define an internal-only process name that has * a dynamically-sized nspace field to save memory */ typedef struct { char *nspace; pmix_rank_t rank; } pmix_name_t; #define PMIX_CHECK_NAMES(a, b) \ (PMIX_CHECK_NSPACE((a)->nspace, (b)->nspace) && ((a)->rank == (b)->rank || (PMIX_RANK_WILDCARD == (a)->rank || PMIX_RANK_WILDCARD == (b)->rank))) /* useful define to print name args in output messages */ PMIX_EXPORT char *pmix_util_print_name_args(const pmix_proc_t *name); #define PMIX_NAME_PRINT(n) pmix_util_print_name_args(n) PMIX_EXPORT char *pmix_util_print_pname_args(const pmix_name_t *name); #define PMIX_PNAME_PRINT(n) pmix_util_print_pname_args(n) PMIX_EXPORT char *pmix_util_print_rank(const pmix_rank_t vpid); #define PMIX_RANK_PRINT(n) pmix_util_print_rank(n) #define PMIX_PEER_PRINT(p) pmix_util_print_pname_args(&(p)->info->pname) PMIX_EXPORT int pmix_util_compare_proc(const void *a, const void *b); END_C_DECLS #endif pmix-6.1.1~rc2/src/util/pmix_shmem.c0000664000175000017500000001526215203536752017561 0ustar alastairalastair/* * Copyright (c) 2021-2023 Triad National Security, LLC. All rights reserved. * Copyright (c) 2022-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/util/pmix_shmem.h" #include "pmix_common.h" #include "pmix_output.h" #include "src/include/pmix_globals.h" #include "src/mca/gds/base/base.h" #include "src/util/pmix_error.h" #include "src/util/pmix_show_help.h" #include "src/util/pmix_string_copy.h" #ifdef HAVE_FCNTL_H #include #endif #include typedef struct pmix_shmem_header_t { /** Reference count. */ pmix_atomic_int32_t ref_count; } pmix_shmem_header_t; static void * data_addr_from_base( void *base_addr ) { const size_t header_offset = pmix_shmem_utils_pad_to_page( sizeof(pmix_shmem_header_t) ); return (void *)((uintptr_t)base_addr + header_offset); } static inline void inc_ref_count( pmix_shmem_header_t *header ) { (void)pmix_atomic_fetch_add_32(&header->ref_count, 1); } static inline bool dec_ref_count( pmix_shmem_header_t *header ) { return pmix_atomic_sub_fetch_32(&header->ref_count, 1) == 0; } static pmix_status_t segment_attach( pmix_shmem_t *shmem, uintptr_t desired_base_address, pmix_shmem_flags_t flags ) { pmix_status_t rc = PMIX_SUCCESS; void *mmap_addr = MAP_FAILED; const int fd = open(shmem->backing_path, O_RDWR); if (fd == -1) { rc = PMIX_ERR_FILE_OPEN_FAILURE; if (0 < pmix_output_get_verbosity(pmix_gds_base_framework.framework_output)) { pmix_show_help("help-pmix-util.txt", "failed-file-open", true, shmem->backing_path, strerror(errno)); } goto out; } mmap_addr = mmap( (void *)desired_base_address, shmem->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 ); if (MAP_FAILED == mmap_addr) { rc = PMIX_ERR_NOMEM; goto out; } // Check flags. // The caller wants memory mapped at their requested address. if ((flags & PMIX_SHMEM_MUST_MAP_AT_RADDR) && desired_base_address != (uintptr_t)NULL) { if (desired_base_address != (uintptr_t)mmap_addr) { rc = PMIX_ERR_NOT_AVAILABLE; goto out; } } out: if (-1 != fd) { (void)close(fd); } if (PMIX_SUCCESS != rc) { (void)pmix_shmem_segment_detach(shmem); } else { shmem->attached = true; } // Always set base addresses. On error it is useful for reporting. shmem->hdr_address = mmap_addr; shmem->data_address = data_addr_from_base(mmap_addr); return rc; } static pmix_status_t add_internal_segment_header( pmix_shmem_t *shmem ) { int rc = PMIX_SUCCESS; // The base address here is inconsequential because this is a temporary, // internal attachment site that should not be exposed to the caller. rc = segment_attach(shmem, (uintptr_t)NULL, 0); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } // Add the header. pmix_shmem_header_t shmem_header = { .ref_count = 0 }; memmove(shmem->hdr_address, &shmem_header, sizeof(shmem_header)); // Done with internal mapping, so detach. return pmix_shmem_segment_detach(shmem); } // TODO(skg) Add network FS warning? pmix_status_t pmix_shmem_segment_create( pmix_shmem_t *shmem, size_t size, const char *backing_path ) { int rc = PMIX_SUCCESS; // Real size of the segment: add header plus extra to pad to page boundary. const size_t real_size = pmix_shmem_utils_pad_to_page( size + sizeof(pmix_shmem_header_t) ); const int fd = open(backing_path, O_CREAT | O_RDWR, 0600); if (fd == -1) { rc = PMIX_ERR_FILE_OPEN_FAILURE; goto out; } // Size backing file. if (0 != ftruncate(fd, real_size)) { rc = PMIX_ERROR; goto out; } // Update segment properties. shmem->size = real_size; pmix_string_copy(shmem->backing_path, backing_path, PMIX_PATH_MAX); // Add internal segment header. rc = add_internal_segment_header(shmem); out: if (-1 != fd) { (void)close(fd); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } return rc; } pmix_status_t pmix_shmem_segment_attach( pmix_shmem_t *shmem, uintptr_t desired_base_address, pmix_shmem_flags_t flags ) { const pmix_status_t rc = segment_attach( shmem, desired_base_address, flags ); if (PMIX_SUCCESS == rc) { inc_ref_count(shmem->hdr_address); } return rc; } pmix_status_t pmix_shmem_segment_detach( pmix_shmem_t *shmem ) { int rc = 0; if (shmem && shmem->attached) { rc = munmap(shmem->hdr_address, shmem->size); shmem->attached = false; shmem->hdr_address = NULL; shmem->data_address = NULL; } return (0 == rc) ? PMIX_SUCCESS : PMIX_ERROR; } pmix_status_t pmix_shmem_segment_chown( pmix_shmem_t *shmem, uid_t owner, gid_t group ) { pmix_status_t rc = PMIX_SUCCESS; if (lchown(shmem->backing_path, owner, group) != 0) { // DO NOT FOLLOW LINKS rc = PMIX_ERROR; PMIX_ERROR_LOG(rc); } return rc; } pmix_status_t pmix_shmem_segment_chmod( pmix_shmem_t *shmem, mode_t mode ) { pmix_status_t rc = PMIX_SUCCESS; if (chmod(shmem->backing_path, mode) != 0) { rc = PMIX_ERROR; PMIX_ERROR_LOG(rc); } return rc; } pmix_status_t pmix_shmem_segment_unlink( pmix_shmem_t *shmem ) { const int rc = unlink(shmem->backing_path); memset(shmem->backing_path, 0, PMIX_PATH_MAX); return (0 == rc) ? PMIX_SUCCESS : PMIX_ERROR; } /** * Returns page size. */ static size_t get_page_size(void) { const long i = sysconf(_SC_PAGE_SIZE); if (0 > i) { PMIX_ERROR_LOG(PMIX_ERROR); return 0; } return i; } size_t pmix_shmem_utils_pad_to_page( size_t size ) { const size_t page_size = get_page_size(); const size_t pad = ((~size) + page_size + 1) & (page_size - 1); return size + pad; } static void shmem_construct( pmix_shmem_t *s ) { s->attached = false; s->size = 0; s->hdr_address = NULL; s->data_address = NULL; memset(s->backing_path, 0, PMIX_PATH_MAX); } static void shmem_destruct( pmix_shmem_t *s ) { // We don't have access to a reference count, so bail. if (!s->attached) { return; } // If our reference count has reached zero, then unlink the backing file. if (dec_ref_count(s->hdr_address)) { (void)pmix_shmem_segment_unlink(s); } (void)pmix_shmem_segment_detach(s); } PMIX_EXPORT PMIX_CLASS_INSTANCE( pmix_shmem_t, pmix_object_t, shmem_construct, shmem_destruct ); pmix-6.1.1~rc2/src/util/pmix_name_fns.c0000664000175000017500000001343615203536752020237 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014-2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/threads/pmix_tsd.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_printf.h" #define PMIX_PRINT_NAME_ARGS_MAX_SIZE 300 #define PMIX_PRINT_NAME_ARG_NUM_BUFS 16 #define PMIX_SCHEMA_DELIMITER_CHAR '.' #define PMIX_SCHEMA_WILDCARD_CHAR '*' #define PMIX_SCHEMA_WILDCARD_STRING "*" #define PMIX_SCHEMA_INVALID_CHAR '$' #define PMIX_SCHEMA_INVALID_STRING "$" static bool fns_init = false; static pmix_tsd_key_t print_args_tsd_key; char *pmix_print_args_null = "NULL"; typedef struct { char *buffers[PMIX_PRINT_NAME_ARG_NUM_BUFS]; int cntr; } pmix_print_args_buffers_t; static void buffer_cleanup(void *value) { int i; pmix_print_args_buffers_t *ptr; if (NULL != value) { ptr = (pmix_print_args_buffers_t *) value; for (i = 0; i < PMIX_PRINT_NAME_ARG_NUM_BUFS; i++) { free(ptr->buffers[i]); } free(ptr); } } static pmix_print_args_buffers_t *get_print_name_buffer(void) { pmix_print_args_buffers_t *ptr; int ret, i; if (!fns_init) { /* setup the print_args function */ if (PMIX_SUCCESS != (ret = pmix_tsd_key_create(&print_args_tsd_key, buffer_cleanup))) { PMIX_ERROR_LOG(ret); return NULL; } fns_init = true; } ret = pmix_tsd_getspecific(print_args_tsd_key, (void **) &ptr); if (PMIX_SUCCESS != ret) return NULL; if (NULL == ptr) { ptr = (pmix_print_args_buffers_t *) malloc(sizeof(pmix_print_args_buffers_t)); for (i = 0; i < PMIX_PRINT_NAME_ARG_NUM_BUFS; i++) { ptr->buffers[i] = (char *) calloc((PMIX_PRINT_NAME_ARGS_MAX_SIZE + 1), sizeof(char)); } ptr->cntr = 0; ret = pmix_tsd_setspecific(print_args_tsd_key, (void *) ptr); } return (pmix_print_args_buffers_t *) ptr; } static char *print_args(char *ns, pmix_rank_t rnk) { pmix_print_args_buffers_t *ptr; char *rank; int index; /* get the next buffer */ ptr = get_print_name_buffer(); if (NULL == ptr) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return pmix_print_args_null; } /* protect against NULL nspace */ if (NULL == ns) { index = ptr->cntr; pmix_snprintf(ptr->buffers[index], PMIX_PRINT_NAME_ARGS_MAX_SIZE, "[NO-NAME]"); ptr->cntr++; if (PMIX_PRINT_NAME_ARG_NUM_BUFS == ptr->cntr) { ptr->cntr = 0; } return ptr->buffers[index]; } rank = pmix_util_print_rank(rnk); index = ptr->cntr; pmix_snprintf(ptr->buffers[index], PMIX_PRINT_NAME_ARGS_MAX_SIZE, "[%s,%s]", ns, rank); ptr->cntr++; if (PMIX_PRINT_NAME_ARG_NUM_BUFS == ptr->cntr) { ptr->cntr = 0; } return ptr->buffers[index]; } char *pmix_util_print_name_args(const pmix_proc_t *name) { if (NULL == name) { return print_args(NULL, PMIX_RANK_UNDEF); } return print_args((char *) name->nspace, name->rank); } char *pmix_util_print_pname_args(const pmix_name_t *name) { if (NULL == name) { return print_args(NULL, PMIX_RANK_UNDEF); } return print_args((char *) name->nspace, name->rank); } char *pmix_util_print_rank(const pmix_rank_t vpid) { pmix_print_args_buffers_t *ptr; int index; ptr = get_print_name_buffer(); if (NULL == ptr) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return pmix_print_args_null; } index = ptr->cntr; if (PMIX_RANK_UNDEF == vpid) { pmix_snprintf(ptr->buffers[index], PMIX_PRINT_NAME_ARGS_MAX_SIZE, "UNDEF"); } else if (PMIX_RANK_WILDCARD == vpid) { pmix_snprintf(ptr->buffers[index], PMIX_PRINT_NAME_ARGS_MAX_SIZE, "WILDCARD"); } else if (PMIX_RANK_LOCAL_NODE == vpid) { pmix_snprintf(ptr->buffers[index], PMIX_PRINT_NAME_ARGS_MAX_SIZE, "LOCAL_NODE"); } else if (PMIX_RANK_LOCAL_PEERS == vpid) { pmix_snprintf(ptr->buffers[index], PMIX_PRINT_NAME_ARGS_MAX_SIZE, "LOCAL_PEERS"); } else if (PMIX_RANK_INVALID == vpid) { pmix_snprintf(ptr->buffers[index], PMIX_PRINT_NAME_ARGS_MAX_SIZE, "INVALID"); } else { pmix_snprintf(ptr->buffers[index], PMIX_PRINT_NAME_ARGS_MAX_SIZE, "%ld", (long) vpid); } ptr->cntr++; if (PMIX_PRINT_NAME_ARG_NUM_BUFS == ptr->cntr) { ptr->cntr = 0; } return ptr->buffers[index]; } int pmix_util_compare_proc(const void *a, const void *b) { const pmix_proc_t *proc_a = (pmix_proc_t *)a; const pmix_proc_t *proc_b = (pmix_proc_t *)b; int nspace_dif = strncmp(proc_a->nspace, proc_b->nspace, PMIX_MAX_NSLEN); if (nspace_dif != 0) return nspace_dif; return proc_a->rank - proc_b->rank; } pmix-6.1.1~rc2/src/util/pmix_os_dirpath.c0000664000175000017500000002213115203536752020575 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #include #if HAVE_SYS_STAT_H # include #endif /* HAVE_SYS_STAT_H */ #ifdef HAVE_SYS_TYPES_H # include #endif /* HAVE_SYS_TYPES_H */ #ifdef HAVE_DIRENT_H # include #endif /* HAVE_DIRENT_H */ #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/mca/ptl/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_os_dirpath.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_output.h" #include "src/util/pmix_show_help.h" static const char path_sep[] = PMIX_PATH_SEP; int pmix_os_dirpath_create(const char *path, const mode_t mode) { char **parts, *tmp; int i, len; int ret; if (NULL == path) { /* protect ourselves from errors */ return (PMIX_ERR_BAD_PARAM); } /* try to make directory */ if (0 == mkdir(path, mode)) { return (PMIX_SUCCESS); } ret = errno; // preserve the error /* check the error */ if (EEXIST == ret) { // already exists - try to set the mode. // Silently fail the chmod if it hits an error - we'll // let us fail later when we try to actually create a // file if we aren't allowed to do so. However, we have // to capture the return to silence static code // analyzer complaints ret = chmod(path, mode); if (0 != ret) { pmix_output_verbose(2, pmix_globals.debug_output, "PATH %s ALREADY EXISTS AND CHMOD FAILED: %s", path, strerror(errno)); } return PMIX_ERR_EXISTS; } if (ENOENT != ret) { // cannot create it pmix_show_help("help-pmix-util.txt", "mkdir-failed", true, path, strerror(ret)); return PMIX_ERR_SILENT; } /* didn't work, so now have to build our way down the tree */ /* Split the requested path up into its individual parts */ parts = PMIx_Argv_split(path, path_sep[0]); /* Ensure to allocate enough space for tmp: the strlen of the incoming path + 1 (for \0) */ tmp = (char *) calloc((strlen(path) + 1), sizeof(char)); tmp[0] = '\0'; /* Iterate through all the subdirectory names in the path, building up a directory name. Check to see if that dirname exists. If it doesn't, create it. */ len = PMIx_Argv_count(parts); for (i = 0; i < len; ++i) { if (i == 0) { /* If in POSIX-land, ensure that we never end a directory name with path_sep */ if ('/' == path[0]) { strcat(tmp, path_sep); } strcat(tmp, parts[i]); } /* If it's not the first part, ensure that there's a preceding path_sep and then append this part */ else { if (path_sep[0] != tmp[strlen(tmp) - 1]) { strcat(tmp, path_sep); } strcat(tmp, parts[i]); } /* Now that we have the name, try to create it */ ret = mkdir(tmp, mode); if (0 != ret && EEXIST != errno) { // true error pmix_show_help("help-pmix-util.txt", "mkdir-failed", true, tmp, strerror(errno)); PMIx_Argv_free(parts); free(tmp); return PMIX_ERR_SILENT; } } /* All done */ PMIx_Argv_free(parts); free(tmp); return PMIX_SUCCESS; } /** * This function attempts to remove a directory along with all the * files in it. If the recursive variable is non-zero, then it will * try to recursively remove all directories. If provided, the * callback function is executed prior to the directory or file being * removed. If the callback returns non-zero, then no removal is * done. */ int pmix_os_dirpath_destroy(const char *path, bool recursive, pmix_os_dirpath_destroy_callback_fn_t cbfunc) { int rc, exit_status = PMIX_SUCCESS; DIR *dp; struct dirent *ep; char *filenm = NULL; if (NULL == path) { /* protect against error */ return PMIX_ERROR; } /* Open up the directory */ dp = opendir(path); if (NULL == dp) { return PMIX_ERROR; } while (NULL != (ep = readdir(dp))) { /* skip: * - . and .. */ if ((0 == strcmp(ep->d_name, ".")) || (0 == strcmp(ep->d_name, ".."))) { continue; } /* Will the caller allow us to remove this file/directory? */ if (NULL != cbfunc) { /* * Caller does not wish to remove this file/directory, * continue with the rest of the entries */ if (!(cbfunc(path, ep->d_name))) { continue; } } /* Create a pathname. This is not always needed, but it makes * for cleaner code just to create it here. Note that we are * allocating memory here, so we need to free it later on. */ filenm = pmix_os_path(false, path, ep->d_name, NULL); // attempt to unlink it rc = unlink(filenm); if (0 > rc) { // we failed to unlink it - save the error rc = errno; if (EPERM == rc || EISDIR == rc) { // it's a directory - attempt to remove it rc = rmdir(filenm); if (0 == rc) { // success free(filenm); continue; } /* if it wasn't empty and we are recursively removing * paths, then proceed downwards */ if (ENOTEMPTY == errno && recursive) { rc = pmix_os_dirpath_destroy(filenm, recursive, cbfunc); free(filenm); if (PMIX_SUCCESS != rc) { exit_status = rc; closedir(dp); goto cleanup; } } else { free(filenm); } } else if (EBUSY == rc) { /* file system mount point or another process * is using it */ exit_status = PMIX_ERROR; free(filenm); continue; } else { // uncorrectable error pmix_show_help("help-pmix-util.txt", "unlink-error", true, filenm, strerror(rc)); free(filenm); filenm = NULL; exit_status = PMIX_ERROR; break; } } else { free(filenm); } } /* Done with this directory */ closedir(dp); cleanup: /* * If the directory is empty, then remove it - but * leave the system tmpdir alone unless we created it! */ if (NULL == pmix_server_globals.system_tmpdir || 0 != strcmp(path, pmix_server_globals.system_tmpdir)) { rmdir(path); } else if (NULL != pmix_server_globals.system_tmpdir && 0 == strcmp(path, pmix_server_globals.system_tmpdir) && pmix_ptl_base.created_system_tmpdir) { rmdir(path); free(pmix_ptl_base.system_tmpdir); pmix_ptl_base.system_tmpdir = NULL; } return exit_status; } bool pmix_os_dirpath_is_empty(const char *path) { DIR *dp; struct dirent *ep; if (NULL != path) { /* protect against error */ dp = opendir(path); if (NULL != dp) { while ((ep = readdir(dp))) { if ((0 != strcmp(ep->d_name, ".")) && (0 != strcmp(ep->d_name, ".."))) { closedir(dp); return false; } } closedir(dp); return true; } return false; } return true; } /** * Stale function left for PRRTE backward compatility */ int pmix_os_dirpath_access(const char *path, const mode_t mode) { PMIX_HIDE_UNUSED_PARAMS(path, mode); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/threads/0000775000175000017500000000000015203536752015716 5ustar alastairalastairpmix-6.1.1~rc2/src/threads/thread.c0000664000175000017500000000740615203536752017340 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015-2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include "src/threads/pmix_threads.h" #include "src/threads/pmix_tsd.h" bool pmix_debug_threads = false; static void pmix_thread_construct(pmix_thread_t *t); static pthread_t pmix_main_thread; struct pmix_tsd_key_value { pmix_tsd_key_t key; pmix_tsd_destructor_t destructor; }; static struct pmix_tsd_key_value *pmix_tsd_key_values = NULL; static int pmix_tsd_key_values_count = 0; PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_thread_t, pmix_object_t, pmix_thread_construct, NULL); /* * Constructor */ static void pmix_thread_construct(pmix_thread_t *t) { t->t_run = 0; t->t_handle = (pthread_t) -1; } int pmix_thread_start(pmix_thread_t *t) { int rc; if (PMIX_ENABLE_DEBUG) { if (NULL == t->t_run || t->t_handle != (pthread_t) -1) { return PMIX_ERR_BAD_PARAM; } } rc = pthread_create(&t->t_handle, NULL, (void *(*) (void *) ) t->t_run, t); return (rc == 0) ? PMIX_SUCCESS : PMIX_ERROR; } int pmix_thread_join(pmix_thread_t *t, void **thr_return) { int rc = pthread_join(t->t_handle, thr_return); t->t_handle = (pthread_t) -1; return (rc == 0) ? PMIX_SUCCESS : PMIX_ERROR; } bool pmix_thread_self_compare(pmix_thread_t *t) { return t->t_handle == pthread_self(); } pmix_thread_t *pmix_thread_get_self(void) { pmix_thread_t *t = PMIX_NEW(pmix_thread_t); t->t_handle = pthread_self(); return t; } void pmix_thread_kill(pmix_thread_t *t, int sig) { pthread_kill(t->t_handle, sig); } int pmix_tsd_key_create(pmix_tsd_key_t *key, pmix_tsd_destructor_t destructor) { int rc; rc = pthread_key_create(key, destructor); if ((0 == rc) && (pthread_self() == pmix_main_thread)) { pmix_tsd_key_values = (struct pmix_tsd_key_value *) realloc(pmix_tsd_key_values, (pmix_tsd_key_values_count + 1) * sizeof(struct pmix_tsd_key_value)); pmix_tsd_key_values[pmix_tsd_key_values_count].key = *key; pmix_tsd_key_values[pmix_tsd_key_values_count].destructor = destructor; pmix_tsd_key_values_count++; } return rc; } int pmix_tsd_keys_destruct(void) { int i; void *ptr; for (i = 0; i < pmix_tsd_key_values_count; i++) { if (PMIX_SUCCESS == pmix_tsd_getspecific(pmix_tsd_key_values[i].key, &ptr)) { if (NULL != pmix_tsd_key_values[i].destructor) { pmix_tsd_key_values[i].destructor(ptr); pmix_tsd_setspecific(pmix_tsd_key_values[i].key, NULL); } } } if (0 < pmix_tsd_key_values_count) { free(pmix_tsd_key_values); pmix_tsd_key_values_count = 0; } return PMIX_SUCCESS; } void pmix_thread_set_main(void) { pmix_main_thread = pthread_self(); } pmix-6.1.1~rc2/src/threads/pmix_threads.h0000664000175000017500000002147615203536752020570 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015-2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2017-2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_THREAD_H #define PMIX_THREAD_H 1 #include "src/include/pmix_config.h" #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_atomic.h" #if PMIX_ENABLE_DEBUG # include "src/util/pmix_output.h" #endif #include "pmix_mutex.h" BEGIN_C_DECLS typedef void *(*pmix_thread_fn_t)(pmix_object_t *); #define PMIX_THREAD_CANCELLED ((void *) 1); struct pmix_thread_t { pmix_object_t super; pmix_thread_fn_t t_run; void *t_arg; pthread_t t_handle; }; typedef struct pmix_thread_t pmix_thread_t; #if PMIX_ENABLE_DEBUG PMIX_EXPORT extern bool pmix_debug_threads; #endif PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_thread_t); #define pmix_condition_wait(a, b) pthread_cond_wait(a, &(b)->m_lock_pthread) typedef pthread_cond_t pmix_condition_t; #define pmix_condition_broadcast(a) pthread_cond_broadcast(a) #define pmix_condition_signal(a) pthread_cond_signal(a) #define PMIX_CONDITION_STATIC_INIT PTHREAD_COND_INITIALIZER typedef struct { pmix_status_t status; pmix_mutex_t mutex; pmix_condition_t cond; volatile bool active; } pmix_lock_t; #define PMIX_LOCK_STATIC_INIT \ { \ .status = PMIX_SUCCESS, \ .mutex = PMIX_MUTEX_STATIC_INIT, \ .cond = PMIX_CONDITION_STATIC_INIT, \ .active = false \ } #define PMIX_CONSTRUCT_LOCK(l) \ do { \ PMIX_CONSTRUCT(&(l)->mutex, pmix_mutex_t); \ /* take the lock */ \ pmix_mutex_lock(&(l)->mutex); \ pthread_cond_init(&(l)->cond, NULL); \ (l)->active = true; \ pmix_mutex_unlock(&(l)->mutex); \ } while (0) #define PMIX_DESTRUCT_LOCK(l) \ do { \ PMIX_DESTRUCT(&(l)->mutex); \ pthread_cond_destroy(&(l)->cond); \ } while (0) #if PMIX_ENABLE_DEBUG # define PMIX_ACQUIRE_THREAD(lck) \ do { \ pmix_mutex_lock(&(lck)->mutex); \ if (pmix_debug_threads) { \ pmix_output(0, "Waiting for thread %s:%d", __FILE__, __LINE__); \ } \ while ((lck)->active) { \ pmix_condition_wait(&(lck)->cond, &(lck)->mutex); \ } \ if (pmix_debug_threads) { \ pmix_output(0, "Thread obtained %s:%d", __FILE__, __LINE__); \ } \ PMIX_ACQUIRE_OBJECT(lck); \ (lck)->active = true; \ } while (0) #else # define PMIX_ACQUIRE_THREAD(lck) \ do { \ pmix_mutex_lock(&(lck)->mutex); \ while ((lck)->active) { \ pmix_condition_wait(&(lck)->cond, &(lck)->mutex); \ } \ PMIX_ACQUIRE_OBJECT(lck); \ (lck)->active = true; \ } while (0) #endif #if PMIX_ENABLE_DEBUG # define PMIX_WAIT_THREAD(lck) \ do { \ pmix_mutex_lock(&(lck)->mutex); \ if (pmix_debug_threads) { \ pmix_output(0, "Waiting for thread %s:%d", __FILE__, __LINE__); \ } \ while ((lck)->active) { \ pmix_condition_wait(&(lck)->cond, &(lck)->mutex); \ } \ if (pmix_debug_threads) { \ pmix_output(0, "Thread obtained %s:%d", __FILE__, __LINE__); \ } \ PMIX_ACQUIRE_OBJECT(lck); \ pmix_mutex_unlock(&(lck)->mutex); \ } while (0) #else # define PMIX_WAIT_THREAD(lck) \ do { \ pmix_mutex_lock(&(lck)->mutex); \ while ((lck)->active) { \ pmix_condition_wait(&(lck)->cond, &(lck)->mutex); \ } \ PMIX_ACQUIRE_OBJECT(lck); \ pmix_mutex_unlock(&(lck)->mutex); \ } while (0) #endif #if PMIX_ENABLE_DEBUG # define PMIX_RELEASE_THREAD(lck) \ do { \ if (pmix_debug_threads) { \ pmix_output(0, "Releasing thread %s:%d", __FILE__, __LINE__); \ } \ (lck)->active = false; \ PMIX_POST_OBJECT(lck); \ pmix_condition_signal(&(lck)->cond); \ pmix_mutex_unlock(&(lck)->mutex); \ } while (0) #else # define PMIX_RELEASE_THREAD(lck) \ do { \ (lck)->active = false; \ PMIX_POST_OBJECT(lck); \ pmix_condition_signal(&(lck)->cond); \ pmix_mutex_unlock(&(lck)->mutex); \ } while (0) #endif #define PMIX_WAKEUP_THREAD(lck) \ do { \ pmix_mutex_lock(&(lck)->mutex); \ (lck)->active = false; \ PMIX_POST_OBJECT(lck); \ pmix_condition_signal(&(lck)->cond); \ pmix_mutex_unlock(&(lck)->mutex); \ } while (0) /* provide a macro for forward-proofing the shifting * of objects between threads - at some point, we * may revamp our threading model */ /* post an object to another thread - for now, we * only have a memory barrier */ #define PMIX_POST_OBJECT(o) pmix_atomic_wmb() /* acquire an object from another thread - for now, * we only have a memory barrier */ #define PMIX_ACQUIRE_OBJECT(o) pmix_atomic_rmb() PMIX_EXPORT int pmix_thread_start(pmix_thread_t *); PMIX_EXPORT int pmix_thread_join(pmix_thread_t *, void **thread_return); PMIX_EXPORT bool pmix_thread_self_compare(pmix_thread_t *); PMIX_EXPORT pmix_thread_t *pmix_thread_get_self(void); PMIX_EXPORT void pmix_thread_kill(pmix_thread_t *, int sig); PMIX_EXPORT void pmix_thread_set_main(void); END_C_DECLS #endif /* PMIX_THREAD_H */ pmix-6.1.1~rc2/src/threads/mutex.c0000664000175000017500000000532215203536752017226 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2016 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2017-2018 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "src/threads/pmix_mutex.h" static void pmix_mutex_construct(pmix_mutex_t *m) { #if PMIX_ENABLE_DEBUG pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); /* set type to ERRORCHECK so that we catch recursive locks */ # if PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK_NP pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); # elif PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); # endif /* PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK_NP */ pthread_mutex_init(&m->m_lock_pthread, &attr); pthread_mutexattr_destroy(&attr); m->m_lock_debug = 0; m->m_lock_file = NULL; m->m_lock_line = 0; #else /* Without debugging, choose the fastest available mutexes */ pthread_mutex_init(&m->m_lock_pthread, NULL); #endif /* PMIX_ENABLE_DEBUG */ } static void pmix_mutex_destruct(pmix_mutex_t *m) { pthread_mutex_destroy(&m->m_lock_pthread); } PMIX_CLASS_INSTANCE(pmix_mutex_t, pmix_object_t, pmix_mutex_construct, pmix_mutex_destruct); static void pmix_recursive_mutex_construct(pmix_recursive_mutex_t *m) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); #if PMIX_ENABLE_DEBUG m->m_lock_debug = 0; m->m_lock_file = NULL; m->m_lock_line = 0; #endif pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&m->m_lock_pthread, &attr); pthread_mutexattr_destroy(&attr); } PMIX_CLASS_INSTANCE(pmix_recursive_mutex_t, pmix_object_t, pmix_recursive_mutex_construct, pmix_mutex_destruct); pmix-6.1.1~rc2/src/threads/pmix_mutex.h0000664000175000017500000000520015203536752020263 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2016 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2007-2016 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2007 Voltaire. All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * * Copyright (c) 2017 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_MUTEX_H #define PMIX_MUTEX_H 1 #include "src/include/pmix_config.h" BEGIN_C_DECLS /** * @file: * * Mutual exclusion functions. * * Functions for locking of critical sections. */ /** * Opaque mutex object */ typedef struct pmix_mutex_t pmix_mutex_t; typedef struct pmix_mutex_t pmix_recursive_mutex_t; /** * Try to acquire a mutex. * * @param mutex Address of the mutex. * @return 0 if the mutex was acquired, 1 otherwise. */ static inline int pmix_mutex_trylock(pmix_mutex_t *mutex); /** * Acquire a mutex. * * @param mutex Address of the mutex. */ static inline void pmix_mutex_lock(pmix_mutex_t *mutex); /** * Release a mutex. * * @param mutex Address of the mutex. */ static inline void pmix_mutex_unlock(pmix_mutex_t *mutex); /** * Try to acquire a mutex using atomic operations. * * @param mutex Address of the mutex. * @return 0 if the mutex was acquired, 1 otherwise. */ static inline int pmix_mutex_atomic_trylock(pmix_mutex_t *mutex); /** * Acquire a mutex using atomic operations. * * @param mutex Address of the mutex. */ static inline void pmix_mutex_atomic_lock(pmix_mutex_t *mutex); /** * Release a mutex using atomic operations. * * @param mutex Address of the mutex. */ static inline void pmix_mutex_atomic_unlock(pmix_mutex_t *mutex); END_C_DECLS #include "pmix_mutex_unix.h" #endif /* PMIX_MUTEX_H */ pmix-6.1.1~rc2/src/threads/Makefile.include0000664000175000017500000000252715203536752021006 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2016 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2017-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from pmix/Makefile.am # Source code files headers += \ threads/pmix_mutex.h \ threads/pmix_mutex_unix.h \ threads/pmix_threads.h \ threads/pmix_tsd.h sources += \ threads/mutex.c \ threads/thread.c pmix-6.1.1~rc2/src/threads/pmix_tsd.h0000664000175000017500000000576615203536752017734 0ustar alastairalastair/* * Copyright (c) 2007-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015-2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_THREADS_TSD_H #define PMIX_THREADS_TSD_H #include "src/include/pmix_config.h" #include #include "pmix_common.h" BEGIN_C_DECLS /** * @file * * Thread Specific Datastore Interface * * Functions for providing thread-specific datastore capabilities. */ /** * Prototype for callback when tsd data is being destroyed */ typedef void (*pmix_tsd_destructor_t)(void *value); typedef pthread_key_t pmix_tsd_key_t; static inline int pmix_tsd_key_delete(pmix_tsd_key_t key) { return pthread_key_delete(key); } static inline int pmix_tsd_setspecific(pmix_tsd_key_t key, void *value) { return pthread_setspecific(key, value); } static inline int pmix_tsd_getspecific(pmix_tsd_key_t key, void **valuep) { *valuep = pthread_getspecific(key); return PMIX_SUCCESS; } /** * Create thread-specific data key * * Create a thread-specific data key visible to all threads in the * current process. The returned key is valid in all threads, * although the values bound to the key by pmix_tsd_setspecific() are * allocated on a per-thread basis and persist for the life of the * calling thread. * * Upon key creation, the value NULL is associated with the new key in * all active threads. When a new thread is created, the value NULL * is associated with all defined keys in the new thread. * * The destructor parameter may be NULL. At thread exit, if * destructor is non-NULL AND the thread has a non-NULL value * associated with the key, the function is called with the current * value as its argument. * * @param key[out] The key for accessing thread-specific data * @param destructor[in] Cleanup function to call when a thread exits * * @retval PMIX_SUCCESS Success * @retval EAGAIN The system lacked the necessary resource to * create another thread specific data key * @retval ENOMEM Insufficient memory exists to create the key */ PMIX_EXPORT int pmix_tsd_key_create(pmix_tsd_key_t *key, pmix_tsd_destructor_t destructor); /** * Destruct all thread-specific data keys * * Destruct all thread-specific data keys and invoke the destructor * * This should only be invoked in the main thread. * This is made necessary since destructors are not invoked on the * keys of the main thread, since there is no such thing as * pthread_join(main_thread) * * @retval PMIX_SUCCESS Success */ PMIX_EXPORT int pmix_tsd_keys_destruct(void); END_C_DECLS #endif /* PMIX_MTHREADS_TSD_H */ pmix-6.1.1~rc2/src/threads/pmix_mutex_unix.h0000664000175000017500000001304615203536752021335 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015-2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_MUTEX_UNIX_H #define PMIX_MUTEX_UNIX_H 1 /** * @file: * * Mutual exclusion functions: Unix implementation. * * Functions for locking of critical sections. * * On unix, use pthreads or our own atomic operations as * available. */ #include "src/include/pmix_config.h" #include #include #include #include "src/class/pmix_object.h" BEGIN_C_DECLS struct pmix_mutex_t { pmix_object_t super; pthread_mutex_t m_lock_pthread; #if PMIX_ENABLE_DEBUG int m_lock_debug; const char *m_lock_file; int m_lock_line; #endif }; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_mutex_t); PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_recursive_mutex_t); #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) # define PMIX_PTHREAD_RECURSIVE_MUTEX_INITIALIZER PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP #elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER) # define PMIX_PTHREAD_RECURSIVE_MUTEX_INITIALIZER PTHREAD_RECURSIVE_MUTEX_INITIALIZER #endif #if PMIX_ENABLE_DEBUG # define PMIX_MUTEX_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_mutex_t), \ .m_lock_pthread = PTHREAD_MUTEX_INITIALIZER, .m_lock_debug = 0, .m_lock_file = NULL, \ .m_lock_line = 0, \ } #else # define PMIX_MUTEX_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_mutex_t), \ .m_lock_pthread = PTHREAD_MUTEX_INITIALIZER, \ } #endif #if defined(PMIX_PTHREAD_RECURSIVE_MUTEX_INITIALIZER) # if PMIX_ENABLE_DEBUG # define PMIX_RECURSIVE_MUTEX_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_mutex_t), \ .m_lock_pthread = PMIX_PTHREAD_RECURSIVE_MUTEX_INITIALIZER, .m_lock_debug = 0, \ .m_lock_file = NULL, .m_lock_line = 0, \ } # else # define PMIX_RECURSIVE_MUTEX_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_mutex_t), \ .m_lock_pthread = PMIX_PTHREAD_RECURSIVE_MUTEX_INITIALIZER, \ } # endif #endif /************************************************************************ * * mutex operations (non-atomic versions) * ************************************************************************/ static inline int pmix_mutex_trylock(pmix_mutex_t *m) { #if PMIX_ENABLE_DEBUG int ret = pthread_mutex_trylock(&m->m_lock_pthread); if (ret == EDEADLK) { errno = ret; perror("pmix_mutex_trylock()"); abort(); } return ret; #else return pthread_mutex_trylock(&m->m_lock_pthread); #endif } static inline void pmix_mutex_lock(pmix_mutex_t *m) { #if PMIX_ENABLE_DEBUG int ret = pthread_mutex_lock(&m->m_lock_pthread); if (ret == EDEADLK) { errno = ret; perror("pmix_mutex_lock()"); abort(); } #else pthread_mutex_lock(&m->m_lock_pthread); #endif } static inline void pmix_mutex_unlock(pmix_mutex_t *m) { #if PMIX_ENABLE_DEBUG int ret = pthread_mutex_unlock(&m->m_lock_pthread); if (ret == EPERM) { errno = ret; perror("pmix_mutex_unlock"); abort(); } #else pthread_mutex_unlock(&m->m_lock_pthread); #endif } /************************************************************************ * Standard locking ************************************************************************/ static inline int pmix_mutex_atomic_trylock(pmix_mutex_t *m) { return pmix_mutex_trylock(m); } static inline void pmix_mutex_atomic_lock(pmix_mutex_t *m) { pmix_mutex_lock(m); } static inline void pmix_mutex_atomic_unlock(pmix_mutex_t *m) { pmix_mutex_unlock(m); } END_C_DECLS #endif /* PMIX_MUTEX_UNIX_H */ pmix-6.1.1~rc2/src/runtime/0000775000175000017500000000000015203536752015747 5ustar alastairalastairpmix-6.1.1~rc2/src/runtime/pmix_rte.h0000664000175000017500000000501415203536752017747 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2010-2022 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file **/ #ifndef PMIX_RTE_H #define PMIX_RTE_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/class/pmix_object.h" #include #include #include #include #include "src/include/pmix_globals.h" #include "src/mca/ptl/ptl_types.h" BEGIN_C_DECLS #if PMIX_ENABLE_TIMING PMIX_EXPORT extern char *pmix_timing_sync_file; PMIX_EXPORT extern char *pmix_timing_output; PMIX_EXPORT extern bool pmix_timing_overhead; #endif PMIX_EXPORT extern char *pmix_net_private_ipv4; PMIX_EXPORT extern int pmix_event_caching_window; PMIX_EXPORT extern char *pmix_progress_thread_cpus; PMIX_EXPORT extern bool pmix_bind_progress_thread_reqd; PMIX_EXPORT extern int pmix_maxfd; PMIX_EXPORT extern int pmix_server_client_fintime; PMIX_EXPORT extern bool pmix_keep_fqdn_hostnames; /** version string of pmix */ extern const char pmix_version_string[]; /** * Initialize the PMIX layer, including the MCA system. * * @retval PMIX_SUCCESS Upon success. * @retval PMIX_ERROR Upon failure. * */ PMIX_EXPORT pmix_status_t pmix_rte_init(uint32_t type, pmix_info_t info[], size_t ninfo, pmix_ptl_cbfunc_t cbfunc); /** * Finalize the PMIX layer, including the MCA system. * */ PMIX_EXPORT void pmix_rte_finalize(void); /** * Internal function. Do not call. */ PMIX_EXPORT pmix_status_t pmix_register_params(void); PMIX_EXPORT pmix_status_t pmix_deregister_params(void); PMIX_EXPORT void pmix_set_aliases(char ***aliases, char *hostname); END_C_DECLS #endif /* PMIX_RTE_H */ pmix-6.1.1~rc2/src/runtime/help-pmix-runtime.txt0000664000175000017500000000643215203536752022101 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. # Copyright (c) 2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017-2018 Intel, Inc. All rights reserved. # Copyright (c) 2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English general help file for PMIX. # [pmix_init:startup:internal-failure] It looks like pmix_init failed for some reason; your parallel process is likely to abort. There are many reasons that a parallel process can fail during pmix_init; some of which are due to configuration or environment problems. This failure appears to be an internal failure; here's some additional information (which may only be relevant to an PMIX developer): %s failed --> Returned value %d instead of PMIX_SUCCESS # [no-plugins] We were unable to find any usable plugins for the %s framework. This PMIx framework requires at least one plugin in order to operate. This can be caused by any of the following: * we were unable to build any of the plugins due to some combination of configure directives and available system support * no plugin was selected due to some combination of MCA parameter directives versus built plugins (i.e., you excluded all the plugins that were built and/or could execute) * the PMIX_PREFIX environment variable, or the MCA parameter "mca_base_component_path", is set and doesn't point to any location that includes at least one usable plugin for this framework. Please check your installation and environment. # [ptl:msg_size] A received msg header indicates a size that is too large: Requested size: %lu Size limit: %lu If you believe this msg is legitimate, please increase the max msg size via the ptl_base_max_msg_size parameter. # [tool:no-server] A call was made to PMIx_tool_connect_to_server, but no information was given as to which server the tool should be connected. Accepted attributes include: - PMIX_CONNECT_TO_SYSTEM: connect solely to the system server - PMIX_CONNECT_SYSTEM_FIRST: a request to use the system server first, if existing, and then look for the server specified in a different attribute - PMIX_SERVER_URI: connect to the server at the given URI - PMIX_SERVER_NSPACE: connect to the server of a given nspace - PMIX_SERVER_PIDINFO: connect to a server embedded in the process with the given pid Please correct your program and try again. # [reentrant-init] An attempt was made to call an initialization routine, but the PMIx library has already been initialized: Function: %s Multiple calls to init are not supported. Please correct your program. pmix-6.1.1~rc2/src/runtime/pmix_finalize.c0000664000175000017500000001311215203536752020747 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010-2015 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2023 Triad National Security, LLC. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file **/ #include "src/include/pmix_config.h" #include "src/class/pmix_object.h" #include "src/client/pmix_client_ops.h" #include "src/common/pmix_attributes.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/mca/pcompress/base/base.h" #include "src/mca/pif/base/base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/mca/plog/base/base.h" #include "src/mca/pnet/base/base.h" #include "src/mca/preg/base/base.h" #include "src/mca/psec/base/base.h" #include "src/mca/ptl/base/base.h" #include "src/threads/pmix_tsd.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_output.h" #include "src/util/pmix_show_help.h" #include "src/util/pmix_net.h" #include "src/runtime/pmix_init_util.h" #include #include "src/runtime/pmix_progress_threads.h" #include "src/runtime/pmix_rte.h" extern int pmix_initialized; extern bool pmix_init_called; void pmix_rte_finalize(void) { int i; pmix_notify_caddy_t *cd; pmix_iof_req_t *req; if (!pmix_init_called) { return; } /* stop the main progress thread - does not release * the event base so we don't break the components */ (void) pmix_progress_thread_pause(NULL); /* release the attribute support trackers */ pmix_release_registered_attrs(); /* close plog */ (void) pmix_mca_base_framework_close(&pmix_plog_base_framework); /* close preg */ (void) pmix_mca_base_framework_close(&pmix_preg_base_framework); /* cleanup communications */ (void) pmix_mca_base_framework_close(&pmix_ptl_base_framework); /* close the security framework */ (void) pmix_mca_base_framework_close(&pmix_psec_base_framework); /* close bfrops */ (void) pmix_mca_base_framework_close(&pmix_bfrops_base_framework); /* close compress */ (void) pmix_mca_base_framework_close(&pmix_pcompress_base_framework); /* close GDS */ (void) pmix_mca_base_framework_close(&pmix_gds_base_framework); /* Finalize the network helper subsystem. */ (void)pmix_net_finalize(); /* finalize the mca */ /* Clear out all the registered MCA params */ pmix_deregister_params(); pmix_mca_base_var_finalize(); /* keyval lex-based parser */ pmix_util_keyval_parse_finalize(); (void) pmix_mca_base_framework_close(&pmix_pinstalldirs_base_framework); (void) pmix_mca_base_framework_close(&pmix_pif_base_framework); (void) pmix_mca_base_close(); /* finalize the show_help system */ pmix_show_help_finalize(); /* finalize the output system. This has to come *after* the malloc code, as the malloc code needs to call into this, but the malloc code turning off doesn't affect pmix_output that much */ pmix_output_finalize(); /* clean out the globals */ PMIX_RELEASE(pmix_globals.mypeer); PMIX_DESTRUCT(&pmix_globals.events); PMIX_LIST_DESTRUCT(&pmix_globals.cached_events); /* clear any notifications */ for (i = 0; i < pmix_globals.max_events; i++) { pmix_hotel_checkout_and_return_occupant(&pmix_globals.notifications, i, (void **) &cd); if (NULL != cd) { PMIX_RELEASE(cd); } } PMIX_DESTRUCT(&pmix_globals.notifications); for (i = 0; i < pmix_globals.iof_requests.size; i++) { req = (pmix_iof_req_t *) pmix_pointer_array_get_item(&pmix_globals.iof_requests, i); if (NULL != req) { PMIX_RELEASE(req); } } PMIX_DESTRUCT(&pmix_globals.iof_requests); PMIX_LIST_DESTRUCT(&pmix_globals.stdin_targets); if (NULL != pmix_globals.hostname) { free(pmix_globals.hostname); pmix_globals.hostname = NULL; } if (NULL != pmix_globals.aliases) { PMIx_Argv_free(pmix_globals.aliases); pmix_globals.aliases = NULL; } PMIX_LIST_DESTRUCT(&pmix_globals.nspaces); PMIX_LIST_DESTRUCT(&pmix_client_globals.groups); PMIX_DESTRUCT(&pmix_globals.keyindex); free(pmix_globals.myidval.data.proc); // release the topology pmix_hwloc_finalize(); for (i = 0; i < PMIX_VAR_DUMP_COLOR_KEY_COUNT; i++) { free(pmix_var_dump_color[i]); pmix_var_dump_color[i] = NULL; } pmix_tsd_keys_destruct(); pmix_finalize_util(); // release the event base pmix_progress_thread_stop(NULL); } pmix-6.1.1~rc2/src/runtime/pmix_params.c0000664000175000017500000004716215203536752020445 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2014 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2008-2022 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2009 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2010-2014 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2014 Hochschule Esslingen. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2019 Intel, Inc. All rights reserved. * Copyright (c) 2020 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "src/client/pmix_client_ops.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/runtime/pmix_rte.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "src/util/pmix_timings.h" #if PMIX_ENABLE_TIMING char *pmix_timing_output = NULL; bool pmix_timing_overhead = true; #endif static bool pmix_register_done = false; char *pmix_net_private_ipv4 = NULL; int pmix_event_caching_window = 1; char *pmix_progress_thread_cpus = NULL; bool pmix_bind_progress_thread_reqd = false; int pmix_maxfd = 1024; int pmix_server_client_fintime; bool pmix_keep_fqdn_hostnames = false; char *pmix_var_dump_color[PMIX_VAR_DUMP_COLOR_KEY_COUNT] = {NULL}; static char *pmix_var_dump_color_string = NULL; static char *pmix_var_dump_color_keys[PMIX_VAR_DUMP_COLOR_KEY_COUNT+1] = { [PMIX_VAR_DUMP_COLOR_VAR_NAME] = "name", [PMIX_VAR_DUMP_COLOR_VAR_VALUE] = "value", [PMIX_VAR_DUMP_COLOR_VALID_VALUES] = "valid_values", [PMIX_VAR_DUMP_COLOR_KEY_COUNT] = NULL }; static int parse_color_string(char *color_string, char **key_names, int key_count, char **values_out); pmix_status_t pmix_register_params(void) { int ret; char *string, *tmp; if (pmix_register_done) { return PMIX_SUCCESS; } pmix_register_done = true; #if PMIX_ENABLE_TIMING pmix_timing_output = NULL; (void) pmix_mca_base_var_register( "pmix", "pmix", NULL, "timing_output", "The name of output file for timing information. If this parameter is not set then output " "will be directed into PMIX debug channel.", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_timing_output); pmix_timing_overhead = true; (void) pmix_mca_base_var_register( "pmix", "pmix", NULL, "timing_overhead", "Timing framework introduce additional overhead (malloc's mostly)." " The time spend in such costly routines is measured and may be accounted" " (subtracted from timestamps). 'true' means consider overhead, 'false' - ignore (default: " "true).", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_timing_overhead); #endif /* RFC1918 defines - 10.0.0./8 - 172.16.0.0/12 - 192.168.0.0/16 RFC3330 also mentions - 169.254.0.0/16 for DHCP onlink iff there's no DHCP server */ pmix_net_private_ipv4 = "10.0.0.0/8;172.16.0.0/12;192.168.0.0/16;169.254.0.0/16"; ret = pmix_mca_base_var_register( "pmix", "pmix", "net", "private_ipv4", "Semicolon-delimited list of CIDR notation entries specifying what networks are considered " "\"private\" (default value based on RFC1918 and RFC3330)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_net_private_ipv4); if (0 > ret) { return ret; } pmix_event_caching_window = 1; (void) pmix_mca_base_var_register( "pmix", "pmix", NULL, "event_caching_window", "Time (in seconds) to aggregate events before reporting them - this " "suppresses event cascades when processes abnormally terminate", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_event_caching_window); /**** CLIENT: VERBOSE OUTPUT PARAMS ****/ (void) pmix_mca_base_var_register("pmix", "pmix", "client", "get_verbose", "Verbosity for client get operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_client_globals.get_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "client", "connect_verbose", "Verbosity for client connect operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_client_globals.connect_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "client", "fence_verbose", "Verbosity for client fence operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_client_globals.fence_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "client", "pub_verbose", "Verbosity for client publish, lookup, and unpublish operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_client_globals.pub_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "client", "spawn_verbose", "Verbosity for client spawn operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_client_globals.spawn_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "client", "event_verbose", "Verbosity for client event notifications", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_client_globals.event_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "client", "iof_verbose", "Verbosity for client iof operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_client_globals.iof_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "client", "base_verbose", "Verbosity for basic client operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_client_globals.base_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "client", "group_verbose", "Verbosity for server group operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_client_globals.group_verbose); /**** SERVER: VERBOSE OUTPUT PARAMS ****/ (void) pmix_mca_base_var_register("pmix", "pmix", "server", "get_verbose", "Verbosity for server get operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_globals.get_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "server", "connect_verbose", "Verbosity for server connect operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_globals.connect_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "server", "fence_verbose", "Verbosity for server fence operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_globals.fence_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "server", "pub_verbose", "Verbosity for server publish, lookup, and unpublish operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_globals.pub_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "server", "spawn_verbose", "Verbosity for server spawn operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_globals.spawn_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "server", "event_verbose", "Verbosity for server event operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_globals.event_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "server", "iof_verbose", "Verbosity for server iof operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_globals.iof_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "server", "base_verbose", "Verbosity for basic server operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_globals.base_verbose); (void) pmix_mca_base_var_register("pmix", "pmix", "server", "group_verbose", "Verbosity for server group operations", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_globals.group_verbose); pmix_server_globals.fence_localonly_opt = true; (void) pmix_mca_base_var_register( "pmix", "pmix", "server", "fence_localonly_opt", "Optimize local-only fence opteration by eliminating the upcall to the RM (default: true)", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_server_globals.fence_localonly_opt); /* check for maximum number of pending output messages */ pmix_globals.output_limit = (size_t) INT_MAX; (void) pmix_mca_base_var_register("pmix", "iof", NULL, "output_limit", "Maximum backlog of output messages [default: unlimited]", PMIX_MCA_BASE_VAR_TYPE_SIZE_T, &pmix_globals.output_limit); pmix_globals.xml_output = false; (void) pmix_mca_base_var_register("pmix", "iof", NULL, "xml_output", "Display all output in XML format (default: false)", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_globals.xml_output); /* whether to tag output */ /* if we requested xml output, be sure to tag the output as well */ pmix_globals.tag_output = pmix_globals.xml_output; (void) pmix_mca_base_var_register("pmix", "iof", NULL, "tag_output", "Tag all output with [job,rank] (default: false)", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_globals.tag_output); if (pmix_globals.xml_output) { pmix_globals.tag_output = true; } /* whether to timestamp output */ pmix_globals.timestamp_output = false; (void) pmix_mca_base_var_register("pmix", "iof", NULL, "timestamp_output", "Timestamp all application process output (default: false)", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_globals.timestamp_output); /* max size of the notification hotel */ pmix_globals.max_events = 512; (void) pmix_mca_base_var_register("pmix", "pmix", "max", "events", "Maximum number of event notifications to cache", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_globals.max_events); /* how long to cache an event */ pmix_globals.event_eviction_time = 120; (void) pmix_mca_base_var_register("pmix", "pmix", "event", "eviction_time", "Maximum number of seconds to cache an event", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_globals.event_eviction_time); /* max number of IOF messages to cache */ pmix_server_globals.max_iof_cache = 1024 * 1024; (void) pmix_mca_base_var_register("pmix", "pmix", "max", "iof_cache", "Maximum number of IOF messages to cache", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_globals.max_iof_cache); (void) pmix_mca_base_var_register("pmix", "pmix", NULL, "progress_thread_cpus", "Comma-delimited list of ranges of CPUs to which" "the internal PMIx progress thread is to be bound", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_progress_thread_cpus); (void) pmix_mca_base_var_register("pmix", "pmix", NULL, "bind_progress_thread_reqd", "Whether binding of internal PMIx progress thread is required", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_bind_progress_thread_reqd); (void) pmix_mca_base_var_register("pmix", "pmix", NULL, "maxfd", "In non-Linux environments, use this value as a maximum number of file descriptors to close when forking a new child process", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_maxfd); pmix_server_client_fintime = 10; (void) pmix_mca_base_var_register("pmix", "pmix", NULL, "finalize_timeout", "Time in seconds to wait for server to ack client finalize request", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_server_client_fintime); pmix_keep_fqdn_hostnames = false; (void) pmix_mca_base_var_register("pmix", "pmix", NULL, "keep_fqdn_hostnames", "Whether or not to keep FQDN hostnames [default: no]", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_keep_fqdn_hostnames); /* Var-dump color */ string = pmix_argv_join_range(pmix_var_dump_color_keys, 0, PMIX_VAR_DUMP_COLOR_KEY_COUNT, ','); if (NULL == string) { return PMIX_ERR_OUT_OF_RESOURCE; } ret = pmix_asprintf(&tmp, "The colors to use when dumping MCA vars with color " "(e.g. pmix_info). The format is a comma-delimited key=value list, where the " "key is the attribute whose color to adjust, and the value is the ANSI color " "code (see the ANSI X3.64 CSI SGR sequence). Available keys: %s.", string); free(string); string = tmp; if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } /* Basic color options: 30=black, 31=red, 32=green, * 33=yellow, 34=blue, 35=magenta, 36=cyan, 37=white * https://en.wikipedia.org/wiki/ANSI_escape_code#Colors */ pmix_var_dump_color_string = "name=34,value=32,valid_values=36"; ret = pmix_mca_base_var_register("pmix", "pmix", NULL, "var_dump_color", string, PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_var_dump_color_string); free(string); if (0 > ret) { return ret; } ret = parse_color_string(pmix_var_dump_color_string, pmix_var_dump_color_keys, PMIX_VAR_DUMP_COLOR_KEY_COUNT, pmix_var_dump_color); if (PMIX_SUCCESS != ret) { return ret; } pmix_hwloc_register(); return PMIX_SUCCESS; } pmix_status_t pmix_deregister_params(void) { pmix_register_done = false; return PMIX_SUCCESS; } /* Parses a color 'string' and extracts the 'code' for each 'key' * The string is in the format of 'key1=code1:key2=code2:...' * Example: pmix_var_dump_color MCA parameter * * color_string: The string containing the key=code sequences to parse * key_names: The keys to extract (e.g. key1, key2) * key_count: The length of key_names * values_out: The extracted values for the keys, 1-1 with key_names * ATTENTION: Make sure it's at least as large as key_names... */ static int parse_color_string(char *color_string, char **key_names, int key_count, char **values_out) { char **tokens = NULL, **kv = NULL; int return_code = PMIX_SUCCESS; for (int k = 0; k < key_count; k++) { values_out[k] = NULL; } if (NULL != color_string) { tokens = PMIx_Argv_split(color_string, ','); if (NULL == tokens) { return_code = PMIX_ERR_OUT_OF_RESOURCE; goto end; } } for (int i = 0; tokens && tokens[i] != NULL; i++) { kv = PMIx_Argv_split(tokens[i], '='); if (NULL == kv) { return_code = PMIX_ERR_OUT_OF_RESOURCE; goto end; } // Expected format of token: key=code if (PMIx_Argv_count(kv) != 2) { pmix_show_help("help-pmix-runtime.txt", "var_dump_color:format-error", true, tokens[i]); goto skip_token; } bool key_found = false; // Look for key name and store value in respective position for (int k = 0; k < key_count; ++k) { if (strcasecmp(key_names[k], kv[0]) == 0) { int ret = pmix_asprintf(&values_out[k], "\033[%sm", kv[1]); if (ret < 0) { return_code = PMIX_ERR_OUT_OF_RESOURCE; goto end; } key_found = true; break; } } if (!key_found) { char *valid_keys = pmix_argv_join_range(key_names, 0, key_count, ','); if (NULL == valid_keys) { return_code = PMIX_ERR_OUT_OF_RESOURCE; goto end; } pmix_show_help("help-pmix-runtime.txt", "var_dump_color:unknown-key", true, kv[0], tokens[i], valid_keys); free(valid_keys); } skip_token: PMIx_Argv_free(kv); kv = NULL; } // Set values for keys not in the MCA parameter to "" for (int k = 0; k < key_count; k++) { if (NULL == values_out[k]) { values_out[k] = strdup(""); // needs to be free-able if (NULL == values_out[k]) { return_code = PMIX_ERR_OUT_OF_RESOURCE; goto end; } } } end: PMIx_Argv_free(tokens); PMIx_Argv_free(kv); if (return_code != PMIX_SUCCESS) { for (int k = 0; k < key_count; k++) { free(values_out[k]); values_out[k] = NULL; } } return return_code; } pmix-6.1.1~rc2/src/runtime/pmix_info_support.c0000664000175000017500000014040515203536752021703 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010-2016 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2011-2012 University of Houston. All rights reserved. * Copyright (c) 2016-2017 Intel, Inc. All rights reserved. * Copyright (c) 2017 IBM Corporation. All rights reserved. * Copyright (c) 2018 Amazon.com, Inc. or its affiliates. All Rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022 Computer Architecture and VLSI Systems (CARV) * Laboratory, ICS Forth. All rights reserved. * Copyright (c) 2023 Jeffrey M. Squyres. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include #ifdef HAVE_UNISTD_H # include #endif #include #include "src/class/pmix_list.h" #include "src/class/pmix_pointer_array.h" #include "src/include/pmix_portable_platform_real.h" #include "src/runtime/pmix_rte.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_error.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "src/include/pmix_frameworks.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/mca/base/pmix_mca_base_component_repository.h" #include "src/runtime/pmix_info_support.h" const char *pmix_info_path_prefix = "prefix"; const char *pmix_info_path_bindir = "bindir"; const char *pmix_info_path_libdir = "libdir"; const char *pmix_info_path_incdir = "incdir"; const char *pmix_info_path_mandir = "mandir"; const char *pmix_info_path_pkglibdir = "pkglibdir"; const char *pmix_info_path_sysconfdir = "sysconfdir"; const char *pmix_info_path_exec_prefix = "exec_prefix"; const char *pmix_info_path_sbindir = "sbindir"; const char *pmix_info_path_libexecdir = "libexecdir"; const char *pmix_info_path_datarootdir = "datarootdir"; const char *pmix_info_path_datadir = "datadir"; const char *pmix_info_path_sharedstatedir = "sharedstatedir"; const char *pmix_info_path_localstatedir = "localstatedir"; const char *pmix_info_path_infodir = "infodir"; const char *pmix_info_path_pkgdatadir = "pkgdatadir"; const char *pmix_info_path_pkgincludedir = "pkgincludedir"; bool pmix_info_pretty = true; bool pmix_info_color = false; pmix_mca_base_register_flag_t pmix_info_register_flags = PMIX_MCA_BASE_REGISTER_ALL; const char *pmix_info_type_all = "all"; const char *pmix_info_type_pmix = "pmix"; const char *pmix_info_component_all = "all"; const char *pmix_info_param_all = "all"; const char *pmix_info_ver_full = "full"; const char *pmix_info_ver_major = "major"; const char *pmix_info_ver_minor = "minor"; const char *pmix_info_ver_release = "release"; const char *pmix_info_ver_greek = "greek"; const char *pmix_info_ver_repo = "repo"; const char *pmix_info_ver_all = "all"; const char *pmix_info_ver_mca = "mca"; const char *pmix_info_ver_type = "type"; const char *pmix_info_ver_component = "component"; static int pmix_info_registered = 0; static void component_map_construct(pmix_info_component_map_t *map) { map->project = NULL; map->type = NULL; } static void component_map_destruct(pmix_info_component_map_t *map) { if (NULL != map->project) { free(map->project); } if (NULL != map->type) { free(map->type); } /* the type close functions will release the * list of components */ } PMIX_CLASS_INSTANCE(pmix_info_component_map_t, pmix_list_item_t, component_map_construct, component_map_destruct); static void pmix_info_show_failed_component(const pmix_mca_base_component_repository_item_t *ri, const char *error_msg); int pmix_info_init(int argc, char **argv, pmix_cli_result_t *pmix_info_cmd_line, struct option poptions[], char *pshorts, char *helpfile) { int ret; char *color; pmix_cli_item_t *opt; PMIX_HIDE_UNUSED_PARAMS(argc); /* initialize the help system */ pmix_show_help_init(); /* keyval lex-based parser */ if (PMIX_SUCCESS != (ret = pmix_util_keyval_parse_init())) { fprintf(stderr, "pmix_util_keyval_parse_init failed with %d\n", ret); return PMIX_ERROR; } /* Setup the parameter system */ if (PMIX_SUCCESS != (ret = pmix_mca_base_var_init())) { fprintf(stderr, "pmix_mca_base_var_init failed with %d\n", ret); return PMIX_ERROR; } if (PMIX_SUCCESS != pmix_mca_base_open(NULL)) { pmix_show_help("help-pmix_info.txt", "lib-call-fail", true, "mca_base_open", __FILE__, __LINE__); PMIX_RELEASE(pmix_info_cmd_line); return PMIX_ERROR; } /* Do the parsing */ ret = pmix_cmd_line_parse(argv, pshorts, poptions, NULL, pmix_info_cmd_line, helpfile); if (PMIX_SUCCESS != ret) { if (PMIX_ERR_SILENT != ret && PMIX_OPERATION_SUCCEEDED != ret) { fprintf(stderr, "%s: command line error (%s)\n", argv[0], PMIx_Error_string(ret)); } if (PMIX_OPERATION_SUCCEEDED == ret) { ret = PMIX_SUCCESS; } exit(ret); } /* Determine color support */ opt = pmix_cmd_line_get_param(pmix_info_cmd_line, PMIX_CLI_INFO_COLOR); if (NULL != opt) { color = NULL; if (NULL != opt->values) { color = opt->values[0]; } if (NULL == color) { color = "auto"; } } else { color = "auto"; } if (0 == strcasecmp(color, "auto")) { #if HAVE_ISATTY pmix_info_color = isatty(STDOUT_FILENO); #else pmix_info_color = false; #endif } else if (0 == strcasecmp(color, "always")) { pmix_info_color = true; } else if (0 == strcasecmp(color, "never")) { pmix_info_color = false; } else { fprintf(stderr, "%s: Unrecognized value '%s' to color parameter\n", argv[0], color); return PMIX_ERROR; } /* set the flags */ if (pmix_cmd_line_is_taken(pmix_info_cmd_line, PMIX_CLI_PRETTY_PRINT)) { pmix_info_pretty = true; } else if (pmix_cmd_line_is_taken(pmix_info_cmd_line, PMIX_CLI_PARSABLE) || pmix_cmd_line_is_taken(pmix_info_cmd_line, PMIX_CLI_PARSEABLE)) { pmix_info_pretty = false; } if (pmix_cmd_line_is_taken(pmix_info_cmd_line, PMIX_CLI_INFO_SELECTED_ONLY)) { /* register only selected components */ pmix_info_register_flags = PMIX_MCA_BASE_REGISTER_DEFAULT; } if (pmix_cmd_line_is_taken(pmix_info_cmd_line, PMIX_CLI_INFO_SHOW_FAILED)) { pmix_mca_base_component_track_load_errors = true; } return PMIX_SUCCESS; } void pmix_info_finalize(void) { pmix_finalize_util(); } static int info_register_framework(const char *project_name, pmix_mca_base_framework_t *framework, pmix_pointer_array_t *component_map) { pmix_info_component_map_t *map; int rc; rc = pmix_mca_base_framework_register(framework, pmix_info_register_flags); if (PMIX_SUCCESS != rc && PMIX_ERR_BAD_PARAM != rc) { return rc; } if (NULL != component_map) { map = PMIX_NEW(pmix_info_component_map_t); map->project = strdup(project_name); map->type = strdup(framework->framework_name); map->components = &framework->framework_components; map->failed_components = &framework->framework_failed_components; pmix_pointer_array_add(component_map, map); } return rc; } int pmix_info_register_project_frameworks(const char *project_name, pmix_mca_base_framework_t **frameworks, pmix_pointer_array_t *component_map) { int i, rc = PMIX_SUCCESS; for (i = 0; NULL != frameworks[i]; i++) { if (PMIX_SUCCESS != (rc = info_register_framework(project_name, frameworks[i], component_map))) { if (PMIX_ERR_BAD_PARAM == rc) { fprintf(stderr, "\nA \"bad parameter\" error was encountered when opening the %s %s " "framework\n", project_name, frameworks[i]->framework_name); fprintf(stderr, "The output received from that framework includes the following " "parameters:\n\n"); } else if (PMIX_ERR_NOT_AVAILABLE != rc) { fprintf(stderr, "%s_info_register: %s failed\n", project_name, frameworks[i]->framework_name); rc = PMIX_ERROR; } else { continue; } break; } } return rc; } void pmix_info_register_types(pmix_pointer_array_t *mca_types, bool frames_only) { int i; if (!frames_only) { /* add the top-level types */ pmix_pointer_array_add(mca_types, "mca"); pmix_pointer_array_add(mca_types, "pmix"); } /* push all the types found by autogen */ for (i = 0; NULL != pmix_frameworks[i]; i++) { pmix_pointer_array_add(mca_types, pmix_frameworks[i]->framework_name); } } int pmix_info_register_framework_params(pmix_pointer_array_t *component_map) { int rc; if (pmix_info_registered++) { return PMIX_SUCCESS; } /* Register mca/base parameters */ if (PMIX_SUCCESS != pmix_mca_base_open(NULL)) { pmix_show_help("help-pmix_info.txt", "lib-call-fail", true, "pmix_mca_base_open", __FILE__, __LINE__); return PMIX_ERROR; } /* Register the PMIX layer's MCA parameters */ if (PMIX_SUCCESS != (rc = pmix_register_params())) { fprintf(stderr, "pmix_info_register: pmix_register_params failed\n"); return rc; } return pmix_info_register_project_frameworks("pmix", pmix_frameworks, component_map); } void pmix_info_close_components(void) { int i; assert(pmix_info_registered); if (--pmix_info_registered) { return; } for (i = 0; NULL != pmix_frameworks[i]; i++) { (void) pmix_mca_base_framework_close(pmix_frameworks[i]); } /* release our reference to MCA */ pmix_mca_base_close(); } void pmix_info_do_pmix_config(bool want_all) { char *debug; char *have_dl; char *symbol_visibility; /* setup the strings that don't require allocations*/ debug = PMIX_ENABLE_DEBUG ? "yes" : "no"; have_dl = PMIX_HAVE_PDL_SUPPORT ? "yes" : "no"; symbol_visibility = PMIX_HAVE_VISIBILITY ? "yes" : "no"; /* output values */ pmix_info_out("Configured by", "config:user", PMIX_CONFIGURE_USER); pmix_info_out("Configured on", "config:timestamp", PMIX_CONFIGURE_DATE); pmix_info_out("Configure host", "config:host", PMIX_CONFIGURE_HOST); pmix_info_out("Configure command line", "config:cli", PMIX_CONFIGURE_CLI); pmix_info_out("Built by", "build:user", PMIX_BUILD_USER); pmix_info_out("Built on", "build:timestamp", PMIX_BUILD_DATE); pmix_info_out("Built host", "build:host", PMIX_BUILD_HOST); pmix_info_out("C compiler", "compiler:c:command", PMIX_CC); pmix_info_out("C compiler absolute", "compiler:c:absolute", PMIX_CC_ABSOLUTE); pmix_info_out("C compiler family name", "compiler:c:familyname", PLATFORM_STRINGIFY(PLATFORM_COMPILER_FAMILYNAME)); pmix_info_out("C compiler version", "compiler:c:version", PLATFORM_STRINGIFY(PLATFORM_COMPILER_VERSION_STR)); if (want_all) { pmix_info_out_int("C bool size", "compiler:c:sizeof:bool", sizeof(bool)); pmix_info_out_int("C short size", "compiler:c:sizeof:short", sizeof(short)); pmix_info_out_int("C int size", "compiler:c:sizeof:int", sizeof(int)); pmix_info_out_int("C long size", "compiler:c:sizeof:long", sizeof(long)); pmix_info_out_int("C pointer size", "compiler:c:sizeof:pointer", sizeof(void *)); } if (want_all) { pmix_info_out("Build CFLAGS", "option:build:cflags", PMIX_BUILD_CFLAGS); pmix_info_out("Build LDFLAGS", "option:build:ldflags", PMIX_BUILD_LDFLAGS); pmix_info_out("Build LIBS", "option:build:libs", PMIX_BUILD_LIBS); } pmix_info_out("Internal debug support", "option:debug", debug); pmix_info_out("dl support", "option:dlopen", have_dl); pmix_info_out("Symbol vis. support", "options:visibility", symbol_visibility); pmix_info_out("Manpages built", "options:man-pages", "yes"); } /* * do_config * Accepts: * - want_all: boolean flag; TRUE -> display all options * FALSE -> display selected options * * This function displays all the options with which the current * pinstallation of pmix was configured. There are many options here * that are carried forward from OMPI-7 and are not mca parameters * in OMPI-10. I have to dig through the invalid options and replace * them with OMPI-10 options. */ void pmix_info_do_config(bool want_all, char *user, char *date, char *host, char *cli, char *builduser, char *builddate, char *buildhost, char *ccline, char *ccabs, char *family, char *versionstr, char *cflags, char *ldflags, char *libs, bool enabledebug, bool havedl, bool havevis) { char *debug; char *have_dl; char *symbol_visibility; /* setup the strings that don't require allocations*/ debug = enabledebug ? "yes" : "no"; have_dl = havedl ? "yes" : "no"; symbol_visibility = havevis ? "yes" : "no"; /* output values */ pmix_info_out("Configured by", "config:user", user); pmix_info_out("Configured on", "config:timestamp", date); pmix_info_out("Configure host", "config:host", host); pmix_info_out("Configure command line", "config:cli", cli); pmix_info_out("Built by", "build:user", builduser); pmix_info_out("Built on", "build:timestamp", builddate); pmix_info_out("Built host", "build:host", buildhost); pmix_info_out("C compiler", "compiler:c:command", ccline); pmix_info_out("C compiler absolute", "compiler:c:absolute", ccabs); pmix_info_out("C compiler family name", "compiler:c:familyname", family); pmix_info_out("C compiler version", "compiler:c:version", versionstr); if (want_all) { pmix_info_out_int("C bool size", "compiler:c:sizeof:bool", sizeof(bool)); pmix_info_out_int("C short size", "compiler:c:sizeof:short", sizeof(short)); pmix_info_out_int("C int size", "compiler:c:sizeof:int", sizeof(int)); pmix_info_out_int("C long size", "compiler:c:sizeof:long", sizeof(long)); pmix_info_out_int("C pointer size", "compiler:c:sizeof:pointer", sizeof(void *)); } if (want_all) { pmix_info_out("Build CFLAGS", "option:build:cflags", cflags); pmix_info_out("Build LDFLAGS", "option:build:ldflags", ldflags); pmix_info_out("Build LIBS", "option:build:libs", libs); } pmix_info_out("Internal debug support", "option:debug", debug); pmix_info_out("dl support", "option:dlopen", have_dl); pmix_info_out("Symbol vis. support", "options:visibility", symbol_visibility); pmix_info_out("Manpages built", "options:man-pages", "yes"); } void pmix_info_show_path(const char *type, const char *value) { char *pretty, *path; pretty = strdup(type); pretty[0] = toupper(pretty[0]); pmix_asprintf(&path, "path:%s", type); pmix_info_out(pretty, path, value); free(pretty); free(path); } void pmix_info_show_pmix_path(void) { pmix_info_show_path(pmix_info_path_prefix, pmix_pinstall_dirs.prefix); } void pmix_info_do_path(bool wall, pmix_cli_result_t *cmd_line, pmix_pinstall_dirs_t *dirs) { int i; char *scope; pmix_cli_item_t *opt; bool want_all = wall; /* Check bozo case */ opt = pmix_cmd_line_get_param(cmd_line, PMIX_CLI_INFO_PATH); if (NULL != opt) { for (i = 0; NULL != opt->values[i]; ++i) { if (0 == strcmp("all", opt->values[i])) { want_all = true; break; } } } if (want_all) { pmix_info_show_path(pmix_info_path_prefix, dirs->prefix); pmix_info_show_path(pmix_info_path_exec_prefix, dirs->exec_prefix); pmix_info_show_path(pmix_info_path_bindir, dirs->bindir); pmix_info_show_path(pmix_info_path_sbindir, dirs->sbindir); pmix_info_show_path(pmix_info_path_libdir, dirs->libdir); pmix_info_show_path(pmix_info_path_incdir, dirs->includedir); pmix_info_show_path(pmix_info_path_mandir, dirs->mandir); pmix_info_show_path(pmix_info_path_pkglibdir, dirs->pmixlibdir); pmix_info_show_path(pmix_info_path_libexecdir, dirs->libexecdir); pmix_info_show_path(pmix_info_path_datarootdir, dirs->datarootdir); pmix_info_show_path(pmix_info_path_datadir, dirs->datadir); pmix_info_show_path(pmix_info_path_sysconfdir, dirs->sysconfdir); pmix_info_show_path(pmix_info_path_sharedstatedir, dirs->sharedstatedir); pmix_info_show_path(pmix_info_path_localstatedir, dirs->localstatedir); pmix_info_show_path(pmix_info_path_infodir, dirs->infodir); pmix_info_show_path(pmix_info_path_pkgdatadir, dirs->pmixdatadir); pmix_info_show_path(pmix_info_path_pkglibdir, dirs->pmixlibdir); pmix_info_show_path(pmix_info_path_pkgincludedir, dirs->pmixincludedir); } else { for (i = 0; NULL != opt->values[i]; ++i) { scope = opt->values[i]; if (0 == strcmp(pmix_info_path_prefix, scope)) { pmix_info_show_path(pmix_info_path_prefix, dirs->prefix); } else if (0 == strcmp(pmix_info_path_bindir, scope)) { pmix_info_show_path(pmix_info_path_bindir, dirs->bindir); } else if (0 == strcmp(pmix_info_path_libdir, scope)) { pmix_info_show_path(pmix_info_path_libdir, dirs->libdir); } else if (0 == strcmp(pmix_info_path_incdir, scope)) { pmix_info_show_path(pmix_info_path_incdir, dirs->includedir); } else if (0 == strcmp(pmix_info_path_mandir, scope)) { pmix_info_show_path(pmix_info_path_mandir, dirs->mandir); } else if (0 == strcmp(pmix_info_path_pkglibdir, scope)) { pmix_info_show_path(pmix_info_path_pkglibdir, dirs->pmixlibdir); } else if (0 == strcmp(pmix_info_path_sysconfdir, scope)) { pmix_info_show_path(pmix_info_path_sysconfdir, dirs->sysconfdir); } else if (0 == strcmp(pmix_info_path_exec_prefix, scope)) { pmix_info_show_path(pmix_info_path_exec_prefix, dirs->exec_prefix); } else if (0 == strcmp(pmix_info_path_sbindir, scope)) { pmix_info_show_path(pmix_info_path_sbindir, dirs->sbindir); } else if (0 == strcmp(pmix_info_path_libexecdir, scope)) { pmix_info_show_path(pmix_info_path_libexecdir, dirs->libexecdir); } else if (0 == strcmp(pmix_info_path_datarootdir, scope)) { pmix_info_show_path(pmix_info_path_datarootdir, dirs->datarootdir); } else if (0 == strcmp(pmix_info_path_datadir, scope)) { pmix_info_show_path(pmix_info_path_datadir, dirs->datadir); } else if (0 == strcmp(pmix_info_path_sharedstatedir, scope)) { pmix_info_show_path(pmix_info_path_sharedstatedir, dirs->sharedstatedir); } else if (0 == strcmp(pmix_info_path_localstatedir, scope)) { pmix_info_show_path(pmix_info_path_localstatedir, dirs->localstatedir); } else if (0 == strcmp(pmix_info_path_infodir, scope)) { pmix_info_show_path(pmix_info_path_infodir, dirs->infodir); } else if (0 == strcmp(pmix_info_path_pkgdatadir, scope)) { pmix_info_show_path(pmix_info_path_pkgdatadir, dirs->pmixdatadir); } else if (0 == strcmp(pmix_info_path_pkgincludedir, scope)) { pmix_info_show_path(pmix_info_path_pkgincludedir, dirs->pmixincludedir); } else { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); exit(1); } } } } void pmix_info_do_pmix_path(bool wall, pmix_cli_result_t *cmd_line) { pmix_info_do_path(wall, cmd_line, &pmix_pinstall_dirs); } void pmix_info_do_params(const char *project, bool want_all_in, bool want_internal, pmix_pointer_array_t *mca_types, pmix_pointer_array_t *component_map, pmix_cli_result_t *pmix_info_cmd_line) { pmix_cli_item_t *opt; char *type, *component, *str; bool found; int i; bool want_all = false; opt = pmix_cmd_line_get_param(pmix_info_cmd_line, PMIX_CLI_INFO_PARAM); if (NULL == opt) { opt = pmix_cmd_line_get_param(pmix_info_cmd_line, PMIX_CLI_INFO_PARAMS); } if (want_all_in) { want_all = true; } else if (NULL != opt) { /* See if the special param "all" was given to --param; that * supercedes any individual type */ if (NULL != opt->values) { for (i=0; NULL != opt->values[i]; i++) { if (0 == strcasecmp(opt->values[i], "all")) { want_all = true; } } } } else { // they didn't ask for params, so this shouldn't have come // here as there is nothing to be done return; } /* Show the params */ if (want_all) { pmix_info_show_component_version(project, mca_types, component_map, pmix_info_type_all, pmix_info_component_all, pmix_info_ver_full, pmix_info_ver_all); for (i = 0; i < mca_types->size; ++i) { if (NULL == (type = (char *) pmix_pointer_array_get_item(mca_types, i))) { continue; } pmix_info_show_mca_params(type, pmix_info_component_all, want_internal); } } else { if (NULL == opt->values) { pmix_show_help("help-pmix_info.txt", "missing-type", true); exit(1); } for (i = 0; NULL != opt->values[i]; ++i) { type = opt->values[i]; ++i; if (NULL == opt->values[i]) { pmix_show_help("help-pmix_info.txt", "missing-component", true); exit(1); } component = opt->values[i]; for (found = false, i = 0; i < mca_types->size; ++i) { if (NULL == (str = (char *) pmix_pointer_array_get_item(mca_types, i))) { continue; } if (0 == strcmp(str, type)) { found = true; break; } } if (!found) { pmix_show_help("help-pmix_info.txt", "not-found", true, type); exit(1); } pmix_info_show_component_version(project, mca_types, component_map, type, component, pmix_info_ver_full, pmix_info_ver_all); pmix_info_show_mca_params(type, component, want_internal); } } } void pmix_info_err_params(pmix_pointer_array_t *component_map) { pmix_info_component_map_t *map = NULL, *mptr; int i; /* all we want to do is display the LAST entry in the * component_map array as this is the one that generated the error */ for (i = 0; i < component_map->size; i++) { mptr = (pmix_info_component_map_t *) pmix_pointer_array_get_item(component_map, i); if (NULL == mptr) { continue; } map = mptr; } if (NULL == map) { fprintf(stderr, "pmix_info_err_params: map not found\n"); return; } pmix_info_show_mca_params(map->type, pmix_info_component_all, true); fprintf(stderr, "\n"); return; } void pmix_info_do_type(pmix_cli_result_t *pmix_info_cmd_line) { pmix_cli_item_t *opt; char *type; int i, j, k, len, ret; const pmix_mca_base_var_t *var; char **strings, *message; const pmix_mca_base_var_group_t *group; opt = pmix_cmd_line_get_param(pmix_info_cmd_line, PMIX_CLI_INFO_TYPES); if (NULL == opt) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); exit(1); } if (NULL == opt->values) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); exit(1); } len = pmix_mca_base_var_get_count(); for (k = 0; NULL != opt->values[k]; ++k) { type = opt->values[k]; for (i = 0; i < len; ++i) { ret = pmix_mca_base_var_get(i, &var); if (PMIX_SUCCESS != ret) { continue; } if (0 == strcmp(type, pmix_var_type_names[var->mbv_type])) { pmix_mca_base_var_dump_type_t dump_type = (!pmix_info_pretty ? PMIX_MCA_BASE_VAR_DUMP_PARSABLE : (pmix_info_color ? PMIX_MCA_BASE_VAR_DUMP_READABLE_COLOR : PMIX_MCA_BASE_VAR_DUMP_READABLE)); ret = pmix_mca_base_var_dump(var->mbv_index, &strings, dump_type); if (PMIX_SUCCESS != ret) { continue; } (void) pmix_mca_base_var_group_get(var->mbv_group_index, &group); for (j = 0; strings[j]; ++j) { if (0 == j && pmix_info_pretty) { pmix_asprintf(&message, "MCA %s", group->group_framework); pmix_output(0, "STRINGS: %s", strings[j]); pmix_info_out(message, message, strings[j]); free(message); } else { pmix_info_out("", "", strings[j]); } free(strings[j]); } free(strings); } } } } static void pmix_info_show_mca_group_params(const pmix_mca_base_var_group_t *group, bool want_internal) { const int *variables, *groups; const char *group_component; const pmix_mca_base_var_t *var; char **strings, *message; bool requested = true; int ret, i, j, count; variables = PMIX_VALUE_ARRAY_GET_BASE(&group->group_vars, const int); count = pmix_value_array_get_size((pmix_value_array_t *) &group->group_vars); /* the default component name is "base". depending on how the * group was registered the group may or not have this set. */ group_component = group->group_component ? group->group_component : "base"; /* check if this group may be disabled due to a selection variable */ if (0 != strcmp(group_component, "base")) { int var_id; /* read the selection parameter */ var_id = pmix_mca_base_var_find(group->group_project, group->group_framework, NULL, NULL); if (0 <= var_id) { const pmix_mca_base_var_storage_t *value = NULL; char **requested_components; bool include_mode; pmix_mca_base_var_get_value(var_id, &value, NULL, NULL); if (NULL != value && NULL != value->stringval && '\0' != value->stringval[0]) { pmix_mca_base_component_parse_requested(value->stringval, &include_mode, &requested_components); for (i = 0, requested = !include_mode; requested_components[i]; ++i) { if (0 == strcmp(requested_components[i], group_component)) { requested = include_mode; break; } } pmix_argv_free(requested_components); } } } const pmix_mca_base_var_group_t *curr_group = NULL; char *component_msg = NULL; pmix_asprintf(&component_msg, " %s", group_component); for (i = 0; i < count; ++i) { ret = pmix_mca_base_var_get(variables[i], &var); if (PMIX_SUCCESS != ret || ((var->mbv_flags & PMIX_MCA_BASE_VAR_FLAG_INTERNAL) && !want_internal)) { continue; } if (pmix_info_pretty && curr_group != group) { pmix_asprintf(&message, "MCA%s %s%s", requested ? "" : " (-)", group->group_framework, component_msg ? component_msg : ""); pmix_info_out(message, message, "---------------------------------------------------"); free(message); curr_group = group; } pmix_mca_base_var_dump_type_t dump_type = (!pmix_info_pretty ? PMIX_MCA_BASE_VAR_DUMP_PARSABLE : (pmix_info_color ? PMIX_MCA_BASE_VAR_DUMP_READABLE_COLOR : PMIX_MCA_BASE_VAR_DUMP_READABLE)); ret = pmix_mca_base_var_dump(variables[i], &strings, dump_type); if (PMIX_SUCCESS != ret) { continue; } for (j = 0; strings[j]; ++j) { if (0 == j && pmix_info_pretty) { pmix_asprintf(&message, "MCA%s %s%s", requested ? "" : " (-)", group->group_framework, component_msg ? component_msg : ""); pmix_info_out(message, message, strings[j]); free(message); } else { pmix_info_out("", "", strings[j]); } free(strings[j]); } if (!pmix_info_pretty) { /* generate an entry indicating whether this variable is disabled or not. if the * format in mca_base_var/pvar.c changes this needs to be changed as well */ pmix_asprintf(&message, "mca:%s:%s:param:%s:disabled:%s", group->group_framework, group_component, var->mbv_full_name, requested ? "false" : "true"); pmix_info_out("", "", message); free(message); } free(strings); } groups = PMIX_VALUE_ARRAY_GET_BASE(&group->group_subgroups, const int); count = pmix_value_array_get_size((pmix_value_array_t *) &group->group_subgroups); for (i = 0; i < count; ++i) { ret = pmix_mca_base_var_group_get(groups[i], &group); if (PMIX_SUCCESS != ret) { continue; } pmix_info_show_mca_group_params(group, want_internal); } free(component_msg); } void pmix_info_show_mca_params(const char *type, const char *component, bool want_internal) { const pmix_mca_base_var_group_t *group; int ret; if (0 == strcmp(component, "all")) { ret = pmix_mca_base_var_group_find("*", type, NULL); if (0 > ret) { return; } (void) pmix_mca_base_var_group_get(ret, &group); pmix_info_show_mca_group_params(group, want_internal); } else { ret = pmix_mca_base_var_group_find("*", type, component); if (0 > ret) { return; } (void) pmix_mca_base_var_group_get(ret, &group); pmix_info_show_mca_group_params(group, want_internal); } } void pmix_info_do_arch(void) { pmix_info_out("Configured architecture", "config:arch", PMIX_ARCH); } void pmix_info_do_hostname(void) { pmix_info_out("Configure host", "config:host", PMIX_CONFIGURE_HOST); } static char *escape_quotes(const char *value) { const char *src; int num_quotes = 0; for (src = value; src != NULL && *src != '\0'; ++src) { if ('"' == *src) { ++num_quotes; } } // If there are no quotes in the string, there's nothing to do if (0 == num_quotes) { return NULL; } // If we have quotes, make a new string. Copy over the old // string, escaping the quotes along the way. This is simple and // clear to read; it's not particularly efficient (performance is // definitely not important here). char *quoted_value; quoted_value = calloc(1, strlen(value) + num_quotes + 1); if (NULL == quoted_value) { return NULL; } char *dest; for (src = value, dest = quoted_value; *src != '\0'; ++src, ++dest) { if ('"' == *src) { *dest++ = '\\'; } *dest = *src; } return quoted_value; } /* * Private variables - set some reasonable screen size defaults */ static int centerpoint = 24; static int screen_width = 78; /* * Prints the passed message in a pretty or parsable format. */ void pmix_info_out(const char *pretty_message, const char *plain_message, const char *value) { size_t len, max_line_width, value_offset; char *spaces = NULL; char *filler = NULL; char *pos, *v, savev, *v_to_free; #ifdef HAVE_ISATTY /* If we have isatty(), if this is not a tty, then disable * wrapping for grep-friendly behavior */ if (0 == isatty(STDOUT_FILENO)) { screen_width = INT_MAX; } #endif #ifdef TIOCGWINSZ if (screen_width < INT_MAX) { struct winsize size; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *) &size) >= 0) { screen_width = size.ws_col; } } #endif /* Sanity check (allow NULL to mean "") */ if (NULL == value) { value = ""; } /* Strip leading and trailing whitespace from the string value */ value_offset = strspn(value, " "); v = v_to_free = strdup(value + value_offset); len = strlen(v); if (len > 0) { while (len > 0 && isspace(v[len - 1])) { len--; } v[len] = '\0'; } if (pmix_info_pretty && NULL != pretty_message) { if (centerpoint > (int) strlen(pretty_message)) { pmix_asprintf(&spaces, "%*s", centerpoint - (int) strlen(pretty_message), " "); } else { spaces = strdup(""); #if PMIX_ENABLE_DEBUG if (centerpoint < (int) strlen(pretty_message)) { pmix_show_help("help-pmix_info.txt", "developer warning: field too long", false, pretty_message, centerpoint); } #endif } max_line_width = screen_width - strlen(spaces) - strlen(pretty_message) - 2; if (0 < strlen(pretty_message)) { pmix_asprintf(&filler, "%s%s: ", spaces, pretty_message); } else { pmix_asprintf(&filler, "%s ", spaces); } free(spaces); spaces = NULL; while (true) { size_t max_value_chars = max_line_width; if (pmix_info_color) { /* We want to print at most max_line_width characters to the * output. Because `value` might contain bytes that do not * appear in the output (ie. escape codes), simply printing * `max_line_width` bytes will not maximize the number of * visible characters that we can print. */ bool in_escape = false; size_t invis = 0; /* The loop counts how many invisible characters we encounter * until the visible ones (= i - invis) reach `max_line_width` */ for (size_t i = 0; v[i] && (i - invis) < max_line_width; i++) { if ('\033' == v[i]) { in_escape = true; } if (in_escape) { invis++; } if ('m' == v[i]) { in_escape = false; } } /* Increase the line limit, so that the invisible * characters are effectively disregarded */ max_value_chars += invis; } if (strlen(v) < max_value_chars) { printf("%s%s\n", filler, v); break; } else { pmix_asprintf(&spaces, "%*s", centerpoint + 2, " "); /* Work backwards to find the first space before * max_value_chars */ savev = v[max_value_chars]; v[max_value_chars] = '\0'; pos = (char *) strrchr(v, (int) ' '); v[max_value_chars] = savev; if (NULL == pos) { /* No space found < max_value_chars. Look for the first * space after max_value_chars. */ pos = strchr(&v[max_value_chars], ' '); if (NULL == pos) { /* There's just no spaces. So just print it and be done. */ printf("%s%s\n", filler, v); break; } else { *pos = '\0'; printf("%s%s\n", filler, v); v = pos + 1; } } else { *pos = '\0'; printf("%s%s\n", filler, v); v = pos + 1; } /* Reset for the next iteration */ free(filler); filler = strdup(spaces); free(spaces); spaces = NULL; } } if (NULL != filler) { free(filler); } if (NULL != spaces) { free(spaces); } } else { if (NULL != plain_message && 0 < strlen(plain_message)) { // Escape any double quotes in the value. char *quoted_value; quoted_value = escape_quotes(value); if (NULL != quoted_value) { value = quoted_value; } char *colon = strchr(value, ':'); if (NULL != colon) { printf("%s:\"%s\"\n", plain_message, value); } else { printf("%s:%s\n", plain_message, value); } if (NULL != quoted_value) { free(quoted_value); } } else { printf("%s\n", value); } } if (NULL != v_to_free) { free(v_to_free); } } /* * Prints the passed integer in a pretty or parsable format. */ void pmix_info_out_int(const char *pretty_message, const char *plain_message, int value) { char *valstr; pmix_asprintf(&valstr, "%d", (int) value); pmix_info_out(pretty_message, plain_message, valstr); free(valstr); } /* * Show all the components of a specific type/component combo (component may be * a wildcard) */ void pmix_info_show_component_version(const char *project, pmix_pointer_array_t *mca_types, pmix_pointer_array_t *component_map, const char *type_name, const char *component_name, const char *scope, const char *ver_type) { bool want_all_components = false; bool want_all_types = false; bool found; pmix_mca_base_component_list_item_t *cli; pmix_mca_base_failed_component_t *cli_failed; int j; char *pos; pmix_info_component_map_t *map; /* see if all components wanted */ if (0 == strcmp(pmix_info_component_all, component_name)) { want_all_components = true; } /* see if all types wanted */ if (0 != strcmp(pmix_info_type_all, type_name)) { /* Check to see if the type is valid */ for (found = false, j = 0; j < mca_types->size; ++j) { if (NULL == (pos = (char *) pmix_pointer_array_get_item(mca_types, j))) { continue; } if (0 == strcmp(pos, type_name)) { found = true; break; } } if (!found) { return; } } else { want_all_types = true; } /* Now that we have a valid type, find the right components */ for (j = 0; j < component_map->size; j++) { map = (pmix_info_component_map_t *) pmix_pointer_array_get_item(component_map, j); if (NULL == map) { continue; } if (0 != strcasecmp(project, map->project)) { continue; } if ((want_all_types || 0 == strcmp(type_name, map->type)) && map->components) { /* found it! */ PMIX_LIST_FOREACH (cli, map->components, pmix_mca_base_component_list_item_t) { const pmix_mca_base_component_t *component = cli->cli_component; if (want_all_components || 0 == strcmp(component->pmix_mca_component_name, component_name)) { pmix_info_show_mca_version(component, scope, ver_type); } } /* found it! */ PMIX_LIST_FOREACH (cli_failed, map->failed_components, pmix_mca_base_failed_component_t) { pmix_mca_base_component_repository_item_t *ri = cli_failed->comp; if (want_all_components || 0 == strcmp(component_name, ri->ri_name)) { pmix_info_show_failed_component(ri, cli_failed->error_msg); } } if (!want_all_types) { break; } } } } static void pmix_info_show_failed_component(const pmix_mca_base_component_repository_item_t *ri, const char *error_msg) { char *message, *content; if (pmix_info_pretty) { pmix_asprintf(&message, "MCA %s", ri->ri_type); pmix_asprintf(&content, "%s (failed to load) %s", ri->ri_name, error_msg); pmix_info_out(message, NULL, content); free(message); free(content); } else { pmix_asprintf(&message, "mca:%s:%s:failed", ri->ri_type, ri->ri_name); pmix_asprintf(&content, "%s", error_msg); pmix_info_out(NULL, message, content); free(message); free(content); } } /* * Given a component, display its relevant version(s) */ void pmix_info_show_mca_version(const pmix_mca_base_component_t *component, const char *scope, const char *ver_type) { bool printed; bool want_mca = false; bool want_type = false; bool want_component = false; char *message, *content; char *mca_version; char *api_version; char *component_version; char *tmp; if (0 == strcmp(ver_type, pmix_info_ver_all) || 0 == strcmp(ver_type, pmix_info_ver_mca)) { want_mca = true; } if (0 == strcmp(ver_type, pmix_info_ver_all) || 0 == strcmp(ver_type, pmix_info_ver_type)) { want_type = true; } if (0 == strcmp(ver_type, pmix_info_ver_all) || 0 == strcmp(ver_type, pmix_info_ver_component)) { want_component = true; } mca_version = pmix_info_make_version_str(scope, component->pmix_mca_major_version, component->pmix_mca_minor_version, component->pmix_mca_release_version, "", ""); api_version = pmix_info_make_version_str(scope, component->pmix_mca_type_major_version, component->pmix_mca_type_minor_version, component->pmix_mca_type_release_version, "", ""); component_version = pmix_info_make_version_str(scope, component->pmix_mca_component_major_version, component->pmix_mca_component_minor_version, component->pmix_mca_component_release_version, "", ""); if (pmix_info_pretty) { pmix_asprintf(&message, "MCA %s", component->pmix_mca_type_name); printed = false; pmix_asprintf(&content, "%s (", component->pmix_mca_component_name); if (want_mca) { pmix_asprintf(&tmp, "%sMCA v%s", content, mca_version); free(content); content = tmp; printed = true; } if (want_type) { if (printed) { pmix_asprintf(&tmp, "%s, ", content); free(content); content = tmp; } pmix_asprintf(&tmp, "%sAPI v%s", content, api_version); free(content); content = tmp; printed = true; } if (want_component) { if (printed) { pmix_asprintf(&tmp, "%s, ", content); free(content); content = tmp; } pmix_asprintf(&tmp, "%sComponent v%s", content, component_version); free(content); content = tmp; printed = true; } if (NULL != content) { pmix_asprintf(&tmp, "%s)", content); free(content); } else { tmp = NULL; } pmix_info_out(message, NULL, tmp); free(message); if (NULL != tmp) { free(tmp); } } else { pmix_asprintf(&message, "mca:%s:%s:version", component->pmix_mca_type_name, component->pmix_mca_component_name); if (want_mca) { pmix_asprintf(&tmp, "mca:%s", mca_version); pmix_info_out(NULL, message, tmp); free(tmp); } if (want_type) { pmix_asprintf(&tmp, "api:%s", api_version); pmix_info_out(NULL, message, tmp); free(tmp); } if (want_component) { pmix_asprintf(&tmp, "component:%s", component_version); pmix_info_out(NULL, message, tmp); free(tmp); } free(message); } if (NULL != mca_version) { free(mca_version); } if (NULL != api_version) { free(api_version); } if (NULL != component_version) { free(component_version); } } char *pmix_info_make_version_str(const char *scope, int major, int minor, int release, const char *greek, const char *repo) { char *str = NULL, *tmp; char temp[BUFSIZ]; temp[BUFSIZ - 1] = '\0'; if (0 == strcmp(scope, pmix_info_ver_full) || 0 == strcmp(scope, pmix_info_ver_all)) { snprintf(temp, BUFSIZ - 1, "%d.%d.%d", major, minor, release); str = strdup(temp); if (NULL != greek) { pmix_asprintf(&tmp, "%s%s", str, greek); free(str); str = tmp; } } else if (0 == strcmp(scope, pmix_info_ver_major)) { snprintf(temp, BUFSIZ - 1, "%d", major); } else if (0 == strcmp(scope, pmix_info_ver_minor)) { snprintf(temp, BUFSIZ - 1, "%d", minor); } else if (0 == strcmp(scope, pmix_info_ver_release)) { snprintf(temp, BUFSIZ - 1, "%d", release); } else if (0 == strcmp(scope, pmix_info_ver_greek)) { str = strdup(greek); } else if (0 == strcmp(scope, pmix_info_ver_repo)) { str = strdup(repo); } if (NULL == str) { str = strdup(temp); } return str; } void pmix_info_show_package(char *pkgstring) { pmix_info_out("Package", "package", pkgstring); } void pmix_info_show_pmix_package(void) { pmix_info_show_package(PMIX_PACKAGE_STRING); } void pmix_info_show_version(const char *project, const char *scope, int major, int minor, int release, const char *greek, const char *repo, const char *rdate) { char *tmp, *tmp2; pmix_asprintf(&tmp, "%s:version:full", pmix_info_type_pmix); tmp2 = pmix_info_make_version_str(scope, major, minor, release, greek, repo); pmix_info_out(project, tmp, tmp2); free(tmp); free(tmp2); pmix_asprintf(&tmp, "%s:version:repo", pmix_info_type_pmix); pmix_asprintf(&tmp2, "%s repo revision", project); pmix_info_out(tmp2, tmp, repo); free(tmp); free(tmp2); pmix_asprintf(&tmp, "%s:version:release_date", pmix_info_type_pmix); pmix_asprintf(&tmp2, "%s release date", project); pmix_info_out(tmp2, tmp, rdate); free(tmp); free(tmp2); } void pmix_info_show_pmix_version(void) { pmix_info_show_version("PMIx", pmix_info_ver_full, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION, PMIX_GREEK_VERSION, PMIX_REPO_REV, PMIX_RELEASE_DATE); } pmix-6.1.1~rc2/src/runtime/pmix_progress_threads.h0000664000175000017500000000547715203536752022550 0ustar alastairalastair/* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PROGRESS_THREADS_H #define PMIX_PROGRESS_THREADS_H #include "pmix_config.h" #include #include #include "src/include/pmix_types.h" /** * Initialize a progress thread name; if a progress thread is not * already associated with that name, start a progress thread. * * If you have general events that need to run in *a* progress thread * (but not necessarily a your own, dedicated progress thread), pass * NULL the "name" argument to the pmix_progress_thead_init() function * to glom on to the general PMIX-wide progress thread. * * If a name is passed that was already used in a prior call to * pmix_progress_thread_init(), the event base associated with that * already-running progress thread will be returned (i.e., no new * progress thread will be started). */ PMIX_EXPORT pmix_event_base_t *pmix_progress_thread_init(const char *name); PMIX_EXPORT pmix_status_t pmix_progress_thread_start(const char *name); /** * Stop a progress thread name (reference counted). * * Once this function is invoked as many times as * pmix_progress_thread_init() was invoked on this name (or NULL), the * progress function is shut down. * it is destroyed. * * Will return PMIX_ERR_NOT_FOUND if the progress thread name does not * exist; PMIX_SUCCESS otherwise. */ PMIX_EXPORT pmix_status_t pmix_progress_thread_stop(const char *name); /** * Finalize a progress thread name (reference counted). * * Once this function is invoked after pmix_progress_thread_stop() has been called * as many times as pmix_progress_thread_init() was invoked on this name (or NULL), * the event base associated with it is destroyed. * * Will return PMIX_ERR_NOT_FOUND if the progress thread name does not * exist; PMIX_SUCCESS otherwise. */ PMIX_EXPORT pmix_status_t pmix_progress_thread_finalize(const char *name); /** * Temporarily pause the progress thread associated with this name. * * This function does not destroy the event base associated with this * progress thread name, but it does stop processing all events on * that event base until pmix_progress_thread_resume() is invoked on * that name. * * Will return PMIX_ERR_NOT_FOUND if the progress thread name does not * exist; PMIX_SUCCESS otherwise. */ PMIX_EXPORT pmix_status_t pmix_progress_thread_pause(const char *name); /** * Restart a previously-paused progress thread associated with this * name. * * Will return PMIX_ERR_NOT_FOUND if the progress thread name does not * exist; PMIX_SUCCESS otherwise. */ PMIX_EXPORT pmix_status_t pmix_progress_thread_resume(const char *name); #endif pmix-6.1.1~rc2/src/runtime/pmix_progress_threads.c0000664000175000017500000003172515203536752022536 0ustar alastairalastair/* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2017-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_PTHREAD_NP_H # include #endif #include #include #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_stdatomic.h" #include "src/runtime/pmix_progress_threads.h" #include "src/runtime/pmix_rte.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_error.h" #include "src/util/pmix_fd.h" /* create a tracking object for progress threads */ typedef struct { pmix_list_item_t super; int refcount; char *name; pmix_event_base_t *ev_base; /* This will be set to false when it is time for the progress thread to exit */ pmix_atomic_bool_t ev_active; /* This event will always be set on the ev_base (so that the ev_base is not empty!) */ pmix_event_t block; bool engine_constructed; pmix_thread_t engine; } pmix_progress_tracker_t; static void tracker_constructor(pmix_progress_tracker_t *p) { p->refcount = 1; // start at one since someone created it p->name = NULL; p->ev_base = NULL; p->ev_active = false; p->engine_constructed = false; } static void tracker_destructor(pmix_progress_tracker_t *p) { pmix_event_del(&p->block); if (NULL != p->name) { free(p->name); } if (NULL != p->ev_base) { pmix_event_base_free(p->ev_base); } if (p->engine_constructed) { PMIX_DESTRUCT(&p->engine); } } static PMIX_CLASS_INSTANCE(pmix_progress_tracker_t, pmix_list_item_t, tracker_constructor, tracker_destructor); /* LOCAL VARIABLES */ static bool inited = false; static pmix_list_t tracking; static struct timeval long_timeout = {.tv_sec = 3600, .tv_usec = 0}; static const char *shared_thread_name = "PMIX-wide async progress thread"; static pmix_progress_tracker_t *shared_thread_tracker = NULL; /* * If this event is fired, just restart it so that this event base * continues to have something to block on. */ static void dummy_timeout_cb(int sd, short args, void *cbdata) { pmix_progress_tracker_t *trk = (pmix_progress_tracker_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_event_add(&trk->block, &long_timeout); } /* * Main for the progress thread */ static void *progress_engine(pmix_object_t *obj) { pmix_thread_t *t = (pmix_thread_t *) obj; pmix_progress_tracker_t *trk = (pmix_progress_tracker_t *) t->t_arg; while (trk->ev_active) { pmix_event_loop(trk->ev_base, PMIX_EVLOOP_ONCE); } return PMIX_THREAD_CANCELLED; } void PMIx_Progress(void) { if (NULL == shared_thread_tracker) { return; } pmix_event_loop(shared_thread_tracker->ev_base, PMIX_EVLOOP_ONCE); } static void stop_progress_engine(pmix_progress_tracker_t *trk) { if (!trk->ev_active) { return; } if (0 == strcmp(trk->name, shared_thread_name)) { // mark progress thread as stopped to prevent new entries from being // added via PMIx API pmix_atomic_set_bool(&pmix_globals.progress_thread_stopped); } trk->ev_active = false; /* break the event loop - this will cause the loop to exit upon completion of any current event */ pmix_event_base_loopexit(trk->ev_base); pmix_thread_join(&trk->engine, NULL); } static void checkev(int fd, short args, void *cbdata) { pmix_lock_t *lock = (pmix_lock_t*)cbdata; PMIX_HIDE_UNUSED_PARAMS(fd, args); PMIX_WAKEUP_THREAD(lock); } void PMIx_Progress_thread_stop(const pmix_info_t *info, size_t ninfo) { size_t n; bool flush = true; pmix_lock_t lock; pmix_event_t ev; char *key; const char *name = NULL; pmix_progress_tracker_t *trk; for (n=0; n < ninfo; n++) { key = (char*)info[n].key; if (PMIx_Check_key(key, PMIX_PROGRESS_THREAD_FLUSH)) { flush = PMIX_INFO_TRUE(&info[n]); } else if (PMIx_Check_key(key, PMIX_PROGRESS_THREAD_NAME)) { name = info[n].value.data.string; } } if (NULL == name) { name = shared_thread_name; } PMIX_LIST_FOREACH (trk, &tracking, pmix_progress_tracker_t) { if (NULL == name || 0 == strcmp(name, trk->name)) { /* If the progress thread is active, stop it */ if (trk->ev_active) { if (flush) { // put a marker event at the end of the event list PMIX_CONSTRUCT_LOCK(&lock); pmix_event_assign(&ev, trk->ev_base, -1, EV_WRITE, checkev, &lock); PMIX_POST_OBJECT(&lock); pmix_event_active(&ev, EV_WRITE, 1); PMIX_WAIT_THREAD(&lock); PMIX_DESTRUCT_LOCK(&lock); } stop_progress_engine(trk); } } } } static int start_progress_engine(pmix_progress_tracker_t *trk) { #ifdef HAVE_PTHREAD_SETAFFINITY_NP cpu_set_t cpuset; char **ranges, *dash; int k, n, start, end; #endif assert(!trk->ev_active); trk->ev_active = true; /* fork off a thread to progress it */ trk->engine.t_run = progress_engine; trk->engine.t_arg = trk; if (0 == strcmp(trk->name, shared_thread_name)) { // mark progress thread as running to enable PMIx APIs pmix_atomic_unset_bool(&pmix_globals.progress_thread_stopped); } int rc = pmix_thread_start(&trk->engine); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } #ifdef HAVE_PTHREAD_SETAFFINITY_NP if (NULL != pmix_progress_thread_cpus) { CPU_ZERO(&cpuset); // comma-delimited list of cpu ranges ranges = PMIx_Argv_split(pmix_progress_thread_cpus, ','); for (n=0; NULL != ranges[n]; n++) { // look for '-' start = strtoul(ranges[n], &dash, 10); if (NULL == dash) { CPU_SET(start, &cpuset); } else { ++dash; // skip over the '-' end = strtoul(dash, NULL, 10); for (k=start; k < end; k++) { CPU_SET(k, &cpuset); } } } rc = pthread_setaffinity_np(trk->engine.t_handle, sizeof(cpu_set_t), &cpuset); if (0 != rc && pmix_bind_progress_thread_reqd) { pmix_output(0, "Failed to bind progress thread %s", (NULL == trk->name) ? "NULL" : trk->name); rc = PMIX_ERR_NOT_SUPPORTED; } else { rc = PMIX_SUCCESS; } PMIx_Argv_free(ranges); } #endif return rc; } pmix_event_base_t *pmix_progress_thread_init(const char *name) { pmix_progress_tracker_t *trk; if (!inited) { PMIX_CONSTRUCT(&tracking, pmix_list_t); inited = true; } if (NULL == name) { name = shared_thread_name; } /* check if we already have this thread */ PMIX_LIST_FOREACH (trk, &tracking, pmix_progress_tracker_t) { if (0 == strcmp(name, trk->name)) { /* we do, so up the refcount on it */ ++trk->refcount; /* return the existing base */ return trk->ev_base; } } trk = PMIX_NEW(pmix_progress_tracker_t); if (NULL == trk) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return NULL; } trk->name = strdup(name); if (NULL == trk->name) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); PMIX_RELEASE(trk); return NULL; } if (NULL == (trk->ev_base = pmix_event_base_create())) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); PMIX_RELEASE(trk); return NULL; } /* add an event to the new event base (if there are no events, pmix_event_loop() will return immediately) */ pmix_event_assign(&trk->block, trk->ev_base, -1, PMIX_EV_PERSIST, dummy_timeout_cb, trk); pmix_event_add(&trk->block, &long_timeout); /* construct the thread object */ PMIX_CONSTRUCT(&trk->engine, pmix_thread_t); trk->engine_constructed = true; pmix_list_append(&tracking, &trk->super); if (0 == strcmp(name, shared_thread_name)) { shared_thread_tracker = trk; } return trk->ev_base; } pmix_status_t pmix_progress_thread_start(const char *name) { pmix_progress_tracker_t *trk; pmix_status_t rc; if (!inited) { /* nothing we can do */ return PMIX_ERR_NOT_FOUND; } if (NULL == name) { if (pmix_globals.external_progress) { return PMIX_SUCCESS; } name = shared_thread_name; } /* find the specified engine */ PMIX_LIST_FOREACH (trk, &tracking, pmix_progress_tracker_t) { if (0 == strcmp(name, trk->name)) { /* If the progress thread is active, ignore the request */ if (trk->ev_active) { return PMIX_SUCCESS; } if (PMIX_SUCCESS != (rc = start_progress_engine(trk))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(trk); } return rc; } } return PMIX_ERR_NOT_FOUND; } pmix_status_t pmix_progress_thread_stop(const char *name) { pmix_progress_tracker_t *trk; if (!inited) { /* nothing we can do */ return PMIX_ERR_NOT_FOUND; } if (NULL == name) { if (pmix_globals.external_progress) { return PMIX_SUCCESS; } name = shared_thread_name; } /* find the specified engine */ PMIX_LIST_FOREACH (trk, &tracking, pmix_progress_tracker_t) { if (0 == strcmp(name, trk->name)) { /* decrement the refcount */ --trk->refcount; /* If the refcount is still above 0, we're done here */ if (trk->refcount > 0) { return PMIX_SUCCESS; } /* If the progress thread is active, stop it */ if (trk->ev_active) { stop_progress_engine(trk); } pmix_list_remove_item(&tracking, &trk->super); PMIX_RELEASE(trk); return PMIX_SUCCESS; } } return PMIX_ERR_NOT_FOUND; } pmix_status_t pmix_progress_thread_finalize(const char *name) { pmix_progress_tracker_t *trk; if (!inited) { /* nothing we can do */ return PMIX_ERR_NOT_FOUND; } if (NULL == name) { if (pmix_globals.external_progress) { return PMIX_SUCCESS; } name = shared_thread_name; // mark progress thread as stopped pmix_atomic_set_bool(&pmix_globals.progress_thread_stopped); } /* find the specified engine */ PMIX_LIST_FOREACH (trk, &tracking, pmix_progress_tracker_t) { if (0 == strcmp(name, trk->name)) { /* If the refcount is still above 0, we're done here */ if (trk->refcount > 0) { return PMIX_SUCCESS; } pmix_list_remove_item(&tracking, &trk->super); PMIX_RELEASE(trk); return PMIX_SUCCESS; } } return PMIX_ERR_NOT_FOUND; } /* * Stop the progress thread, but don't delete the tracker (or event base) */ pmix_status_t pmix_progress_thread_pause(const char *name) { pmix_progress_tracker_t *trk; if (!inited) { /* nothing we can do */ return PMIX_ERR_NOT_FOUND; } if (NULL == name) { if (pmix_globals.external_progress) { return PMIX_SUCCESS; } name = shared_thread_name; } /* find the specified engine */ PMIX_LIST_FOREACH (trk, &tracking, pmix_progress_tracker_t) { if (0 == strcmp(name, trk->name)) { if (trk->ev_active) { stop_progress_engine(trk); } return PMIX_SUCCESS; } } return PMIX_ERR_NOT_FOUND; } pmix_status_t pmix_progress_thread_resume(const char *name) { pmix_progress_tracker_t *trk; if (!inited) { /* nothing we can do */ return PMIX_ERR_NOT_FOUND; } if (NULL == name) { if (pmix_globals.external_progress) { return PMIX_SUCCESS; } name = shared_thread_name; } /* find the specified engine */ PMIX_LIST_FOREACH (trk, &tracking, pmix_progress_tracker_t) { if (0 == strcmp(name, trk->name)) { if (trk->ev_active) { return PMIX_ERR_RESOURCE_BUSY; } return start_progress_engine(trk); } } return PMIX_ERR_NOT_FOUND; } pmix-6.1.1~rc2/src/runtime/pmix_init_util.h0000664000175000017500000000301615203536752021155 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2010-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file **/ #ifndef PMIX_INIT_UTIL_H #define PMIX_INIT_UTIL_H #include "src/include/pmix_config.h" #include "pmix_common.h" BEGIN_C_DECLS PMIX_EXPORT extern const char* pmix_tool_basename; PMIX_EXPORT extern const char* pmix_tool_version; PMIX_EXPORT extern const char* pmix_tool_org; PMIX_EXPORT extern const char* pmix_tool_msg; PMIX_EXPORT int pmix_init_util(pmix_info_t info[], size_t ninfo, char *helpdir); PMIX_EXPORT int pmix_finalize_util(void); PMIX_EXPORT void pmix_expose_param(char *param); END_C_DECLS #endif /* PMIX_INIT_UTIL_H */ pmix-6.1.1~rc2/src/runtime/pmix_init.c0000664000175000017500000005267415203536752020131 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2009 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2010-2015 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022-2026 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file **/ #include "src/include/pmix_config.h" #ifdef HAVE_UNISTD_H # include #endif #include "src/include/pmix_globals.h" #include "src/include/pmix_dictionary.h" #include "src/include/pmix_types.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/mca/pcompress/base/base.h" #include "src/mca/pif/base/base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/mca/plog/base/base.h" #include "src/mca/pnet/base/base.h" #include "src/mca/preg/base/base.h" #include "src/mca/psec/base/base.h" #include "src/mca/ptl/base/base.h" #include "src/util/pmix_error.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_net.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "src/client/pmix_client_ops.h" #include "src/common/pmix_attributes.h" #include "src/event/pmix_event.h" #include "src/runtime/pmix_progress_threads.h" #include "src/runtime/pmix_rte.h" #include "src/runtime/pmix_init_util.h" const char pmix_version_string[] = PMIX_IDENT_STRING; const char* pmix_tool_basename = NULL; const char* pmix_tool_version = PMIX_VERSION; const char* pmix_tool_org = "PMIx"; const char* pmix_tool_msg = PMIX_PROXY_BUGREPORT_STRING; PMIX_EXPORT bool pmix_init_called = false; /* we have to export the pmix_globals object so * all plugins can access it. */ PMIX_EXPORT pmix_globals_t pmix_globals = { .init_called = false, .initialized = false, .util_initialized = false, .connected = false, .progress_thread_stopped = false, .myid = PMIX_PROC_STATIC_INIT, .myidval = PMIX_VALUE_STATIC_INIT, .myrankval = PMIX_VALUE_STATIC_INIT, .mypeer = NULL, .realuid = 0, .uid = 0, .realgid = 0, .gid = 0, .hostname = NULL, .aliases = NULL, .appnum = 0, .pid = 0, .nodeid = UINT32_MAX, .sessionid = UINT32_MAX, .pindex = 0, .evbase = NULL, .evauxbase = NULL, .debug_output = -1, .events = PMIX_EVENTS_STATIC_INIT, .commits_pending = false, .event_window = {0, 0}, .cached_events = PMIX_LIST_STATIC_INIT, .iof_requests = PMIX_POINTER_ARRAY_STATIC_INIT, .max_events = INT_MAX, .event_eviction_time = 0, .notifications = PMIX_HOTEL_STATIC_INIT, .pushstdin = false, .stdin_targets = PMIX_LIST_STATIC_INIT, .tag_output = false, .xml_output = false, .timestamp_output = false, .output_limit = SIZE_MAX, .nspaces = PMIX_LIST_STATIC_INIT, .topology = {NULL, NULL}, .cpuset = {NULL, NULL}, .external_topology = false, .external_progress = false, .iof_flags = PMIX_IOF_FLAGS_STATIC_INIT, .keyindex = PMIX_KEYINDEX_STATIC_INIT }; static void _notification_eviction_cbfunc(struct pmix_hotel_t *hotel, int room_num, void *occupant) { pmix_notify_caddy_t *cache = (pmix_notify_caddy_t *) occupant; PMIX_HIDE_UNUSED_PARAMS(hotel, room_num); PMIX_RELEASE(cache); } void pmix_expose_param(char *param) { char *value, *pm; value = strchr(param, '='); if (NULL == value) { // should never happen return; } *value = '\0'; ++value; pmix_asprintf(&pm, "PMIX_MCA_%s", param); setenv(pm, value, true); free(pm); --value; *value = '='; } int pmix_init_util(pmix_info_t info[], size_t ninfo, char *libdir) { pmix_status_t ret; if (pmix_atomic_check_bool(&pmix_globals.util_initialized)) { return PMIX_SUCCESS; } /* initialize the output system */ if (!pmix_output_init()) { return PMIX_ERROR; } /* initialize install dirs code */ ret = pmix_mca_base_framework_open(&pmix_pinstalldirs_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != ret) { fprintf(stderr, "pmix_pinstalldirs_base_open() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, ret); return ret; } if (PMIX_SUCCESS != (ret = pmix_pinstall_dirs_base_init(info, ninfo))) { fprintf(stderr, "pmix_pinstalldirs_base_init() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, ret); return ret; } /* initialize the help system */ pmix_show_help_init(); /* keyval lex-based parser */ if (PMIX_SUCCESS != (ret = pmix_util_keyval_parse_init())) { fprintf(stderr, "pmix_util_keyval_parse_init failed\n"); return ret; } /* Setup the parameter system */ if (PMIX_SUCCESS != (ret = pmix_mca_base_var_init())) { fprintf(stderr, "mca_base_var_init failed\n"); return ret; } /* initialize the mca */ if (PMIX_SUCCESS != (ret = pmix_mca_base_open(libdir))) { fprintf(stderr, "pmix_mca_base_open failed\n"); return ret; } if (PMIX_SUCCESS != (ret = pmix_net_init())) { fprintf(stderr, "pmix_net_init failed\n"); return ret; } /* initialize pif framework */ ret = pmix_mca_base_framework_open(&pmix_pif_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != ret) { fprintf(stderr, "pmix_pif_base_open failed\n"); return ret; } pmix_atomic_set_bool(&pmix_globals.util_initialized); return PMIX_SUCCESS; } int pmix_rte_init(uint32_t type, pmix_info_t info[], size_t ninfo, pmix_ptl_cbfunc_t cbfunc) { int ret, debug_level; char *error = NULL, *evar; size_t n, m; char hostname[PMIX_MAXHOSTNAMELEN] = {0}; pmix_info_t *iptr; size_t minfo; pmix_iof_flags_t flags; #if PMIX_NO_LIB_DESTRUCTOR if (pmix_init_called) { /* can't use pmix_show_help.here */ fprintf( stderr, "pmix_init: attempted to initialize after finalize without compiler " "support for either __attribute__(destructor) or linker support for -fini -- process " "will likely abort\n"); return PMIX_ERR_NOT_SUPPORTED; } #endif pmix_init_called = true; memset(&flags, 0, sizeof(pmix_iof_flags_t)); if (PMIX_SUCCESS != pmix_init_util(info, ninfo, NULL)) { return PMIX_ERROR; } /* register params for pmix */ if (PMIX_SUCCESS != (ret = pmix_register_params())) { fprintf(stderr, "pmix_register_params failed\n"); return ret; } /* scan incoming info for directives */ if (NULL != info) { for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_HOSTNAME)) { if (NULL != pmix_globals.hostname) { free(pmix_globals.hostname); } pmix_globals.hostname = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_NODEID)) { ret = PMIx_Value_get_number(&info[n].value, &pmix_globals.nodeid, PMIX_UINT32); if (PMIX_SUCCESS != ret) { goto return_error; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_NODE_INFO_ARRAY)) { /* contains info about our node */ iptr = (pmix_info_t *) info[n].value.data.darray->array; minfo = info[n].value.data.darray->size; for (m = 0; m < minfo; m++) { if (PMIX_CHECK_KEY(&iptr[m], PMIX_HOSTNAME)) { if (NULL != pmix_globals.hostname) { free(pmix_globals.hostname); } pmix_globals.hostname = strdup(iptr[m].value.data.string); } else if (PMIX_CHECK_KEY(&iptr[m], PMIX_NODEID)) { ret = PMIx_Value_get_number(&iptr[m].value, &pmix_globals.nodeid, PMIX_UINT32); if (PMIX_SUCCESS != ret) { goto return_error; } } } } else if (PMIX_CHECK_KEY(&info[n], PMIX_EXTERNAL_PROGRESS)) { pmix_globals.external_progress = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_EXTERNAL_AUX_EVENT_BASE)) { pmix_globals.evauxbase = (pmix_event_base_t*)info[n].value.data.ptr; } else if (PMIX_CHECK_KEY(&info[n], PMIX_HOSTNAME_KEEP_FQDN)) { pmix_keep_fqdn_hostnames = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_BIND_PROGRESS_THREAD)) { if (NULL != pmix_progress_thread_cpus) { free(pmix_progress_thread_cpus); } pmix_progress_thread_cpus = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_BIND_REQUIRED)) { pmix_bind_progress_thread_reqd = PMIX_INFO_TRUE(&info[n]); } else { pmix_iof_check_flags(&info[n], &flags); } } } /* tell libevent that we need thread support */ pmix_event_use_threads(); /* create an event base and progress thread for us */ if (NULL == (pmix_globals.evbase = pmix_progress_thread_init(NULL))) { error = "progress thread"; ret = PMIX_ERROR; goto return_error; } /* if we were not given an aux event base, set it to our internal one */ if (NULL == pmix_globals.evauxbase) { pmix_globals.evauxbase = pmix_globals.evbase; } /* setup the globals structure */ pmix_globals.pid = getpid(); PMIX_LOAD_PROCID(&pmix_globals.myid, NULL, PMIX_RANK_INVALID); pmix_globals.myidval.type = PMIX_PROC; pmix_globals.myidval.data.proc = (pmix_proc_t *) malloc(sizeof(pmix_proc_t)); PMIX_LOAD_PROCID(pmix_globals.myidval.data.proc, NULL, PMIX_RANK_INVALID); pmix_globals.myrankval.type = PMIX_PROC_RANK; pmix_globals.myrankval.data.rank = PMIX_RANK_INVALID; PMIX_CONSTRUCT(&pmix_globals.events, pmix_events_t); pmix_globals.event_window.tv_sec = pmix_event_caching_window; pmix_globals.event_window.tv_usec = 0; PMIX_CONSTRUCT(&pmix_globals.cached_events, pmix_list_t); /* construct the global notification ring buffer */ PMIX_CONSTRUCT(&pmix_globals.notifications, pmix_hotel_t); ret = pmix_hotel_init(&pmix_globals.notifications, pmix_globals.max_events, pmix_globals.evbase, pmix_globals.event_eviction_time, _notification_eviction_cbfunc); PMIX_CONSTRUCT(&pmix_globals.nspaces, pmix_list_t); PMIX_CONSTRUCT(&pmix_globals.keyindex, pmix_keyindex_t); PMIX_CONSTRUCT(&pmix_client_globals.groups, pmix_list_t); /* need to hold off checking the hotel init return code * until after we construct all the globals so they can * correctly finalize */ if (PMIX_SUCCESS != ret) { error = "notification hotel init"; goto return_error; } /* and setup the iof request tracking list */ PMIX_CONSTRUCT(&pmix_globals.iof_requests, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_globals.iof_requests, 128, INT_MAX, 128); /* setup the stdin forwarding target list */ PMIX_CONSTRUCT(&pmix_globals.stdin_targets, pmix_list_t); memcpy(&pmix_globals.iof_flags, &flags, sizeof(pmix_iof_flags_t)); /* Setup client verbosities as all procs are allowed to * access client APIs */ if (0 < pmix_client_globals.get_verbose) { /* set default output */ pmix_client_globals.get_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_client_globals.get_output, pmix_client_globals.get_verbose); } if (0 < pmix_client_globals.connect_verbose) { /* set default output */ pmix_client_globals.connect_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_client_globals.connect_output, pmix_client_globals.connect_verbose); } if (0 < pmix_client_globals.fence_verbose) { /* set default output */ pmix_client_globals.fence_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_client_globals.fence_output, pmix_client_globals.fence_verbose); } if (0 < pmix_client_globals.pub_verbose) { /* set default output */ pmix_client_globals.pub_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_client_globals.pub_output, pmix_client_globals.pub_verbose); } if (0 < pmix_client_globals.spawn_verbose) { /* set default output */ pmix_client_globals.spawn_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_client_globals.spawn_output, pmix_client_globals.spawn_verbose); } if (0 < pmix_client_globals.event_verbose) { /* set default output */ pmix_client_globals.event_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_client_globals.event_output, pmix_client_globals.event_verbose); } if (0 < pmix_client_globals.iof_verbose) { /* set default output */ pmix_client_globals.iof_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_client_globals.iof_output, pmix_client_globals.iof_verbose); } if (0 < pmix_client_globals.group_verbose) { /* set default output */ pmix_client_globals.group_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_client_globals.group_output, pmix_client_globals.group_verbose); } /* get our real id's */ pmix_globals.realuid = getuid(); pmix_globals.realgid = getgid(); /* get our effective id's */ pmix_globals.uid = geteuid(); pmix_globals.gid = getegid(); /* see if debug is requested */ if (NULL != (evar = getenv("PMIX_DEBUG"))) { debug_level = strtol(evar, NULL, 10); pmix_globals.debug_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_globals.debug_output, debug_level); } /* create our peer object */ pmix_globals.mypeer = PMIX_NEW(pmix_peer_t); if (NULL == pmix_globals.mypeer) { ret = PMIX_ERR_NOMEM; goto return_error; } /* whatever our declared proc type, set our version */ PMIX_SET_PEER_TYPE(pmix_globals.mypeer, type); PMIX_SET_PEER_MAJOR(pmix_globals.mypeer, PMIX_VERSION_MAJOR); PMIX_SET_PEER_MINOR(pmix_globals.mypeer, PMIX_VERSION_MINOR); PMIX_SET_PEER_RELEASE(pmix_globals.mypeer, PMIX_VERSION_RELEASE); /* create an nspace object for ourselves - we will * fill in the nspace name later */ pmix_globals.mypeer->nptr = PMIX_NEW(pmix_namespace_t); if (NULL == pmix_globals.mypeer->nptr) { PMIX_RELEASE(pmix_globals.mypeer); ret = PMIX_ERR_NOMEM; goto return_error; } /* the passed-in hostname trumps all, so don't overwrite it * if we were given one */ if (NULL == pmix_globals.hostname) { /* if we were given a hostname in our environment, use it */ if (NULL != (evar = getenv("PMIX_HOSTNAME"))) { pmix_globals.hostname = strdup(evar); } else { /* if we weren't previously given a hostname, then * use the OS one */ gethostname(hostname, PMIX_MAXHOSTNAMELEN - 1); pmix_globals.hostname = strdup(hostname); } pmix_set_aliases(&pmix_globals.aliases, pmix_globals.hostname); } /* open the bfrops and select the active plugins */ ret = pmix_mca_base_framework_open(&pmix_bfrops_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != ret) { error = "pmix_bfrops_base_open"; goto return_error; } if (PMIX_SUCCESS != (ret = pmix_bfrop_base_select())) { error = "pmix_bfrops_base_select"; goto return_error; } /* open and select the compress framework */ ret = pmix_mca_base_framework_open(&pmix_pcompress_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != ret) { error = "pmix_pcompress_base_open"; goto return_error; } if (PMIX_SUCCESS != (ret = pmix_compress_base_select())) { error = "pmix_pcompress_base_select"; goto return_error; } /* open the ptl and select the active plugins */ ret = pmix_mca_base_framework_open(&pmix_ptl_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != ret) { error = "pmix_ptl_base_open"; goto return_error; } if (PMIX_SUCCESS != (ret = pmix_ptl_base_select())) { error = "pmix_ptl_base_select"; goto return_error; } /* set the notification callback function */ if (PMIX_SUCCESS != (ret = pmix_ptl_base_set_notification_cbfunc(cbfunc))) { error = "pmix_ptl_set_notification_cbfunc"; goto return_error; } /* open the psec and select the active plugins */ if (NULL != (evar = getenv("PMIX_SECURITY_MODE"))) { /* convert to an MCA param, but don't overwrite something already there */ PMIx_Setenv("PMIX_MCA_psec", evar, false, &environ); } ret = pmix_mca_base_framework_open(&pmix_psec_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != ret) { error = "pmix_psec_base_open"; goto return_error; } if (PMIX_SUCCESS != (ret = pmix_psec_base_select())) { error = "pmix_psec_base_select"; goto return_error; } /* open the gds and select the active plugins */ ret = pmix_mca_base_framework_open(&pmix_gds_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != ret) { error = "pmix_gds_base_open"; goto return_error; } if (PMIX_SUCCESS != (ret = pmix_gds_base_select(info, ninfo))) { error = "pmix_gds_base_select"; goto return_error; } /* open the preg and select the active plugins - must come after pcompress! */ ret = pmix_mca_base_framework_open(&pmix_preg_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != ret) { error = "pmix_preg_base_open"; goto return_error; } if (PMIX_SUCCESS != (ret = pmix_preg_base_select())) { error = "pmix_preg_base_select"; goto return_error; } /* open the plog and select the active plugins */ ret = pmix_mca_base_framework_open(&pmix_plog_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != ret) { error = "pmix_plog_base_open"; goto return_error; } if (PMIX_SUCCESS != (ret = pmix_plog_base_select())) { error = "pmix_plog_base_select"; goto return_error; } /* initialize the attribute support system */ pmix_init_registered_attrs(); /* start progressing the event library */ if (PMIX_SUCCESS != (ret = pmix_progress_thread_start(NULL))) { error = "pmix_progress_thread_start"; goto return_error; } return PMIX_SUCCESS; return_error: if (PMIX_ERR_SILENT != ret) { pmix_show_help("help-pmix-runtime.txt", "pmix_init:startup:internal-failure", true, error, ret); } if (NULL != flags.file) { free(flags.file); } if (NULL != flags.directory) { free(flags.directory); } return ret; } int pmix_finalize_util(void) { pmix_atomic_unset_bool(&pmix_globals.util_initialized); return PMIX_SUCCESS; } void pmix_set_aliases(char ***aliases, char *hostname) { char *ptr; if (!pmix_net_isaddr(hostname) && NULL != (ptr = strchr(hostname, '.'))) { if (pmix_keep_fqdn_hostnames) { /* retain the non-fqdn name as an alias */ *ptr = '\0'; PMIx_Argv_append_unique_nosize(aliases, hostname); *ptr = '.'; } else { /* add the fqdn name as an alias */ PMIx_Argv_append_unique_nosize(aliases, hostname); /* retain the non-fqdn name as the node's name */ *ptr = '\0'; } } } pmix-6.1.1~rc2/src/runtime/Makefile.include0000664000175000017500000000444115203536752021034 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, LLC. # All rights reserved. # Copyright (c) 2014-2017 Intel, Inc. All rights reserved. # Copyright (c) 2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from src/Makefile.am EXTRA_DIST += runtime/help-pmix-runtime.txt AM_CFLAGS = \ -DPMIX_CONFIGURE_USER="\"@PMIX_CONFIGURE_USER@\"" \ -DPMIX_CONFIGURE_HOST="\"@PMIX_CONFIGURE_HOST@\"" \ -DPMIX_CONFIGURE_DATE="\"@PMIX_CONFIGURE_DATE@\"" \ -DPMIX_BUILD_USER="\"$$USER\"" \ -DPMIX_BUILD_HOST="\"$${HOSTNAME:-`(hostname || uname -n) | sed 1q`}\"" \ -DPMIX_BUILD_DATE="\"`$(top_srcdir)/config/getdate.sh`\"" \ -DPMIX_BUILD_CFLAGS="\"@CFLAGS@\"" \ -DPMIX_BUILD_CPPFLAGS="\"@CPPFLAGS@\"" \ -DPMIX_BUILD_LDFLAGS="\"@LDFLAGS@\"" \ -DPMIX_BUILD_LIBS="\"@LIBS@\"" \ -DPMIX_CC_ABSOLUTE="\"@PMIX_CC_ABSOLUTE@\"" \ -DPMIX_GREEK_VERSION="\"@PMIX_GREEK_VERSION@\"" \ -DPMIX_REPO_REV="\"@PMIX_REPO_REV@\"" \ -DPMIX_RELEASE_DATE="\"@PMIX_RELEASE_DATE@\"" headers += \ runtime/pmix_rte.h \ runtime/pmix_progress_threads.h \ runtime/pmix_init_util.h \ runtime/pmix_info_support.h sources += \ runtime/pmix_finalize.c \ runtime/pmix_init.c \ runtime/pmix_params.c \ runtime/pmix_progress_threads.c \ runtime/pmix_info_support.c pmix-6.1.1~rc2/src/runtime/pmix_info_support.h0000664000175000017500000001333215203536752021706 0ustar alastairalastair/* * Copyright (c) 2012-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2017 IBM Corporation. All rights reserved. * Copyright (c) 2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file **/ #ifndef PMIX_INFO_REGISTER_H #define PMIX_INFO_REGISTER_H #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/class/pmix_pointer_array.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pinstalldirs/pinstalldirs_types.h" #include "src/util/pmix_cmd_line.h" BEGIN_C_DECLS PMIX_EXPORT extern const char *pmix_info_path_prefix; PMIX_EXPORT extern const char *pmix_info_type_all; PMIX_EXPORT extern const char *pmix_info_type_pmix; PMIX_EXPORT extern const char *pmix_info_component_all; extern const char *pmix_info_param_all; PMIX_EXPORT extern const char *pmix_info_ver_full; extern const char *pmix_info_ver_major; extern const char *pmix_info_ver_minor; extern const char *pmix_info_ver_release; extern const char *pmix_info_ver_greek; extern const char *pmix_info_ver_repo; PMIX_EXPORT extern const char *pmix_info_ver_all; extern const char *pmix_info_ver_mca; extern const char *pmix_info_ver_type; extern const char *pmix_info_ver_component; PMIX_EXPORT extern bool pmix_info_color; PMIX_EXPORT extern bool pmix_info_pretty; PMIX_EXPORT extern pmix_mca_base_register_flag_t pmix_info_register_flags; /* * Component-related functions */ typedef struct { pmix_list_item_t super; char *project; char *type; pmix_list_t *components; pmix_list_t *failed_components; } pmix_info_component_map_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_info_component_map_t); PMIX_EXPORT int pmix_info_init(int argc, char **argv, pmix_cli_result_t *pmix_info_cmd_line, struct option poptions[], char *pshorts, char *helpfile); PMIX_EXPORT void pmix_info_finalize(void); PMIX_EXPORT void pmix_info_register_types(pmix_pointer_array_t *mca_types, bool frames_only); PMIX_EXPORT int pmix_info_register_framework_params(pmix_pointer_array_t *component_map); PMIX_EXPORT void pmix_info_close_components(void); PMIX_EXPORT void pmix_info_err_params(pmix_pointer_array_t *component_map); PMIX_EXPORT void pmix_info_show_package(char *pkgstring); PMIX_EXPORT void pmix_info_show_pmix_package(void); PMIX_EXPORT void pmix_info_do_pmix_config(bool want_all); PMIX_EXPORT void pmix_info_do_config(bool want_all, char *user, char *date, char *host, char *cli, char *builduser, char *builddate, char *buildhost, char *ccline, char *ccabs, char *family, char *versionstr, char *cflags, char *ldflags, char *libs, bool enabledebug, bool havedl, bool havevi); PMIX_EXPORT void pmix_info_do_params(const char *project, bool want_all_in, bool want_internal, pmix_pointer_array_t *mca_type, pmix_pointer_array_t *component_map, pmix_cli_result_t *pmix_info_cmd_line); PMIX_EXPORT void pmix_info_show_path(const char *type, const char *value); PMIX_EXPORT void pmix_info_show_pmix_path(void); PMIX_EXPORT void pmix_info_do_path(bool want_all, pmix_cli_result_t *cmd_line, pmix_pinstall_dirs_t *dirs); PMIX_EXPORT void pmix_info_do_pmix_path(bool wall, pmix_cli_result_t *cmd_line); PMIX_EXPORT void pmix_info_show_mca_params(const char *type, const char *component, bool want_internal); PMIX_EXPORT void pmix_info_show_mca_version(const pmix_mca_base_component_t *component, const char *scope, const char *ver_type); PMIX_EXPORT void pmix_info_show_component_version(const char *project, pmix_pointer_array_t *mca_types, pmix_pointer_array_t *component_map, const char *type_name, const char *component_name, const char *scope, const char *ver_type); PMIX_EXPORT char *pmix_info_make_version_str(const char *scope, int major, int minor, int release, const char *greek, const char *repo); PMIX_EXPORT void pmix_info_show_version(const char *project, const char *scope, int major, int minor, int release, const char *greek, const char *repo, const char *rdate); PMIX_EXPORT void pmix_info_show_pmix_version(void); PMIX_EXPORT void pmix_info_do_arch(void); PMIX_EXPORT void pmix_info_do_hostname(void); PMIX_EXPORT void pmix_info_do_type(pmix_cli_result_t *pmix_info_cmd_line); PMIX_EXPORT void pmix_info_out(const char *pretty_message, const char *plain_message, const char *value); PMIX_EXPORT void pmix_info_out_int(const char *pretty_message, const char *plain_message, int value); PMIX_EXPORT int pmix_info_register_project_frameworks(const char *project_name, pmix_mca_base_framework_t **frameworks, pmix_pointer_array_t *component_map); END_C_DECLS #endif pmix-6.1.1~rc2/src/server/0000775000175000017500000000000015203536752015572 5ustar alastairalastairpmix-6.1.1~rc2/src/server/pmix_server_resolve.c0000664000175000017500000004362615203536752022053 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2020 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_TIME_H # include #endif #include #ifndef MAX # define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #include "src/class/pmix_hotel.h" #include "src/class/pmix_list.h" #include "src/common/pmix_attributes.h" #include "src/common/pmix_iof.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/mca/plog/plog.h" #include "src/mca/pnet/pnet.h" #include "src/mca/psensor/psensor.h" #include "src/mca/ptl/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/client/pmix_client_ops.h" #include "src/server/pmix_server_ops.h" pmix_status_t pmix_server_resolve_peers(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc) { int32_t cnt; pmix_status_t rc; char *nodename = NULL; char *nd, *str; pmix_info_t *iptr; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* unpack the nodename */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &nodename, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } // if the nodename is NULL, then they are asking for our // local host if (NULL == nodename) { nd = pmix_globals.hostname; } else { nd = nodename; } /* unpack the nspace */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &str, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); if (NULL != nodename) { free(nodename); } return rc; } PMIX_QUERY_CREATE(cd->query, 1); PMIX_ARGV_APPEND(rc, cd->query->keys, PMIX_QUERY_RESOLVE_PEERS); PMIX_INFO_CREATE(iptr, 2); PMIX_INFO_LOAD(&iptr[0], PMIX_NSPACE, str, PMIX_STRING); if (NULL != str) { free(str); } PMIX_INFO_SET_QUALIFIER(&iptr[0]); PMIX_INFO_LOAD(&iptr[1], PMIX_HOSTNAME, nd, PMIX_STRING); if (NULL != nodename) { free(nodename); } PMIX_INFO_SET_QUALIFIER(&iptr[1]); cd->query->qualifiers = iptr; cd->query->nqual = 2; // if the host supports the "query" interface, then // pass this up to the host for processing as it has // the latest information if (NULL != pmix_host_server.query) { rc = pmix_host_server.query(&pmix_globals.myid, cd->query, 1, cbfunc, (void*)cd); if (PMIX_SUCCESS == rc) { return PMIX_SUCCESS; } } // they either don't support this query, or have // nothing to contribute - so use what we know PMIX_THREADSHIFT(cd, pmix_server_locally_resolve_peers); // indicate that the switchyard is not to send a response return PMIX_SUCCESS; } void pmix_server_locally_resolve_peers(int sd, short args, void *cbdata) { pmix_server_caddy_t *cd = (pmix_server_caddy_t*)cbdata; pmix_cb_t cb; pmix_status_t rc, ret=PMIX_SUCCESS; pmix_info_t info[3]; pmix_proc_t proc; pmix_kval_t *kv; char **p, **tmp = NULL, *prs; char *nspace, *nd; pmix_proc_t *pa = NULL; size_t m, n, np = 0, ninfo = 3; pmix_namespace_t *ns; pmix_buffer_t *reply; PMIX_HIDE_UNUSED_PARAMS(sd, args); // construct these so we don't have to worry about // destruct later for (n=0; n < ninfo; n++) { PMIX_INFO_CONSTRUCT(&info[n]); } // first qualifier in the query has the nspace in it nspace = cd->query->qualifiers[0].value.data.string; // second qualifier in the query has the nodename nd = cd->query->qualifiers[1].value.data.string; PMIX_CONSTRUCT(&cb, pmix_cb_t); proc.rank = PMIX_RANK_UNDEF; cb.proc = &proc; cb.key = PMIX_LOCAL_PEERS; cb.scope = PMIX_INTERNAL; cb.info = info; cb.ninfo = ninfo; // restrict our search to already available info - do // not allow the search to call the host. This // avoids a threadlock situation PMIX_INFO_LOAD(&info[0], PMIX_OPTIONAL, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[1], PMIX_NODE_INFO, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[2], PMIX_HOSTNAME, nd, PMIX_STRING); if (0 == pmix_nslen(nspace)) { // asking for a complete list of peers rc = PMIX_ERR_DATA_VALUE_NOT_FOUND; np = 0; /* cycle across all known nspaces and aggregate the results */ PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { PMIX_LOAD_NSPACE(proc.nspace, ns->nspace); PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS != rc) { if (PMIX_RANK_UNDEF == proc.rank) { // try again with wildcard proc.rank = PMIX_RANK_WILDCARD; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS != rc) { continue; } } else { continue; } } /* sanity check */ if (0 == pmix_list_get_size(&cb.kvs)) { continue; } kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs); if (PMIX_STRING != kv->value->type) { PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL); PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); continue; } if (NULL == kv->value->data.string) { /* no local peers on this node */ PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); continue; } /* prepend the nspace */ if (0 > asprintf(&prs, "%s:%s", ns->nspace, kv->value->data.string)) { PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); continue; } /* add to our list of results */ PMIx_Argv_append_nosize(&tmp, prs); /* split to count the npeers */ p = PMIx_Argv_split(kv->value->data.string, ','); np += PMIx_Argv_count(p); /* done with this entry */ PMIx_Argv_free(p); free(prs); // clean up and cycle around to next namespace PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); } if (0 < np) { /* allocate the proc array */ PMIX_PROC_CREATE(pa, np); if (NULL == pa) { ret = PMIX_ERR_NOMEM; PMIx_Argv_free(tmp); np = 0; PMIX_DESTRUCT(&cb); goto done; } /* transfer the results */ np = 0; for (n = 0; NULL != tmp[n]; n++) { /* find the nspace delimiter */ prs = strchr(tmp[n], ':'); if (NULL == prs) { /* should never happen, but silence a Coverity warning */ ret = PMIX_ERR_BAD_PARAM; PMIx_Argv_free(tmp); PMIX_PROC_FREE(pa, np); pa = NULL; np = 0; PMIX_DESTRUCT(&cb); goto done; } *prs = '\0'; ++prs; p = PMIx_Argv_split(prs, ','); for (m = 0; NULL != p[m]; m++) { PMIX_LOAD_NSPACE(pa[np].nspace, tmp[n]); pa[np].rank = strtoul(p[m], NULL, 10); ++np; } PMIx_Argv_free(p); } PMIx_Argv_free(tmp); ret = PMIX_SUCCESS; } PMIX_DESTRUCT(&cb); goto done; } /* get the list of local peers for this nspace and node */ PMIX_LOAD_PROCID(&proc, nspace, PMIX_RANK_UNDEF); PMIX_GDS_FETCH_KV(ret, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS == ret) { goto process; } if (PMIX_ERR_INVALID_NAMESPACE == ret) { // this namespace is unknown PMIX_DESTRUCT(&cb); goto done; } if (PMIX_ERR_NOT_FOUND == ret) { // found the namespace, but the node is // not present on that namespace - the // default response is correct ret = PMIX_SUCCESS; PMIX_DESTRUCT(&cb); goto done; } if (PMIX_ERR_DATA_VALUE_NOT_FOUND == ret) { // found the namespace and node, but the // host did not provide the information PMIX_DESTRUCT(&cb); goto done; } // get here if we see a different error if (PMIX_RANK_UNDEF == proc.rank) { // try again with wildcard proc.rank = PMIX_RANK_WILDCARD; PMIX_GDS_FETCH_KV(ret, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS == ret) { goto process; } if (PMIX_ERR_NOT_FOUND == ret) { // found the namespace, but the node is // not present on that namespace - the // default response is correct ret = PMIX_SUCCESS; } // couldn't find it PMIX_DESTRUCT(&cb); goto done; } process: /* sanity check */ if (0 == pmix_list_get_size(&cb.kvs)) { ret = PMIX_ERR_INVALID_VAL; PMIX_DESTRUCT(&cb); goto done; } kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs); if (PMIX_STRING != kv->value->type || NULL == kv->value->data.string) { ret = PMIX_ERR_INVALID_VAL; PMIX_DESTRUCT(&cb); goto done; } /* split the procs to get a list */ p = PMIx_Argv_split(kv->value->data.string, ','); np = PMIx_Argv_count(p); /* allocate the proc array */ PMIX_PROC_CREATE(pa, np); if (NULL == pa) { ret = PMIX_ERR_NOMEM; PMIx_Argv_free(p); PMIX_DESTRUCT(&cb); goto done; } /* transfer the results */ for (n = 0; n < np; n++) { PMIX_LOAD_NSPACE(pa[n].nspace, nspace); pa[n].rank = strtoul(p[n], NULL, 10); } PMIx_Argv_free(p); ret = PMIX_SUCCESS; PMIX_DESTRUCT(&cb); done: for (n=0; n < ninfo; n++) { PMIX_INFO_DESTRUCT(&info[n]); } reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); PMIX_RELEASE(cd); return; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &ret, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS == ret) { PMIX_BFROPS_PACK(rc, cd->peer, reply, &np, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < np) { PMIX_BFROPS_PACK(rc, cd->peer, reply, pa, np, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } PMIX_RELEASE(cd); if (NULL != pa) { PMIX_PROC_FREE(pa, np); } } pmix_status_t pmix_server_resolve_node(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc) { int32_t cnt; pmix_status_t rc; pmix_info_t *iptr; char *str; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* unpack the nspace */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &str, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_QUERY_CREATE(cd->query, 1); PMIX_ARGV_APPEND(rc, cd->query->keys, PMIX_QUERY_RESOLVE_NODE); PMIX_INFO_CREATE(iptr, 1); PMIX_INFO_LOAD(&iptr[0], PMIX_NSPACE, str, PMIX_STRING); if (NULL != str) { free(str); } PMIX_INFO_SET_QUALIFIER(&iptr[0]); cd->query->qualifiers = iptr; cd->query->nqual = 1; // if the host supports the "query" interface, then // pass this up to the host for processing as it has // the latest information if (NULL != pmix_host_server.query) { rc = pmix_host_server.query(&pmix_globals.myid, cd->query, 1, cbfunc, (void*)cd); if (PMIX_SUCCESS == rc) { return PMIX_SUCCESS; } } // they either don't support this query, or have // nothing to contribute - so use what we know PMIX_THREADSHIFT(cd, pmix_server_locally_resolve_node); // indicate that the switchyard is not to send a response return PMIX_SUCCESS; } void pmix_server_locally_resolve_node(int sd, short args, void *cbdata) { pmix_server_caddy_t *cd = (pmix_server_caddy_t*)cbdata; pmix_cb_t cb; pmix_status_t rc, ret = PMIX_SUCCESS; pmix_nspace_t nspace; pmix_info_t info; pmix_proc_t proc; pmix_kval_t *kv; pmix_value_t *val; char **p, **tmp = NULL, *nodelist = NULL; pmix_namespace_t *ns; size_t n; pmix_buffer_t *reply; PMIX_HIDE_UNUSED_PARAMS(sd, args); // restrict our search to already available info PMIX_INFO_LOAD(&info, PMIX_OPTIONAL, NULL, PMIX_BOOL); PMIX_CONSTRUCT(&cb, pmix_cb_t); proc.rank = PMIX_RANK_WILDCARD; cb.proc = &proc; cb.key = PMIX_NODE_LIST; cb.scope = PMIX_INTERNAL; cb.info = &info; cb.ninfo = 1; if (0 == pmix_nslen(nspace)) { /* cycle across all known nspaces and aggregate the results */ PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { PMIX_LOAD_NSPACE(proc.nspace, ns->nspace); PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb); if (PMIX_SUCCESS != rc) { continue; } /* sanity check */ if (0 == pmix_list_get_size(&cb.kvs)) { continue; } kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs); val = kv->value; if (PMIX_STRING != val->type) { PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL); PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); continue; } if (NULL == val->data.string) { /* no nodes found */ PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); continue; } /* add to our list of results, ensuring uniqueness */ p = PMIx_Argv_split(val->data.string, ','); for (n = 0; NULL != p[n]; n++) { PMIx_Argv_append_unique_nosize(&tmp, p[n]); } PMIx_Argv_free(p); PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); } if (0 < PMIx_Argv_count(tmp)) { nodelist = PMIx_Argv_join(tmp, ','); PMIx_Argv_free(tmp); } ret = PMIX_SUCCESS; PMIX_DESTRUCT(&cb); goto done; } // looking for a specific nspace PMIX_LOAD_NSPACE(proc.nspace, nspace); PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&cb); ret = rc; goto done; } /* sanity check */ if (0 == pmix_list_get_size(&cb.kvs)) { PMIX_DESTRUCT(&cb); goto done; } kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs); val = kv->value; if (PMIX_STRING != val->type || NULL == val->data.string) { PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL); ret = PMIX_ERR_INVALID_VAL; PMIX_DESTRUCT(&cb); goto done; } nodelist = strdup(val->data.string); PMIX_DESTRUCT(&cb); done: reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); PMIX_RELEASE(cd); return; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &ret, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS == ret) { PMIX_BFROPS_PACK(rc, cd->peer, reply, &nodelist, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } if (NULL != nodelist) { free(nodelist); } PMIX_RELEASE(cd); } pmix-6.1.1~rc2/src/server/pmix_server_fence.c0000664000175000017500000012430015203536752021441 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2020 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_TIME_H # include #endif #include #ifndef MAX # define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #include "src/class/pmix_hotel.h" #include "src/class/pmix_list.h" #include "src/common/pmix_attributes.h" #include "src/common/pmix_iof.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/mca/pcompress/pcompress.h" #include "src/mca/plog/plog.h" #include "src/mca/pnet/pnet.h" #include "src/mca/psensor/psensor.h" #include "src/mca/ptl/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/client/pmix_client_ops.h" #include "pmix_server_ops.h" /* The rank_blob_t type to collect processes blobs, * this list afterward will form a node modex blob. */ typedef struct { pmix_list_item_t super; pmix_buffer_t *buf; } rank_blob_t; static void bufcon(rank_blob_t *p) { p->buf = NULL; } static void bufdes(rank_blob_t *p) { if (NULL != p->buf) { PMIX_RELEASE(p->buf); } } static PMIX_CLASS_INSTANCE(rank_blob_t, pmix_list_item_t, bufcon, bufdes); pmix_status_t pmix_server_commit(pmix_peer_t *peer, pmix_buffer_t *buf) { int32_t cnt; pmix_status_t rc; pmix_buffer_t b2, pbkt; pmix_kval_t *kp; pmix_scope_t scope; pmix_namespace_t *nptr; pmix_rank_info_t *info; pmix_proc_t proc; pmix_dmdx_remote_t *dcd, *dcdnext; char *data; size_t sz; pmix_cb_t cb; /* shorthand */ info = peer->info; nptr = peer->nptr; pmix_strncpy(proc.nspace, nptr->nspace, PMIX_MAX_NSLEN); proc.rank = info->pname.rank; pmix_output_verbose(2, pmix_server_globals.fence_output, "%s:%d EXECUTE COMMIT FOR %s:%d", pmix_globals.myid.nspace, pmix_globals.myid.rank, nptr->nspace, info->pname.rank); /* this buffer will contain one or more buffers, each * representing a different scope. These need to be locally * stored separately so we can provide required data based * on the requestor's location */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &scope, &cnt, PMIX_SCOPE); while (PMIX_SUCCESS == rc) { /* unpack and store the blob */ cnt = 1; PMIX_CONSTRUCT(&b2, pmix_buffer_t); PMIX_BFROPS_ASSIGN_TYPE(peer, &b2); PMIX_BFROPS_UNPACK(rc, peer, buf, &b2, &cnt, PMIX_BUFFER); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* unpack the buffer and store the values - we store them * in this peer's native GDS component so that other local * procs from that nspace can access it */ kp = PMIX_NEW(pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, &b2, kp, &cnt, PMIX_KVAL); while (PMIX_SUCCESS == rc) { if (PMIX_LOCAL == scope || PMIX_GLOBAL == scope) { PMIX_GDS_STORE_KV(rc, peer, &proc, scope, kp); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp); PMIX_DESTRUCT(&b2); return rc; } } if (PMIX_REMOTE == scope || PMIX_GLOBAL == scope) { PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &proc, scope, kp); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp); PMIX_DESTRUCT(&b2); return rc; } } PMIX_RELEASE(kp); // maintain accounting kp = PMIX_NEW(pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, &b2, kp, &cnt, PMIX_KVAL); } PMIX_RELEASE(kp); // maintain accounting PMIX_DESTRUCT(&b2); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); return rc; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &scope, &cnt, PMIX_SCOPE); } if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); return rc; } rc = PMIX_SUCCESS; /* mark us as having successfully received a blob from this proc */ info->modex_recvd = true; /* update the commit counter */ peer->commit_cnt++; /* see if anyone remote is waiting on this data - could be more than one */ PMIX_LIST_FOREACH_SAFE (dcd, dcdnext, &pmix_server_globals.remote_pnd, pmix_dmdx_remote_t) { if (0 != strncmp(dcd->cd->proc.nspace, nptr->nspace, PMIX_MAX_NSLEN)) { continue; } if (dcd->cd->proc.rank == info->pname.rank) { pmix_list_remove_item(&pmix_server_globals.remote_pnd, &dcd->super); /* we can now fulfill this request - collect the * remote/global data from this proc - note that there * may not be a contribution */ data = NULL; sz = 0; PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &proc; cb.scope = PMIX_REMOTE; cb.copy = true; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS == rc) { /* package it up */ PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); PMIX_LIST_FOREACH (kp, &cb.kvs, pmix_kval_t) { /* we pack this in our native BFROPS form as it * will be sent to another daemon */ PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &pbkt, kp, 1, PMIX_KVAL); } PMIX_UNLOAD_BUFFER(&pbkt, data, sz); } PMIX_DESTRUCT(&cb); /* execute the callback */ dcd->cd->cbfunc(rc, data, sz, dcd->cd->cbdata); if (NULL != data) { free(data); } /* we have finished this request */ PMIX_RELEASE(dcd); } } /* see if anyone local is waiting on this data- could be more than one */ rc = pmix_pending_resolve(nptr, info->pname.rank, PMIX_SUCCESS, PMIX_LOCAL, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } return rc; } /* get an existing object for tracking LOCAL participation in a collective * operation such as "fence". The only way this function can be * called is if at least one local client process is participating * in the operation. Thus, we know that at least one process is * involved AND has called the collective operation. * * NOTE: the host server *cannot* call us with a collective operation * as there is no mechanism by which it can do so. We call the host * server only after all participating local procs have called us. * So it is impossible for us to be called with a collective without * us already knowing about all local participants. * * procs - the array of procs participating in the collective, * regardless of location * nprocs - the number of procs in the array */ pmix_server_trkr_t *pmix_server_get_tracker(char *id, pmix_proc_t *procs, size_t nprocs, pmix_cmd_t type) { pmix_server_trkr_t *trk; size_t i, j, sz; size_t matches; pmix_proclist_t *p; pmix_proc_t *ptr; pmix_list_t cache; bool found; pmix_output_verbose(5, pmix_server_globals.fence_output, "pmix_server_get_tracker called with %d procs", (int) nprocs); /* bozo check - should never happen outside of programmer error */ if (NULL == procs && NULL == id) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return NULL; } /* there is no shortcut way to search the trackers - all * we can do is perform a brute-force search. Fortunately, * it is highly unlikely that there will be more than one * or two active at a time, and they are most likely to * involve only a single proc with WILDCARD rank - so this * shouldn't take long */ PMIX_LIST_FOREACH (trk, &pmix_server_globals.collectives, pmix_server_trkr_t) { /* Collective operation if unique identified by * the set of participating processes and the type of collective, * or by the operation ID */ if (NULL != id) { if (NULL != trk->id && 0 == strcmp(id, trk->id)) { PMIX_CONSTRUCT(&cache, pmix_list_t); /* update tracked procs to include the given ones, * filtered to only keep unique entries */ if (NULL != procs) { for (i=0; i < nprocs; i++) { found = false; for (j=0; j < trk->npcs; j++) { if (PMIX_CHECK_PROCID(&procs[i], &trk->pcs[j])) { // match - can ignore it found = true; break; } } if (!found) { // new proc, so we need to add it p = PMIX_NEW(pmix_proclist_t); memcpy(&p->proc, &procs[i], sizeof(pmix_proc_t)); pmix_list_append(&cache, &p->super); } } } i = pmix_list_get_size(&cache); if (0 < i) { sz = trk->npcs + i; PMIX_PROC_CREATE(ptr, sz); memcpy(ptr, trk->pcs, trk->npcs * sizeof(pmix_proc_t)); j = trk->npcs; PMIX_LIST_FOREACH(p, &cache, pmix_proclist_t) { memcpy(&ptr[j], &p->proc, sizeof(pmix_proc_t)); ++j; } PMIX_PROC_FREE(trk->pcs, trk->npcs); trk->pcs = ptr; trk->npcs = sz; } PMIX_LIST_DESTRUCT(&cache); return trk; } } else { // id must have been NULL, so we know procs is not if (nprocs != trk->npcs) { continue; } if (type != trk->type) { continue; } matches = 0; if (NULL != procs) { for (i = 0; i < nprocs; i++) { /* the procs may be in different order, so we have * to do an exhaustive search */ for (j = 0; j < trk->npcs; j++) { if (0 == strcmp(procs[i].nspace, trk->pcs[j].nspace) && procs[i].rank == trk->pcs[j].rank) { ++matches; break; } } } } if (trk->npcs == matches) { return trk; } } } /* No tracker was found */ return NULL; } /* create a new object for tracking LOCAL participation in a collective * operation such as "fence". The only way this function can be * called is if at least one local client process is participating * in the operation. Thus, we know that at least one process is * involved AND has called the collective operation. * * NOTE: the host server *cannot* call us with a collective operation * as there is no mechanism by which it can do so. We call the host * server only after all participating local procs have called us. * So it is impossible for us to be called with a collective without * us already knowing about all local participants. * * procs - the array of procs participating in the collective, * regardless of location * nprocs - the number of procs in the array */ pmix_server_trkr_t *pmix_server_new_tracker(char *id, pmix_proc_t *procs, size_t nprocs, pmix_cmd_t type) { pmix_server_trkr_t *trk; size_t i; bool all_def, found; pmix_namespace_t *nptr, *ns; pmix_rank_info_t *info; pmix_nspace_caddy_t *nm; pmix_nspace_t first; pmix_output_verbose(5, pmix_server_globals.fence_output, "pmix_server_new_tracker called with %d procs", (int) nprocs); /* bozo check - should never happen outside of programmer error */ if (NULL == procs && NULL == id) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return NULL; } pmix_output_verbose(5, pmix_server_globals.fence_output, "adding new tracker %s with %d procs", (NULL == id) ? "NO-ID" : id, (int) nprocs); /* this tracker is new - create it */ trk = PMIX_NEW(pmix_server_trkr_t); if (NULL == trk) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return NULL; } trk->type = type; if (NULL != id) { trk->id = strdup(id); } if (NULL == procs) { // we are done trk->def_complete = true; pmix_list_append(&pmix_server_globals.collectives, &trk->super); return trk; } /* copy the procs */ PMIX_PROC_CREATE(trk->pcs, nprocs); if (NULL == trk->pcs) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); PMIX_RELEASE(trk); return NULL; } memcpy(trk->pcs, procs, nprocs * sizeof(pmix_proc_t)); trk->npcs = nprocs; trk->local = true; trk->nlocal = 0; all_def = true; PMIX_LOAD_NSPACE(first, NULL); for (i = 0; i < nprocs; i++) { /* is this nspace known to us? */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(procs[i].nspace, ns->nspace)) { nptr = ns; break; } } /* check if multiple nspaces are involved in this operation */ if (0 == strlen(first)) { PMIX_LOAD_NSPACE(first, procs[i].nspace); } else if (!PMIX_CHECK_NSPACE(first, procs[i].nspace)) { trk->hybrid = true; } if (NULL == nptr) { /* we don't know about this nspace. If there is going to * be at least one local process participating in a fence, * they we require that either at least one process must already * have been registered (via "register client") or that the * nspace itself have been regisered. So either the nspace * wasn't registered because it doesn't include any local * procs, or our host has not been told about this nspace * because it won't host any local procs. We therefore mark * this tracker as including non-local participants. * * NOTE: It is conceivable that someone might want to review * this constraint at a future date. I believe it has to be * required (at least for now) as otherwise we wouldn't have * a way of knowing when all local procs have participated. * It is possible that a new nspace could come along at some * later time and add more local participants - but we don't * know how long to wait. * * The only immediately obvious alternative solutions would * be to either require that RMs always inform all daemons * about the launch of nspaces, regardless of whether or * not they will host local procs; or to drop the aggregation * of local participants and just pass every fence call * directly to the host. Neither of these seems palatable * at this time. */ trk->local = false; /* we don't know any more info about this nspace, so * there isn't anything more we can do */ continue; } /* it is possible we know about this nspace because the host * has registered one or more clients via "register_client", * but the host has not yet called "register_nspace". There is * a very tiny race condition whereby this can happen due * to event-driven processing, but account for it here */ if (SIZE_MAX == nptr->nlocalprocs) { /* delay processing until this nspace is registered */ all_def = false; continue; } if (0 == nptr->nlocalprocs) { /* the host has informed us that this nspace has no local procs */ pmix_output_verbose(5, pmix_server_globals.fence_output, "pmix_server_new_tracker: nspace %s has no local procs", procs[i].nspace); trk->local = false; continue; } /* check and add uniq ns into trk nslist */ found = false; PMIX_LIST_FOREACH (nm, &trk->nslist, pmix_nspace_caddy_t) { if (0 == strcmp(nptr->nspace, nm->ns->nspace)) { found = true; break; } } if (!found) { nm = PMIX_NEW(pmix_nspace_caddy_t); PMIX_RETAIN(nptr); nm->ns = nptr; pmix_list_append(&trk->nslist, &nm->super); } /* if they want all the local members of this nspace, then * add them in here. They told us how many procs will be * local to us from this nspace, but we don't know their * ranks. So as long as they want _all_ of them, we can * handle that case regardless of whether the individual * clients have been "registered" */ if (PMIX_RANK_WILDCARD == procs[i].rank) { trk->nlocal += nptr->nlocalprocs; /* the total number of procs in this nspace was provided * in the data blob delivered to register_nspace, so check * to see if all the procs are local */ if (nptr->nprocs != nptr->nlocalprocs) { trk->local = false; } continue; } /* They don't want all the local clients, or they are at * least listing them individually. Check if all the clients * for this nspace have been registered via "register_client" * so we know the specific ranks on this node */ if (!nptr->all_registered) { /* nope, so no point in going further on this one - we'll * process it once all the procs are known */ all_def = false; pmix_output_verbose(5, pmix_server_globals.fence_output, "pmix_server_new_tracker: all clients not registered nspace %s", procs[i].nspace); continue; } /* is this one of my local ranks? */ found = false; PMIX_LIST_FOREACH (info, &nptr->ranks, pmix_rank_info_t) { if (procs[i].rank == info->pname.rank) { pmix_output_verbose(5, pmix_server_globals.fence_output, "adding local proc %s.%d to tracker", info->pname.nspace, info->pname.rank); found = true; /* track the count */ trk->nlocal++; break; } } if (!found) { trk->local = false; } } if (all_def) { trk->def_complete = true; } pmix_list_append(&pmix_server_globals.collectives, &trk->super); return trk; } static void fence_timeout(int sd, short args, void *cbdata) { pmix_server_trkr_t *trk = (pmix_server_trkr_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(2, pmix_server_globals.fence_output, "ALERT: fence timeout fired"); /* execute the provided callback function with the error */ if (NULL != trk->modexcbfunc) { trk->modexcbfunc(PMIX_ERR_TIMEOUT, NULL, 0, trk, NULL, NULL); return; // the cbfunc will have cleaned up the tracker } trk->event_active = false; PMIX_RELEASE(trk); } static void _collect_job_info(int sd, short args, void *cbdata) { pmix_cb_t *cbin = (pmix_cb_t*)cbdata; char **nspaces = NULL; size_t n, m; bool found; pmix_proc_t proc; pmix_cb_t cb; pmix_status_t ret; pmix_buffer_t pbkt; pmix_kval_t *kptr; pmix_byte_object_t pbo; pmix_namespace_t *nptr, *ns; pmix_rank_info_t *rinfo; pmix_peer_t *peer; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cbin); /* find the unique nspaces that are participating */ for (m=0; m < cbin->nprocs; m++) { if (NULL == nspaces) { PMIx_Argv_append_nosize(&nspaces, cbin->procs[m].nspace); } else { found = false; for (n = 0; NULL != nspaces[n]; n++) { if (0 == strcmp(nspaces[n], cbin->procs[m].nspace)) { found = true; break; } } if (!found) { PMIx_Argv_append_nosize(&nspaces, cbin->procs[m].nspace); } } } // cycle across the nspaces to collect their job info for (n = 0; NULL != nspaces[n]; n++) { // see if we have this nspace nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(ns->nspace, nspaces[n])) { nptr = ns; break; } } if (NULL == nptr) { // we don't know this one, so nothing we can do continue; } /* this is a local request, so give the gds the option * of returning a copy of the data, or a pointer to * local storage */ PMIX_LOAD_PROCID(&proc, nspaces[n], PMIX_RANK_WILDCARD); PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &proc; cb.scope = PMIX_SCOPE_UNDEF; cb.copy = false; ret = PMIX_ERR_NOT_FOUND; // have any local clients registered? if (0 < pmix_list_get_size(&nptr->ranks)) { // get one of the local clients so we will // know its gds module rinfo = (pmix_rank_info_t*)pmix_list_get_first(&nptr->ranks); if (NULL != rinfo) { peer = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, rinfo->peerid); if (NULL != peer) { PMIX_GDS_FETCH_KV(ret, peer, &cb); } } } // if we didn't find it there, try getting it // from our storage if (PMIX_SUCCESS != ret) { PMIX_GDS_FETCH_KV(ret, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_DESTRUCT(&cb); continue; } } PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); /* pack the nspace name */ PMIX_BFROPS_PACK(ret, pmix_globals.mypeer, &pbkt, &nspaces[n], 1, PMIX_STRING); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&cb); goto done; } PMIX_LIST_FOREACH (kptr, &cb.kvs, pmix_kval_t) { PMIX_BFROPS_PACK(ret, pmix_globals.mypeer, &pbkt, kptr, 1, PMIX_KVAL); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&cb); goto done; } } PMIX_DESTRUCT(&cb); PMIX_UNLOAD_BUFFER(&pbkt, pbo.bytes, pbo.size); PMIX_BFROPS_PACK(ret, pmix_globals.mypeer, &cb.data, &pbo, 1, PMIX_BYTE_OBJECT); PMIX_BYTE_OBJECT_DESTRUCT(&pbo); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_DESTRUCT(&pbkt); goto done; } PMIX_DESTRUCT(&pbkt); } done: PMIx_Argv_free(nspaces); PMIX_WAKEUP_THREAD(&cbin->lock); PMIX_POST_OBJECT(cb); } pmix_status_t PMIx_server_collect_job_info(pmix_proc_t *procs, size_t nprocs, pmix_data_buffer_t *dbuf) { pmix_cb_t cb; pmix_byte_object_t bo; pmix_status_t rc; // we need to threadshift this request as it accesses // global data PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.procs = procs; cb.nprocs = nprocs; PMIX_THREADSHIFT(&cb, _collect_job_info); PMIX_WAIT_THREAD(&cb.lock); if (PMIX_SUCCESS == cb.status) { PMIX_UNLOAD_BUFFER(&cb.data, bo.bytes, bo.size); PMIx_Data_buffer_load(dbuf, bo.bytes, bo.size); // removes data from the byte object } rc = cb.status; PMIX_DESTRUCT(&cb); return rc; } pmix_status_t pmix_server_collect_data(pmix_server_trkr_t *trk, pmix_buffer_t *buf) { pmix_buffer_t bucket, bkt, *pbkt = NULL; pmix_cb_t cb; pmix_kval_t *kv; pmix_byte_object_t bo, outbo; pmix_server_caddy_t *scd; pmix_proc_t pcs; pmix_status_t rc = PMIX_SUCCESS; pmix_list_t rank_blobs; rank_blob_t *blob; uint8_t blob_info_byte; bool compressed; PMIX_CONSTRUCT(&bucket, pmix_buffer_t); if (PMIX_COLLECT_YES == trk->collect_type) { pmix_output_verbose(2, pmix_server_globals.fence_output, "fence - assembling data"); PMIX_CONSTRUCT(&rank_blobs, pmix_list_t); PMIX_LIST_FOREACH (scd, &trk->local_cbs, pmix_server_caddy_t) { /* get any remote contribution - note that there * may not be a contribution */ PMIX_LOAD_PROCID(&pcs, scd->peer->info->pname.nspace, scd->peer->info->pname.rank); pbkt = PMIX_NEW(pmix_buffer_t); /* pack the rank */ PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, pbkt, &pcs, 1, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_LIST_DESTRUCT(&rank_blobs); PMIX_RELEASE(pbkt); goto cleanup; } PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &pcs; cb.scope = PMIX_REMOTE; cb.copy = true; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS == rc) { /* pack the returned kval's */ PMIX_LIST_FOREACH (kv, &cb.kvs, pmix_kval_t) { PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, pbkt, kv, 1, PMIX_KVAL); if (rc != PMIX_SUCCESS) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); PMIX_LIST_DESTRUCT(&rank_blobs); PMIX_RELEASE(pbkt); goto cleanup; } } /* add the blob to the list */ blob = PMIX_NEW(rank_blob_t); blob->buf = pbkt; pmix_list_append(&rank_blobs, &blob->super); pbkt = NULL; } PMIX_DESTRUCT(&cb); if (NULL != pbkt) { PMIX_RELEASE(pbkt); } } /* mark the collection type so we can check on the * receiving end that all participants did the same. Note * that if the receiving end thinks that the collect flag * is false, then store_modex will not be called on that * node and this information (and the flag) will be ignored, * meaning that no error is generated! */ blob_info_byte= PMIX_COLLECT_YES; /* pack the modex blob info byte */ PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &bucket, &blob_info_byte, 1, PMIX_BYTE); /* pack the collected blobs of processes */ PMIX_LIST_FOREACH (blob, &rank_blobs, rank_blob_t) { /* extract the blob */ PMIX_UNLOAD_BUFFER(blob->buf, bo.bytes, bo.size); blob->buf = NULL; /* pack the returned blob */ PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &bucket, &bo, 1, PMIX_BYTE_OBJECT); PMIX_BYTE_OBJECT_DESTRUCT(&bo); // releases the data if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } PMIX_LIST_DESTRUCT(&rank_blobs); } else { /* mark the collection type so we can check on the * receiving end that all participants did the same. * Don't do it for non-debug mode so we don't unnecessarily * send the collection bucket. The mdxcbfunc in the * server only calls store_modex if the local collect * flag is set to true. In debug mode, this check will * cause the store_modex function to see that this node * thought the collect flag was not set, and therefore * generate an error */ blob_info_byte= PMIX_COLLECT_NO; /* pack the modex blob info byte */ PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &bucket, &blob_info_byte, 1, PMIX_BYTE); } if (!PMIX_BUFFER_IS_EMPTY(&bucket)) { /* because the remote servers have to unpack things * in chunks, we have to pack the bucket as a single * byte object to allow remote unpack */ PMIX_UNLOAD_BUFFER(&bucket, bo.bytes, bo.size); // compress the data if (pmix_compress.compress((uint8_t*)bo.bytes, bo.size, (uint8_t**)&outbo.bytes, &outbo.size)) { compressed = true; PMIX_BYTE_OBJECT_DESTRUCT(&bo); bo.bytes = outbo.bytes; bo.size = outbo.size; } else { compressed = false; } // need to get the compressed flag inside the byte object we pass along PMIX_CONSTRUCT(&bkt, pmix_buffer_t); PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &bkt, &compressed, 1, PMIX_BOOL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_BYTE_OBJECT_DESTRUCT(&bo); PMIX_DESTRUCT(&bkt); goto cleanup; } PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &bkt, &bo, 1, PMIX_BYTE_OBJECT); PMIX_BYTE_OBJECT_DESTRUCT(&bo); // releases the data if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&bkt); goto cleanup; } // now transfer to final buffer PMIX_UNLOAD_BUFFER(&bkt, bo.bytes, bo.size); PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, buf, &bo, 1, PMIX_BYTE_OBJECT); PMIX_BYTE_OBJECT_DESTRUCT(&bo); // releases the data if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&bkt); } } cleanup: PMIX_DESTRUCT(&bucket); return rc; } pmix_status_t pmix_server_fence(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_modex_cbfunc_t modexcbfunc, pmix_op_cbfunc_t opcbfunc) { int32_t cnt; pmix_status_t rc; size_t nprocs; pmix_proc_t *procs = NULL; bool collect_data = false; pmix_server_trkr_t *trk; char *data = NULL; size_t sz = 0; pmix_buffer_t bucket; pmix_info_t *info = NULL; size_t ninfo = 0, ninf, n; struct timeval tv = {0, 0}; pmix_output_verbose(2, pmix_server_globals.fence_output, "recvd FENCE"); /* unpack the number of procs */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &nprocs, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { return rc; } pmix_output_verbose(2, pmix_server_globals.fence_output, "recvd fence from %s with %d procs", PMIX_PEER_PRINT(cd->peer), (int) nprocs); /* there must be at least one as the client has to at least provide * their own namespace */ if (nprocs < 1) { return PMIX_ERR_BAD_PARAM; } /* create space for the procs */ PMIX_PROC_CREATE(procs, nprocs); if (NULL == procs) { return PMIX_ERR_NOMEM; } /* unpack the procs */ cnt = nprocs; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, procs, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { goto cleanup; } /* sort the array */ qsort(procs, nprocs, sizeof(pmix_proc_t), pmix_util_compare_proc); /* unpack the number of provided info structs */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &ninf, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { return rc; } ninfo = ninf + 2; PMIX_INFO_CREATE(info, ninfo); if (NULL == info) { PMIX_PROC_FREE(procs, nprocs); return PMIX_ERR_NOMEM; } /* store the default response */ rc = PMIX_SUCCESS; PMIX_INFO_LOAD(&info[ninf+1], PMIX_LOCAL_COLLECTIVE_STATUS, &rc, PMIX_STATUS); PMIX_INFO_LOAD(&info[ninf], PMIX_SORTED_PROC_ARRAY, NULL, PMIX_BOOL); if (0 < ninf) { /* unpack the info */ cnt = ninf; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_INFO_FREE(info, ninfo); goto cleanup; } /* see if we are to collect data or enforce a timeout - we don't internally care * about any other directives */ for (n = 0; n < ninf; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_COLLECT_DATA)) { collect_data = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_TIMEOUT)) { rc = PMIx_Value_get_number(&info[n].value, &tv.tv_sec, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_PROC_FREE(procs, nprocs); PMIX_INFO_FREE(info, ninfo); return rc; } } } } /* find/create the local tracker for this operation */ if (NULL == (trk = pmix_server_get_tracker(NULL, procs, nprocs, PMIX_FENCENB_CMD))) { /* If no tracker was found - create and initialize it once */ if (NULL == (trk = pmix_server_new_tracker(NULL, procs, nprocs, PMIX_FENCENB_CMD))) { /* only if a bozo error occurs */ PMIX_ERROR_LOG(PMIX_ERROR); /* DO NOT HANG */ if (NULL != opcbfunc) { opcbfunc(PMIX_ERROR, cd); } rc = PMIX_ERROR; PMIX_INFO_FREE(info, ninfo); goto cleanup; } trk->type = PMIX_FENCENB_CMD; trk->modexcbfunc = modexcbfunc; /* mark if they want the data back */ if (collect_data) { trk->collect_type = PMIX_COLLECT_YES; } else { trk->collect_type = PMIX_COLLECT_NO; } } else { switch (trk->collect_type) { case PMIX_COLLECT_NO: if (collect_data) { trk->collect_type = PMIX_COLLECT_INVALID; } break; case PMIX_COLLECT_YES: if (!collect_data) { trk->collect_type = PMIX_COLLECT_INVALID; } break; default: break; } } /* we only save the info structs from the first caller * who provides them - it is a user error to provide * different values from different participants */ if (NULL == trk->info) { trk->info = info; trk->ninfo = ninfo; } else { /* cleanup */ PMIX_INFO_FREE(info, ninfo); info = NULL; ninfo = 0; } /* add this contributor to the tracker so they get * notified when we are done */ pmix_list_append(&trk->local_cbs, &cd->super); /* if a timeout was specified, set it */ if (0 < tv.tv_sec && !trk->event_active) { PMIX_THREADSHIFT_DELAY(trk, fence_timeout, tv.tv_sec); trk->event_active = true; } /* if all local contributions have been received, * let the local host's server know that we are at the * "fence" point - they will callback once the barrier * across all participants has been completed */ if (trk->def_complete && pmix_list_get_size(&trk->local_cbs) == trk->nlocal) { pmix_output_verbose(2, pmix_server_globals.fence_output, "fence LOCALLY complete"); /* if a timeout was set, then we delete it here as we can * ONLY check for local completion. Otherwise, passing * the tracker object up to the host can result in * competing timeout events, and the host could return * the tracker AFTER we released it due to our internal * timeout firing */ if (trk->event_active) { pmix_event_del(&trk->ev); trk->event_active = false; } /* if this is a purely local fence (i.e., all participants are local), * then it is done and we notify accordingly */ if (pmix_server_globals.fence_localonly_opt && trk->local) { /* the modexcbfunc thread-shifts the call prior to processing, * so it is okay to call it directly from here. The switchyard * will acknowledge successful acceptance of the fence request, * but the client still requires a return from the callback in * that scenario, so we leave this caddy on the list of local cbs */ rc = trk->info[trk->ninfo-1].value.data.status; trk->modexcbfunc(rc, NULL, 0, trk, NULL, NULL); rc = PMIX_SUCCESS; // ensure the switchyard doesn't release the caddy goto cleanup; } /* this fence involves non-local procs - check if the * host supports it */ if (NULL == pmix_host_server.fence_nb) { rc = PMIX_ERR_NOT_SUPPORTED; /* clear the caddy from this tracker so it can be * released upon return - the switchyard will send an * error to this caller, and so the fence completion * function doesn't need to do so */ pmix_list_remove_item(&trk->local_cbs, &cd->super); cd->trk = NULL; /* we need to ensure that all other local participants don't * just hang waiting for the error return, so execute * the fence completion function - it threadshifts the call * prior to processing, so it is okay to call it directly * from here */ trk->host_called = false; // the host will not be calling us back trk->modexcbfunc(rc, NULL, 0, trk, NULL, NULL); goto cleanup; } /* if the user asked us to collect data, then we have * to provide any locally collected data to the host * server so they can circulate it - only take data * from the specified procs as not everyone is necessarily * participating! And only take data intended for remote * or global distribution */ PMIX_CONSTRUCT(&bucket, pmix_buffer_t); if (PMIX_SUCCESS != (rc = pmix_server_collect_data(trk, &bucket))) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&bucket); /* clear the caddy from this tracker so it can be * released upon return - the switchyard will send an * error to this caller, and so the fence completion * function doesn't need to do so */ pmix_list_remove_item(&trk->local_cbs, &cd->super); cd->trk = NULL; /* we need to ensure that all other local participants don't * just hang waiting for the error return, so execute * the fence completion function - it threadshifts the call * prior to processing, so it is okay to call it directly * from here */ trk->modexcbfunc(rc, NULL, 0, trk, NULL, NULL); goto cleanup; } /* now unload the blob and pass it upstairs */ PMIX_UNLOAD_BUFFER(&bucket, data, sz); PMIX_DESTRUCT(&bucket); trk->host_called = true; rc = pmix_host_server.fence_nb(trk->pcs, trk->npcs, trk->info, trk->ninfo, data, sz, trk->modexcbfunc, trk); if (PMIX_SUCCESS != rc && PMIX_OPERATION_SUCCEEDED != rc) { /* clear the caddy from this tracker so it can be * released upon return - the switchyard will send an * error to this caller, and so the fence completion * function doesn't need to do so */ pmix_list_remove_item(&trk->local_cbs, &cd->super); cd->trk = NULL; /* we need to ensure that all other local participants don't * just hang waiting for the error return, so execute * the fence completion function - it threadshifts the call * prior to processing, so it is okay to call it directly * from here */ trk->host_called = false; // the host will not be calling us back trk->modexcbfunc(rc, NULL, 0, trk, NULL, NULL); } else if (PMIX_OPERATION_SUCCEEDED == rc) { /* the operation was atomically completed and the host will * not be calling us back - ensure we notify all participants. * the modexcbfunc thread-shifts the call prior to processing, * so it is okay to call it directly from here */ trk->host_called = false; // the host will not be calling us back rc = trk->info[trk->ninfo-1].value.data.status; trk->modexcbfunc(rc, NULL, 0, trk, NULL, NULL); /* ensure that the switchyard doesn't release the caddy */ rc = PMIX_SUCCESS; } } cleanup: PMIX_PROC_FREE(procs, nprocs); return rc; } pmix-6.1.1~rc2/src/server/pmix_server_get.c0000664000175000017500000014163315203536752021150 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "src/class/pmix_list.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/gds/gds.h" #include "src/mca/ptl/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "pmix_server_ops.h" #include "src/client/pmix_client_ops.h" extern pmix_server_module_t pmix_host_server; typedef struct { pmix_object_t super; pmix_event_t ev; volatile bool active; pmix_status_t status; const char *data; size_t ndata; pmix_dmdx_local_t *lcd; pmix_release_cbfunc_t relcbfunc; void *cbdata; } pmix_dmdx_reply_caddy_t; static void dcd_con(pmix_dmdx_reply_caddy_t *p) { p->status = PMIX_ERROR; p->ndata = 0; p->lcd = NULL; p->relcbfunc = NULL; p->cbdata = NULL; } PMIX_CLASS_INSTANCE(pmix_dmdx_reply_caddy_t, pmix_object_t, dcd_con, NULL); static void dmdx_cbfunc(pmix_status_t status, const char *data, size_t ndata, void *cbdata, pmix_release_cbfunc_t relfn, void *relcbdata); static pmix_status_t _satisfy_request(pmix_namespace_t *nptr, pmix_rank_t rank, char *key, pmix_server_caddy_t *cd, bool diffnspace, pmix_scope_t scope, pmix_modex_cbfunc_t cbfunc, void *cbdata); static pmix_status_t create_local_tracker(char nspace[], pmix_rank_t rank, char *key, pmix_info_t info[], size_t ninfo, pmix_modex_cbfunc_t cbfunc, void *cbdata, pmix_dmdx_local_t **lcd, pmix_dmdx_request_t **rq); static pmix_status_t get_job_data(char *nspace, pmix_server_caddy_t *cd, char *key, pmix_buffer_t *pbkt); static void get_timeout(int sd, short args, void *cbdata); /* declare a function whose sole purpose is to * free data that we provided to our host server * when servicing dmodex requests */ static void relfn(void *cbdata) { char *data = (char *) cbdata; if (NULL != data) { free(data); } } static pmix_status_t defer_response(char *nspace, pmix_rank_t rank, char *key, pmix_server_caddy_t *cd, bool localonly, pmix_modex_cbfunc_t cbfunc, void *cbdata, struct timeval *tv, pmix_dmdx_local_t **locald) { pmix_status_t rc; pmix_dmdx_request_t *req; pmix_dmdx_local_t *lcd; *locald = NULL; if (localonly) { /* the client asked that we not wait, so return now */ pmix_output_verbose(2, pmix_server_globals.get_output, "%s:%d CLIENT REQUESTED IMMEDIATE", pmix_globals.myid.nspace, pmix_globals.myid.rank); return PMIX_ERR_NOT_AVAILABLE; } /* we cannot do anything further, so just track this request * for now */ rc = create_local_tracker(nspace, rank, key, cd->info, cd->ninfo, cbfunc, cbdata, &lcd, &req); if (PMIX_ERR_NOMEM == rc || NULL == lcd) { return rc; } pmix_output_verbose(2, pmix_server_globals.get_output, "%s:%d TRACKER CREATED - WAITING TIMEOUT %d", pmix_globals.myid.nspace, pmix_globals.myid.rank, (NULL == tv) ? -1 : (int)tv->tv_sec); /* if they specified a timeout, set it up now */ if (NULL != tv && 0 < tv->tv_sec) { pmix_event_evtimer_set(pmix_globals.evbase, &req->ev, get_timeout, req); pmix_event_evtimer_add(&req->ev, tv); req->event_active = true; } /* the peer object has been added to the new lcd tracker, * so return success here */ *locald = lcd; return rc; } pmix_status_t pmix_server_get(pmix_buffer_t *buf, pmix_modex_cbfunc_t cbfunc, void *cbdata) { pmix_server_caddy_t *cd = (pmix_server_caddy_t *) cbdata; int32_t cnt; pmix_status_t rc; pmix_rank_t rank; char *cptr, *key = NULL; char nspace[PMIX_MAX_NSLEN + 1]; pmix_namespace_t *ns, *nptr; pmix_dmdx_local_t *lcd; bool local = false; bool localonly = false; bool diffnspace = false; bool refresh_cache = false; bool scope_given = false; bool keyprovided = false; struct timeval tv = {0, 0}; pmix_buffer_t pbkt; pmix_cb_t cb; pmix_kval_t *kval; pmix_byte_object_t bo; pmix_proc_t proc; char *data; size_t sz, n; pmix_info_t *info; pmix_scope_t scope = PMIX_SCOPE_UNDEF; pmix_rank_info_t *iptr; pmix_output_verbose(2, pmix_server_globals.get_output, "%s recvd GET", PMIX_NAME_PRINT(&pmix_globals.myid)); /* setup */ PMIX_LOAD_NSPACE(nspace, NULL); /* retrieve the nspace and rank of the requested proc */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &cptr, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_LOAD_NSPACE(nspace, cptr); free(cptr); cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &rank, &cnt, PMIX_PROC_RANK); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_LOAD_PROCID(&proc, nspace, rank); /* retrieve any provided info structs */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &cd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } if (0 < cd->ninfo) { PMIX_INFO_CREATE(cd->info, cd->ninfo); if (NULL == cd->info) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } cnt = cd->ninfo; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } /* if they provided a specific key, get it */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &key, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); return rc; } if (PMIX_SUCCESS == rc) { keyprovided = true; } /* search for directives we can deal with here */ for (n = 0; n < cd->ninfo; n++) { if (PMIX_CHECK_KEY(&cd->info[n], PMIX_IMMEDIATE)) { /* just check our own data - don't wait * or request it from someone else */ localonly = PMIX_INFO_TRUE(&cd->info[n]); } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_TIMEOUT)) { tv.tv_sec = cd->info[n].value.data.uint32; } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_GET_REFRESH_CACHE)) { refresh_cache = PMIX_INFO_TRUE(&cd->info[n]); } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_DATA_SCOPE)) { scope = cd->info[n].value.data.scope; scope_given = true; } } /* check for a request for pset names - these are not associated * with a given nspace. Instead, we are searching for any psets * that contain the calling process */ if (keyprovided && PMIx_Check_key(key, PMIX_PSET_NAMES)) { /* loop over all known psets and collect names * in which this proc is a member */ pmix_pset_t *pset; char **psets = NULL; PMIX_LIST_FOREACH(pset, &pmix_server_globals.psets, pmix_pset_t) { for (n=0; n < pset->nmembers; n++) { if (PMIx_Check_procid(&pset->members[n], &proc)) { PMIx_Argv_append_nosize(&psets, pset->name); break; } } } if (NULL != psets) { data = PMIx_Argv_join(psets, ','); PMIx_Argv_free(psets); // pass it back // we have to assemble this data into a form that // the client_get function can properly unpack PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); PMIX_CONSTRUCT(&cb, pmix_cb_t); PMIX_KVAL_NEW(kval, PMIX_PSET_NAMES); kval->value->data.string = data; kval->value->type = PMIX_STRING; pmix_list_append(&cb.kvs, &kval->super); /* assemble the provided data into a byte object */ PMIX_GDS_ASSEMB_KVS_REQ(rc, pmix_globals.mypeer, &proc, &cb.kvs, &pbkt, cd); if (rc != PMIX_SUCCESS) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&cb); return rc; } PMIX_DESTRUCT(&cb); if (PMIX_PEER_IS_V1(cd->peer)) { /* if the client is using v1, then it expects the * data returned to it as the rank followed by a byte object containing * a buffer - so we have to do a little gyration */ pmix_buffer_t xfer; PMIX_CONSTRUCT(&xfer, pmix_buffer_t); PMIX_BFROPS_PACK(rc, cd->peer, &xfer, &pbkt, 1, PMIX_BUFFER); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&xfer); PMIX_DESTRUCT(&cb); return rc; } PMIX_UNLOAD_BUFFER(&xfer, bo.bytes, bo.size); PMIX_DESTRUCT(&xfer); } else { PMIX_UNLOAD_BUFFER(&pbkt, bo.bytes, bo.size); } PMIX_DESTRUCT(&pbkt); /* pack it for transmission */ PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); PMIX_BFROPS_PACK(rc, cd->peer, &pbkt, &bo, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); return rc; } /* unload the resulting payload */ PMIX_UNLOAD_BUFFER(&pbkt, data, sz); PMIX_DESTRUCT(&pbkt); /* call the internal callback function - it will * release the cbdata */ cbfunc(PMIX_SUCCESS, data, sz, cbdata, relfn, data); /* return success so the server doesn't duplicate * the release of cbdata */ return PMIX_SUCCESS; } else { // return not found as this proc doesn't belong to any psets return PMIX_ERR_NOT_FOUND; } } /* find the nspace object for the target proc */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(nspace, ns->nspace)) { nptr = ns; break; } } pmix_output_verbose(2, pmix_server_globals.get_output, "%s EXECUTE GET FOR %s:%d WITH KEY %s ON BEHALF OF %s", PMIX_NAME_PRINT(&pmix_globals.myid), nspace, rank, (NULL == key) ? "NULL" : PMIx_Get_attribute_name(key), PMIX_PNAME_PRINT(&cd->peer->info->pname)); /* This call flows upward from a local client. If we don't * know about this nspace, then it cannot refer to the * nspace of the requestor - i.e., they aren't asking * about one of their peers. There are two reasons why we * might not know about this nspace at this time: * * (a) we don't host any local procs from this nspace, and * so the local RM didn't tell us about it. We will have * to request the information from it. * * (b) a race condition where the other job hasn't registered * its nspace yet. This begs the question as to how the * requestor got the nspace name in the first place! * However, there _may_ be some path whereby that could * happen, so we try to deal with it here. * * Either way, we are going to have to request the info from * the host RM. Since we are hopeful of getting an answer, * we add the nspace to our list of known nspaces so the * info has a "landing zone" upon return */ if (NULL == nptr) { if (localonly) { /* the user doesn't want us to look for the info, * so we simply return at this point */ pmix_output_verbose(5, pmix_server_globals.get_output, "%s UNKNOWN NSPACE: LOCAL ONLY - NOT FOUND", PMIX_NAME_PRINT(&pmix_globals.myid)); return PMIX_ERR_NOT_FOUND; } /* this is for an nspace we don't know about yet, so * give the host server a chance to tell us about it. * The cbdata passed here is the pmix_server_caddy_t * we were passed - it contains the pmix_peer_t of * the original requestor so they will get the data * back when we receive it */ goto request; } /* the target nspace is known, so we can process the request */ if (PMIX_RANK_WILDCARD == rank) { PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); /* they are asking for the job-level info for (or at least a * reserved key from) this nspace */ rc = get_job_data(nptr->nspace, cd, key, &pbkt); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&pbkt); return rc; } /* unload the resulting payload */ PMIX_UNLOAD_BUFFER(&pbkt, data, sz); PMIX_DESTRUCT(&pbkt); /* call the internal callback function - it will * release the cbdata */ cbfunc(PMIX_SUCCESS, data, sz, cbdata, relfn, data); /* return success so the server doesn't duplicate * the release of cbdata */ return PMIX_SUCCESS; } /* We have to wait for all local clients to be registered before * we can know whether this request is for data from a local or a * remote client because one client might ask for data about another * client that the host RM hasn't told us about yet. Fortunately, * we do know how many clients to expect, so first check to see if * all clients have been registered with us */ if (!nptr->all_registered) { pmix_output_verbose(2, pmix_server_globals.get_output, "%s:%d NSPACE %s not all registered - delay %d", pmix_globals.myid.nspace, pmix_globals.myid.rank, nspace, (int)tv.tv_sec); rc = defer_response(nspace, rank, key, cd, localonly, cbfunc, cbdata, &tv, &lcd); if (PMIX_ERR_NOT_FOUND == rc) { /* just means we created a tracker */ rc = PMIX_SUCCESS; } else if (PMIX_ERR_NOT_AVAILABLE == rc) { /* means they requested "immediate" */ rc = PMIX_ERR_NOT_FOUND; } return rc; } /* everyone has been registered, so we know who our local procs * are - see if this target is one of them. Note that we cannot reach * this point if rank = WILDCARD */ if (0 < nptr->nlocalprocs) { /* if all the procs are local, then this must be a local proc */ if (nptr->nprocs == nptr->nlocalprocs) { local = true; } else { /* see if this proc is one of our local ones */ PMIX_LIST_FOREACH (iptr, &nptr->ranks, pmix_rank_info_t) { if (rank == iptr->pname.rank) { if (0 > iptr->peerid) { /* this rank has not connected yet, so this request needs to be held */ rc = defer_response(nspace, rank, key, cd, localonly, cbfunc, cbdata, &tv, &lcd); if (PMIX_ERR_NOT_FOUND == rc) { /* just means we created a tracker */ rc = PMIX_SUCCESS; } else if (PMIX_ERR_NOT_AVAILABLE == rc) { /* means they requested "immediate" */ rc = PMIX_ERR_NOT_FOUND; } return rc; } local = true; break; } } if (NULL == pmix_pointer_array_get_item(&pmix_server_globals.clients, iptr->peerid)) { /* this must be a remote rank */ local = false; } } } else { local = false; } /* if the proc is local, then we assume that the host/server maintains * updated info - there is no need to ask the host to refresh a cache */ if (local && refresh_cache) { return PMIX_OPERATION_SUCCEEDED; } else if (refresh_cache) { if (NULL != key) { free(key); key = NULL; } goto request; } /* the target nspace is known - if they asked us to wait for a specific * key to be available, check if it is present. NOTE: key is only * NULL if the request came from an older version */ if (NULL != key || !keyprovided) { PMIX_LOAD_PROCID(&proc, nspace, rank); PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &proc; if (scope_given) { cb.scope = scope; } else { if (NULL != key && PMIX_CHECK_RESERVED_KEY(key)) { cb.scope = PMIX_SCOPE_UNDEF; } else if (local) { cb.scope = PMIX_LOCAL; } else { cb.scope = PMIX_REMOTE; } } cb.copy = false; cb.info = cd->info; cb.ninfo = cd->ninfo; cb.key = key; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); /* if the requested key was found, but in a different scope, * then we report this back as there is no point in waiting */ if (PMIX_ERR_EXISTS_OUTSIDE_SCOPE == rc) { PMIX_DESTRUCT(&cb); return PMIX_ERR_NOT_FOUND; } /* A local client may send a get request concurrently with * a commit request from another client, but the server may * have processed the commit request earlier than the get * request. In this case, we create a local tracker for * possibly existing keys that are added with the completed * commit request. Thus, the get request will be pended in * tracker and will be deferred. This scenario is possible * when the non-fence commit-get scheme is used and when * the peer GDS component is `dstore`. * Checking the peer storage for local keys to avoid creating * a local tracker for existing keys. */ if ((PMIX_SUCCESS != rc) && local) { PMIX_GDS_FETCH_KV(rc, cd->peer, &cb); if (PMIX_SUCCESS == rc) { cbfunc(rc, NULL, 0, cbdata, NULL, NULL); PMIX_DESTRUCT(&cb); return rc; } } PMIX_DESTRUCT(&cb); // does not release info or key /* if the requested key was found, but in a different scope, * then we report this back as there is no point in waiting */ if (PMIX_ERR_EXISTS_OUTSIDE_SCOPE == rc) { return PMIX_ERR_NOT_FOUND; } if (PMIX_SUCCESS != rc) { /* if the target proc is local, then we just need to wait */ if (local) { /* if they provided a timeout, we need to execute it here * as we are not going to pass it upwards for the host * to perform - we default it to 2 sec */ if (0 == tv.tv_sec) { tv.tv_sec = 2; } rc = defer_response(nspace, rank, key, cd, localonly, cbfunc, cbdata, &tv, &lcd); if (PMIX_ERR_NOT_FOUND == rc) { /* just means we created a tracker */ rc = PMIX_SUCCESS; } else if (PMIX_ERR_NOT_AVAILABLE == rc) { /* means they requested "immediate" */ rc = PMIX_ERR_NOT_FOUND; } return rc; } /* otherwise, we need to request the info */ goto request; } /* we did find it, so go ahead and collect the payload */ } else if (PMIX_PEER_IS_EARLIER(pmix_client_globals.myserver, 4, 0, 0)) { PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); rc = get_job_data(nspace, cd, key, &pbkt); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&pbkt); return rc; } /* pass it back */ PMIX_UNLOAD_BUFFER(&pbkt, data, sz); PMIX_DESTRUCT(&pbkt); cbfunc(rc, data, sz, cbdata, relfn, data); return rc; } /* check if the nspace of the requestor is different from * the nspace of the target process */ diffnspace = !PMIX_CHECK_NSPACE(nptr->nspace, cd->peer->info->pname.nspace); if (!scope_given) { if (PMIX_RANK_UNDEF == rank || diffnspace) { scope = PMIX_GLOBAL; } else if (local) { scope = PMIX_LOCAL; } else { scope = PMIX_REMOTE; } } /* since everyone has registered, see if we already have this data */ rc = _satisfy_request(nptr, rank, key, cd, diffnspace, scope, cbfunc, cbdata); if (PMIX_SUCCESS == rc) { /* return success as the satisfy_request function * calls the cbfunc for us, and it will have * released the cbdata object */ return PMIX_SUCCESS; } pmix_output_verbose(2, pmix_server_globals.get_output, "%s:%d DATA NOT FOUND", pmix_globals.myid.nspace, pmix_globals.myid.rank); request: /* setup to handle this remote request, but don't set any timeout as * this might create a race condition with our host if they also * support the timeout */ rc = defer_response(nspace, rank, key, cd, localonly, cbfunc, cbdata, NULL, &lcd); if (PMIX_SUCCESS == rc) { /* we are already waiting for the data - nothing more * for us to do as the function added the new request * to the tracker for us */ return PMIX_SUCCESS; } else if (PMIX_ERR_NOT_AVAILABLE == rc) { /* means they requested "immediate" */ return PMIX_ERR_NOT_FOUND; } /* Getting here means that we didn't already have a request for * for data pending, and so we created a new tracker for this * request. We know the identity of all our local clients, so * if this is one, then we have nothing further to do - we will * fulfill the request once the process commits its data */ if (local) { return PMIX_SUCCESS; } /* this isn't a local client of ours, so we need to ask the host * resource manager server to please get the info for us from * whomever is hosting the target process */ if (NULL != pmix_host_server.direct_modex) { if (NULL != key) { sz = cd->ninfo; PMIX_INFO_CREATE(info, sz + 1); for (n = 0; n < sz; n++) { PMIX_INFO_XFER(&info[n], &cd->info[n]); } PMIX_INFO_LOAD(&info[sz], PMIX_REQUIRED_KEY, key, PMIX_STRING); if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } cd->info = info; cd->ninfo = sz + 1; } rc = pmix_host_server.direct_modex(&lcd->proc, cd->info, cd->ninfo, dmdx_cbfunc, lcd); if (PMIX_SUCCESS != rc) { /* may have a function entry but not support the request */ pmix_list_remove_item(&pmix_server_globals.local_reqs, &lcd->super); PMIX_RELEASE(lcd); } } else { pmix_output_verbose(2, pmix_server_globals.get_output, "%s:%d NO SERVER SUPPORT", pmix_globals.myid.nspace, pmix_globals.myid.rank); /* if we don't have direct modex feature, just respond with "not found" */ pmix_list_remove_item(&pmix_server_globals.local_reqs, &lcd->super); PMIX_RELEASE(lcd); rc = PMIX_ERR_NOT_FOUND; } return rc; } static pmix_status_t create_local_tracker(char nspace[], pmix_rank_t rank, char *key, pmix_info_t info[], size_t ninfo, pmix_modex_cbfunc_t cbfunc, void *cbdata, pmix_dmdx_local_t **ld, pmix_dmdx_request_t **rq) { pmix_dmdx_local_t *lcd, *cd; pmix_dmdx_request_t *req; pmix_status_t rc; size_t n; /* define default */ *ld = NULL; *rq = NULL; /* see if we already have an existing request for data * from this namespace/rank */ lcd = NULL; PMIX_LIST_FOREACH (cd, &pmix_server_globals.local_reqs, pmix_dmdx_local_t) { if (!PMIX_CHECK_NSPACE(nspace, cd->proc.nspace) || rank != cd->proc.rank) { continue; } lcd = cd; break; } if (NULL != lcd) { /* we already have a request, so just track that someone * else wants data from the same target */ rc = PMIX_SUCCESS; // indicates we found an existing request PMIX_RETAIN(lcd); goto complete; } /* we do not have an existing request, so let's create * one and add it to our list */ lcd = PMIX_NEW(pmix_dmdx_local_t); if (NULL == lcd) { return PMIX_ERR_NOMEM; } PMIX_LOAD_PROCID(&lcd->proc, nspace, rank); if (0 < ninfo) { lcd->ninfo = ninfo; PMIX_INFO_CREATE(lcd->info, lcd->ninfo); for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&lcd->info[n], &info[n]); } } pmix_list_append(&pmix_server_globals.local_reqs, &lcd->super); rc = PMIX_ERR_NOT_FOUND; // indicates that we created a new request tracker complete: /* track this specific requester so we return the * data to them */ req = PMIX_NEW(pmix_dmdx_request_t); if (NULL == req) { *ld = lcd; return PMIX_ERR_NOMEM; } if (NULL != key) { req->key = strdup(key); } PMIX_RETAIN(lcd); req->lcd = lcd; req->cbfunc = cbfunc; pmix_list_append(&lcd->loc_reqs, &req->super); /* if provided, the cbdata is always a pmix_server_caddy_t. Since * it will be released by every req when it completes, we have to * up the refcount on it to avoid multiple free's of its contents */ if (NULL != cbdata && 1 < pmix_list_get_size(&lcd->loc_reqs)) { PMIX_RETAIN(cbdata); } req->cbdata = cbdata; *ld = lcd; *rq = req; return rc; } void pmix_pending_nspace_requests(pmix_namespace_t *nptr) { pmix_dmdx_local_t *cd, *cd_next; pmix_status_t rc; /* Now that we know all local ranks, go along request list and ask for remote data * for the non-local ranks, and resolve all pending requests for local procs * that were waiting for registration to complete */ PMIX_LIST_FOREACH_SAFE (cd, cd_next, &pmix_server_globals.local_reqs, pmix_dmdx_local_t) { pmix_rank_info_t *info; bool found = false; if (0 != strncmp(nptr->nspace, cd->proc.nspace, PMIX_MAX_NSLEN)) { continue; } /* If they asked for job level data, then the data was just registered */ if(cd->proc.rank == PMIX_RANK_WILDCARD){ found = true; }else{ PMIX_LIST_FOREACH (info, &nptr->ranks, pmix_rank_info_t) { if (info->pname.rank == cd->proc.rank) { found = true; // we will satisy this request upon commit from new proc break; } } } /* if not found - this is remote process and we need to send * corresponding direct modex request */ if (!found) { rc = PMIX_ERR_NOT_SUPPORTED; if (NULL != pmix_host_server.direct_modex) { rc = pmix_host_server.direct_modex(&cd->proc, cd->info, cd->ninfo, dmdx_cbfunc, cd); } if (PMIX_SUCCESS != rc) { pmix_dmdx_request_t *req, *req_next; PMIX_LIST_FOREACH_SAFE (req, req_next, &cd->loc_reqs, pmix_dmdx_request_t) { req->cbfunc(PMIX_ERR_NOT_FOUND, NULL, 0, req->cbdata, NULL, NULL); pmix_list_remove_item(&cd->loc_reqs, &req->super); PMIX_RELEASE(req); } pmix_list_remove_item(&pmix_server_globals.local_reqs, &cd->super); PMIX_RELEASE(cd); } } } } static pmix_status_t get_job_data(char *nspace, pmix_server_caddy_t *cd, char *key, pmix_buffer_t *pbkt) { pmix_status_t rc; pmix_buffer_t pkt; pmix_proc_t proc; pmix_cb_t cb; pmix_byte_object_t bo; PMIX_LOAD_PROCID(&proc, nspace, PMIX_RANK_WILDCARD); PMIX_CONSTRUCT(&cb, pmix_cb_t); /* this data is requested by a local client, so give the gds the option * of returning a copy of the data, or a pointer to * local storage */ cb.proc = &proc; cb.key = key; cb.scope = PMIX_INTERNAL; cb.copy = false; cb.info = cd->info; cb.ninfo = cd->ninfo; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); cb.info = NULL; cb.ninfo = 0; if (PMIX_SUCCESS == rc) { PMIX_CONSTRUCT(&pkt, pmix_buffer_t); /* assemble the provided data into a byte object */ PMIX_GDS_ASSEMB_KVS_REQ(rc, pmix_globals.mypeer, &proc, &cb.kvs, &pkt, cd); if (rc != PMIX_SUCCESS) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pkt); PMIX_DESTRUCT(&cb); return rc; } if (PMIX_PEER_IS_V1(cd->peer)) { /* if the client is using v1, then it expects the * data returned to it as the rank followed by a byte object containing * a buffer - so we have to do a little gyration */ pmix_buffer_t xfer; PMIX_CONSTRUCT(&xfer, pmix_buffer_t); PMIX_BFROPS_PACK(rc, cd->peer, &xfer, &pkt, 1, PMIX_BUFFER); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pkt); PMIX_DESTRUCT(&xfer); PMIX_DESTRUCT(&cb); return rc; } PMIX_UNLOAD_BUFFER(&xfer, bo.bytes, bo.size); PMIX_DESTRUCT(&xfer); } else { PMIX_UNLOAD_BUFFER(&pkt, bo.bytes, bo.size); } PMIX_DESTRUCT(&pkt); /* pack it for transmission */ PMIX_BFROPS_PACK(rc, cd->peer, pbkt, &bo, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } } PMIX_DESTRUCT(&cb); return PMIX_SUCCESS; } static pmix_status_t _satisfy_request(pmix_namespace_t *nptr, pmix_rank_t rank, char *key, pmix_server_caddy_t *cd, bool diffnspace, pmix_scope_t scope, pmix_modex_cbfunc_t cbfunc, void *cbdata) { pmix_status_t rc; bool found = false; pmix_buffer_t pbkt, pkt; pmix_proc_t proc; pmix_cb_t cb; pmix_byte_object_t bo; char *data = NULL; size_t sz = 0; pmix_output_verbose(2, pmix_server_globals.get_output, "%s:%d SATISFY REQUEST CALLED FOR %s:%d ON SCOPE %s KEY %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, nptr->nspace, rank, PMIx_Scope_string(scope), (NULL == key) ? "NULL" : key); PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); PMIX_LOAD_NSPACE(proc.nspace, nptr->nspace); /* if the rank is WILDCARD or the target is in an nspace different * from the requester, include a copy of the job-level data */ if (PMIX_RANK_WILDCARD == rank || diffnspace) { rc = get_job_data(nptr->nspace, cd, NULL, &pbkt); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&pbkt); return rc; } if (PMIX_RANK_WILDCARD == rank) { // we are done found = true; goto complete; } } proc.rank = rank; PMIX_CONSTRUCT(&cb, pmix_cb_t); /* if they are asking for a reserved key, we only look for * that one specific key. If they are looking for a * non-reserved key - return all non-reserved keys for the * specified proc. We do this as an optimization as we * suspect that a request for one value for a proc will be * followed by requests for additional values */ if (NULL != key && PMIX_CHECK_RESERVED_KEY(key)) { cb.key = key; } cb.proc = &proc; cb.scope = scope; cb.info = cd->info; cb.ninfo = cd->ninfo; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); /* if we didn't find it on my peer, then it isn't found */ if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&cb); goto complete; } cb.info = NULL; cb.ninfo = 0; found = true; PMIX_CONSTRUCT(&pkt, pmix_buffer_t); /* assemble the provided data into a byte object */ if (PMIX_RANK_UNDEF == rank || diffnspace) { PMIX_GDS_ASSEMB_KVS_REQ(rc, pmix_globals.mypeer, &proc, &cb.kvs, &pkt, cd); } else { PMIX_GDS_ASSEMB_KVS_REQ(rc, cd->peer, &proc, &cb.kvs, &pkt, cd); } if (rc != PMIX_SUCCESS) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pkt); PMIX_DESTRUCT(&cb); goto complete; } if (PMIX_PEER_IS_V1(cd->peer)) { /* if the client is using v1, then it expects the * data returned to it in a different order than v2 * - so we have to do a little gyration */ /* pack the rank */ PMIX_BFROPS_PACK(rc, cd->peer, &pbkt, &rank, 1, PMIX_PROC_RANK); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pkt); PMIX_DESTRUCT(&cb); goto complete; } /* now pack the data itself as a buffer */ PMIX_BFROPS_PACK(rc, cd->peer, &pbkt, &pkt, 1, PMIX_BUFFER); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pkt); PMIX_DESTRUCT(&cb); goto complete; } PMIX_DESTRUCT(&pkt); } else { PMIX_UNLOAD_BUFFER(&pkt, bo.bytes, bo.size); PMIX_DESTRUCT(&pkt); /* pack it for transmission */ PMIX_BFROPS_PACK(rc, cd->peer, &pbkt, &bo, 1, PMIX_BYTE_OBJECT); PMIX_BYTE_OBJECT_DESTRUCT(&bo); // data has been copied if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&cb); goto complete; } } PMIX_DESTRUCT(&cb); complete: PMIX_UNLOAD_BUFFER(&pbkt, data, sz); PMIX_DESTRUCT(&pbkt); if (found) { /* pass it back */ cbfunc(rc, data, sz, cbdata, relfn, data); return rc; } return PMIX_ERR_NOT_FOUND; } static void check_req(pmix_namespace_t *nptr, pmix_rank_t rank, pmix_status_t status, pmix_scope_t scope, pmix_dmdx_local_t *ptr) { pmix_dmdx_request_t *req, *rnext; pmix_server_caddy_t scd; bool diffnspace; pmix_status_t rc; char *key; /* if there are no local reqs on this request (e.g., only * one proc requested it and that proc has died), then * just remove the request */ if (0 == pmix_list_get_size(&ptr->loc_reqs)) { return; } /* somebody was interested in this rank */ if (PMIX_SUCCESS != status) { /* if we've got an error for this request - just forward it*/ PMIX_LIST_FOREACH_SAFE(req, rnext, &ptr->loc_reqs, pmix_dmdx_request_t) { req->cbfunc(status, NULL, 0, req->cbdata, NULL, NULL); pmix_list_remove_item(&ptr->loc_reqs, &req->super); PMIX_RELEASE(req); } } else { /* if we've got the blob - try to satisfy requests */ /* run through all the requests for this rank */ /* this info is going back to one of our peers, so provide a server * caddy with our peer in it so the data gets packed correctly */ PMIX_CONSTRUCT(&scd, pmix_server_caddy_t); PMIX_RETAIN(pmix_globals.mypeer); scd.peer = pmix_globals.mypeer; PMIX_LIST_FOREACH_SAFE(req, rnext, &ptr->loc_reqs, pmix_dmdx_request_t) { diffnspace = !PMIX_CHECK_NSPACE(nptr->nspace, req->lcd->proc.nspace); // if the rank is undef, then only ask for the one key - otherwise, // return all keys for that rank. This is an optimization as we // assume if someone asked for one key for a specific rank, they // are likely to ask for more of them if (PMIX_RANK_UNDEF == rank) { key = req->key; } else { key = NULL; } rc = _satisfy_request(nptr, rank, key, &scd, diffnspace, scope, req->cbfunc, req->cbdata); if (PMIX_SUCCESS != rc) { /* if we can't satisfy this particular request (missing key?) */ req->cbfunc(rc, NULL, 0, req->cbdata, NULL, NULL); } pmix_list_remove_item(&ptr->loc_reqs, &req->super); PMIX_RELEASE(req); } PMIX_DESTRUCT(&scd); } } /* Resolve pending requests to this namespace/rank */ pmix_status_t pmix_pending_resolve(pmix_namespace_t *nptr, pmix_rank_t rank, pmix_status_t status, pmix_scope_t scope, pmix_dmdx_local_t *lcd) { pmix_dmdx_local_t *cd, *cdnext; /* find corresponding request (if exists) */ if (NULL == lcd) { PMIX_LIST_FOREACH_SAFE(cd, cdnext, &pmix_server_globals.local_reqs, pmix_dmdx_local_t) { if (!PMIX_CHECK_NSPACE(nptr->nspace, cd->proc.nspace) ) { continue; } if (PMIX_RANK_UNDEF == cd->proc.rank || rank == cd->proc.rank) { check_req(nptr, cd->proc.rank, status, scope, cd); } if (0 == pmix_list_get_size(&cd->loc_reqs)) { pmix_list_remove_item(&pmix_server_globals.local_reqs, &cd->super); PMIX_RELEASE(cd); } } } else { check_req(nptr, rank, status, scope, lcd); if (0 == pmix_list_get_size(&lcd->loc_reqs)) { pmix_list_remove_item(&pmix_server_globals.local_reqs, &lcd->super); PMIX_RELEASE(lcd); } } return PMIX_SUCCESS; } /* process the returned data from the host RM server */ static void _process_dmdx_reply(int sd, short args, void *cbdata) { pmix_dmdx_reply_caddy_t *caddy = (pmix_dmdx_reply_caddy_t *) cbdata; pmix_server_caddy_t *cd; pmix_peer_t *peer; pmix_rank_info_t *rinfo, *rptr; int32_t cnt; pmix_kval_t *kv; pmix_namespace_t *ns, *nptr; pmix_status_t rc; pmix_list_t nspaces; pmix_nspace_caddy_t *nm; pmix_dmdx_request_t *dm; bool found; pmix_buffer_t pbkt; pmix_cb_t cb; PMIX_ACQUIRE_OBJECT(caddy); PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(2, pmix_server_globals.get_output, "[%s:%d] process dmdx reply from %s:%u", __FILE__, __LINE__, caddy->lcd->proc.nspace, caddy->lcd->proc.rank); /* find the nspace object for the proc whose data is being received */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (PMIX_CHECK_NSPACE(caddy->lcd->proc.nspace, ns->nspace)) { nptr = ns; break; } } if (NULL == nptr) { /* We may not have this namespace because there are no local * processes from it running on this host - so just record it * so we know we have the data for any future requests */ nptr = PMIX_NEW(pmix_namespace_t); nptr->nspace = strdup(caddy->lcd->proc.nspace); /* add to the list */ pmix_list_append(&pmix_globals.nspaces, &nptr->super); } /* if the request was successfully satisfied, then store the data. * Although we could immediately * resolve any outstanding requests on our tracking list, we instead * store the data first so we can immediately satisfy any future * requests. Then, rather than duplicate the resolve code here, we * will let the pmix_pending_resolve function go ahead and retrieve * it from the GDS * * NOTE: if the data returned is NULL, then it has already been * stored (e.g., via a register_nspace call in response to a request * for job-level data). For now, we will retrieve it so it can * be stored for each peer */ if (PMIX_SUCCESS == caddy->status) { /* cycle across all outstanding local requests and collect their * unique nspaces so we can store this for each one */ PMIX_CONSTRUCT(&nspaces, pmix_list_t); PMIX_LIST_FOREACH (dm, &caddy->lcd->loc_reqs, pmix_dmdx_request_t) { /* this is a local proc that has requested this data - search * the list of nspace's and see if we already have it */ cd = (pmix_server_caddy_t *) dm->cbdata; found = false; PMIX_LIST_FOREACH (nm, &nspaces, pmix_nspace_caddy_t) { if (PMIX_CHECK_NSPACE(nm->ns->nspace, cd->peer->nptr->nspace)) { found = true; break; } } if (!found) { /* add it */ nm = PMIX_NEW(pmix_nspace_caddy_t); PMIX_RETAIN(cd->peer->nptr); nm->ns = cd->peer->nptr; pmix_list_append(&nspaces, &nm->super); } } /* now go thru each unique nspace and store the data using its * assigned GDS component - note that if the nspace of the requesting * proc is different from the nspace of the proc whose data is being * returned, then we have to store it into our hash tables */ PMIX_LIST_FOREACH (nm, &nspaces, pmix_nspace_caddy_t) { if (NULL == nm->ns->compat.gds || 0 == nm->ns->nlocalprocs || !PMIX_CHECK_NSPACE(nptr->nspace, nm->ns->nspace)) { peer = pmix_globals.mypeer; } else { /* there must be at least one local proc */ rinfo = NULL; PMIX_LIST_FOREACH(rptr, &nm->ns->ranks, pmix_rank_info_t) { if (0 <= rptr->peerid) { rinfo = rptr; break; } } if (NULL == rinfo) { PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND); goto complete; } peer = (pmix_peer_t *) pmix_pointer_array_get_item(&pmix_server_globals.clients, rinfo->peerid); if (NULL == peer) { PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND); goto complete; } } PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); if (NULL == caddy->data) { if (peer != pmix_globals.mypeer) { /* we assume that the data was provided via a call to * register_nspace, so what we need to do now is simply * transfer it across to the individual nspace storage * components */ PMIX_CONSTRUCT(&cb, pmix_cb_t); PMIX_PROC_CREATE(cb.proc, 1); if (NULL == cb.proc) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); PMIX_DESTRUCT(&cb); goto complete; } PMIX_LOAD_PROCID(cb.proc, nm->ns->nspace, PMIX_RANK_WILDCARD); cb.scope = PMIX_INTERNAL; cb.copy = false; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); goto complete; } PMIX_LIST_FOREACH (kv, &cb.kvs, pmix_kval_t) { PMIX_GDS_STORE_KV(rc, peer, &caddy->lcd->proc, PMIX_INTERNAL, kv); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); break; } } PMIX_DESTRUCT(&cb); } } else { PMIX_LOAD_BUFFER(pmix_globals.mypeer, &pbkt, caddy->data, caddy->ndata); /* unpack and store it*/ kv = PMIX_NEW(pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &pbkt, kv, &cnt, PMIX_KVAL); while (PMIX_SUCCESS == rc) { if (caddy->lcd->proc.rank == PMIX_RANK_WILDCARD) { PMIX_GDS_STORE_KV(rc, peer, &caddy->lcd->proc, PMIX_INTERNAL, kv); } else { PMIX_GDS_STORE_KV(rc, peer, &caddy->lcd->proc, PMIX_REMOTE, kv); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); caddy->status = rc; goto complete; } PMIX_RELEASE(kv); kv = PMIX_NEW(pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &pbkt, kv, &cnt, PMIX_KVAL); } PMIX_RELEASE(kv); pbkt.base_ptr = NULL; // protect the data PMIX_DESTRUCT(&pbkt); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); caddy->status = rc; goto complete; } } } PMIX_LIST_DESTRUCT(&nspaces); } complete: /* always execute the callback to avoid having the client hang */ pmix_pending_resolve(nptr, caddy->lcd->proc.rank, caddy->status, PMIX_REMOTE, caddy->lcd); /* now call the release function so the host server * knows it can release the data */ if (NULL != caddy->relcbfunc) { caddy->relcbfunc(caddy->cbdata); } PMIX_RELEASE(caddy); } /* this is the callback function that the host RM server will call * when it gets requested info back from a remote server */ static void dmdx_cbfunc(pmix_status_t status, const char *data, size_t ndata, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_dmdx_reply_caddy_t *caddy; pmix_dmdx_local_t *lcd = (pmix_dmdx_local_t *) cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { if (NULL != release_fn) { release_fn(release_cbdata); } PMIX_RELEASE(lcd); return; } /* because the host RM is calling us from their own thread, we * need to thread-shift into our local progress thread before * accessing any global info */ caddy = PMIX_NEW(pmix_dmdx_reply_caddy_t); caddy->status = status; /* point to the callers cbfunc */ caddy->relcbfunc = release_fn; caddy->cbdata = release_cbdata; /* point to the returned data and our own internal * tracker */ caddy->data = data; caddy->ndata = ndata; caddy->lcd = (pmix_dmdx_local_t *) cbdata; pmix_output_verbose(2, pmix_server_globals.get_output, "[%s:%d] queue dmdx reply for %s:%u", __FILE__, __LINE__, caddy->lcd->proc.nspace, caddy->lcd->proc.rank); PMIX_THREADSHIFT(caddy, _process_dmdx_reply); } static void get_timeout(int sd, short args, void *cbdata) { pmix_dmdx_request_t *req = (pmix_dmdx_request_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(2, pmix_server_globals.get_output, "ALERT: get timeout fired"); /* execute the provided callback function with the error */ if (NULL != req->cbfunc) { req->cbfunc(PMIX_ERR_TIMEOUT, NULL, 0, req->cbdata, NULL, NULL); } req->event_active = false; pmix_list_remove_item(&req->lcd->loc_reqs, &req->super); PMIX_RELEASE(req); } pmix-6.1.1~rc2/src/server/pmix_server.c0000664000175000017500000061416715203536752020320 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Cisco Systems, Inc. All rights reserved * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "pmix_common.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include #include "src/common/pmix_attributes.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/base/pmix_mca_base_vari.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/mca/pgpu/base/base.h" #include "src/mca/pmdl/base/base.h" #include "src/mca/pnet/base/base.h" #include "src/mca/preg/preg.h" #include "src/mca/psensor/base/base.h" #include "src/mca/pstat/base/base.h" #include "src/mca/ptl/base/base.h" #include "src/runtime/pmix_progress_threads.h" #include "src/runtime/pmix_rte.h" #include "src/tool/pmix_tool_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" /* the server also needs access to client operations * as it can, and often does, behave as a client */ #include "pmix_server_ops.h" #include "src/client/pmix_client_ops.h" // global variables pmix_server_globals_t pmix_server_globals = { .nspaces = PMIX_LIST_STATIC_INIT, .clients = PMIX_POINTER_ARRAY_STATIC_INIT, .collectives = PMIX_LIST_STATIC_INIT, .remote_pnd = PMIX_LIST_STATIC_INIT, .local_reqs = PMIX_LIST_STATIC_INIT, .gdata = PMIX_LIST_STATIC_INIT, .genvars = NULL, .events = PMIX_LIST_STATIC_INIT, .iof = PMIX_LIST_STATIC_INIT, .iof_residuals = PMIX_LIST_STATIC_INIT, .psets = PMIX_LIST_STATIC_INIT, .max_iof_cache = 0, .tool_connections_allowed = false, .tmpdir = NULL, .system_tmpdir = NULL, .fence_localonly_opt = false, .get_output = -1, .get_verbose = 0, .connect_output = -1, .connect_verbose = 0, .fence_output = -1, .fence_verbose = 0, .pub_output = -1, .pub_verbose = 0, .spawn_output = -1, .spawn_verbose = 0, .event_output = -1, .event_verbose = 0, .iof_output = -1, .iof_verbose = 0, .base_output = -1, .base_verbose = 0, .group_output = -1, .group_verbose = 0 }; // local variables static pmix_event_t parentdied; static char *security_mode = NULL; static char *bfrops_mode = NULL; static char *gds_mode = NULL; static pid_t mypid; static pmix_proc_t myparent; static void _pdiedcb(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t*)cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_RELEASE(cb); } static void pdiedfn(int fd, short flags, void *arg) { pmix_proc_t keepalive; pmix_cb_t *cb; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(fd, flags, arg); PMIX_LOAD_PROCID(&keepalive, "PMIX_KEEPALIVE_PIPE", PMIX_RANK_UNDEF); /* generate a job-terminated event */ cb = PMIX_NEW(pmix_cb_t); cb->ninfo = 2; PMIX_INFO_CREATE(cb->info, cb->ninfo); PMIX_INFO_LOAD(&cb->info[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&cb->info[1], PMIX_EVENT_AFFECTED_PROC, &keepalive, PMIX_PROC); cb->infocopy = true; // ensure cleanup rc = PMIx_Notify_event(PMIX_ERR_JOB_TERMINATED, &pmix_globals.myid, PMIX_RANGE_PROC_LOCAL, cb->info, cb->ninfo, _pdiedcb, (void*)cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cb); } } static void server_iof_handler(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_peer_t *peer = (pmix_peer_t *) pr; pmix_proc_t source; pmix_iof_channel_t channel; pmix_byte_object_t bo; int32_t cnt; pmix_status_t rc; size_t refid, ninfo = 0; pmix_iof_req_t *req; pmix_info_t *info = NULL; PMIX_HIDE_UNUSED_PARAMS(hdr, cbdata); pmix_output_verbose(2, pmix_server_globals.iof_output, "recvd IOF with %d bytes from %s", (int) buf->bytes_used, PMIX_PNAME_PRINT(&peer->info->pname)); /* if the buffer is empty, they are simply closing the socket */ if (0 == buf->bytes_used) { return; } PMIX_BYTE_OBJECT_CONSTRUCT(&bo); cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &source, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &channel, &cnt, PMIX_IOF_CHANNEL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &refid, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } if (0 < ninfo) { PMIX_INFO_CREATE(info, ninfo); cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &bo, &cnt, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* lookup the handler for this IOF package */ req = (pmix_iof_req_t *) pmix_pointer_array_get_item(&pmix_globals.iof_requests, refid); if (NULL != req && NULL != req->cbfunc) { req->cbfunc(refid, channel, &source, &bo, info, ninfo); } else { /* otherwise, simply write it out to the specified std IO channel */ if (NULL != bo.bytes && 0 < bo.size) { pmix_iof_write_output(&source, channel, &bo); } } cleanup: /* cleanup the memory */ if (0 < ninfo) { PMIX_INFO_FREE(info, ninfo); } PMIX_BYTE_OBJECT_DESTRUCT(&bo); } /* callback to receive job info */ static void job_data(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_status_t rc; char *nspace; int32_t cnt = 1; pmix_cb_t *cb = (pmix_cb_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(pr, hdr); /* unpack the nspace - should be same as our own */ PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &nspace, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); cb->status = PMIX_ERROR; PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); return; } /* decode it */ PMIX_GDS_STORE_JOB_INFO(cb->status, pmix_client_globals.myserver, nspace, buf); cb->status = PMIX_SUCCESS; PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } /* event handler registration callback */ static void evhandler_reg_callbk(pmix_status_t status, size_t evhandler_ref, void *cbdata) { pmix_rshift_caddy_t *cd = (pmix_rshift_caddy_t *) cbdata; PMIX_ACQUIRE_OBJECT(cd); if (PMIX_SUCCESS == status) { cd->status = evhandler_ref; } else { cd->status = status; } PMIX_WAKEUP_THREAD(&cd->lock); } static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { pmix_lock_t *lock = NULL; char *name = NULL; size_t n; pmix_output_verbose(2, pmix_server_globals.base_output, "[%s:%d] DEBUGGER RELEASE RECVD", pmix_globals.myid.nspace, pmix_globals.myid.rank); PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, results, nresults); if (NULL != info) { lock = NULL; for (n = 0; n < ninfo; n++) { if (0 == strncmp(info[n].key, PMIX_EVENT_RETURN_OBJECT, PMIX_MAX_KEYLEN)) { lock = (pmix_lock_t *) info[n].value.data.ptr; } else if (0 == strncmp(info[n].key, PMIX_EVENT_HDLR_NAME, PMIX_MAX_KEYLEN)) { name = info[n].value.data.string; } } /* if the object wasn't returned, then that is an error */ if (NULL == lock) { pmix_output_verbose(2, pmix_server_globals.base_output, "event handler %s failed to return object", (NULL == name) ? "NULL" : name); /* let the event handler progress */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } return; } } if (NULL != lock) { PMIX_WAKEUP_THREAD(lock); } if (NULL != cbfunc) { cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } static pmix_status_t register_singleton(char *name) { char *tmp, *ptr; pmix_namespace_t *nptr; pmix_rank_t rank; pmix_rank_info_t *rinfo; tmp = strdup(name); ptr = strrchr(tmp, '.'); *ptr = '\0'; ++ptr; rank = strtoul(ptr, NULL, 10); nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { free(tmp); return PMIX_ERR_NOMEM; } nptr->nspace = strdup(tmp); nptr->nlocalprocs = 1; nptr->nprocs = 1; pmix_list_append(&pmix_globals.nspaces, &nptr->super); /* add this rank */ rinfo = PMIX_NEW(pmix_rank_info_t); if (NULL == rinfo) { free(tmp); return PMIX_ERR_NOMEM; } rinfo->pname.nspace = strdup(tmp); rinfo->pname.rank = rank; rinfo->realuid = getuid(); rinfo->uid = geteuid(); rinfo->realgid = getgid(); rinfo->gid = getegid(); pmix_list_append(&nptr->ranks, &rinfo->super); nptr->all_registered = true; free(tmp); return PMIX_SUCCESS; } // local functions for connection support pmix_status_t pmix_server_initialize(void) { /* setup the server-specific globals */ PMIX_CONSTRUCT(&pmix_server_globals.clients, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_server_globals.clients, 1, INT_MAX, 1); PMIX_CONSTRUCT(&pmix_server_globals.nspaces, pmix_list_t); PMIX_CONSTRUCT(&pmix_server_globals.collectives, pmix_list_t); PMIX_CONSTRUCT(&pmix_server_globals.remote_pnd, pmix_list_t); PMIX_CONSTRUCT(&pmix_server_globals.local_reqs, pmix_list_t); PMIX_CONSTRUCT(&pmix_server_globals.gdata, pmix_list_t); PMIX_CONSTRUCT(&pmix_server_globals.events, pmix_list_t); PMIX_CONSTRUCT(&pmix_server_globals.iof, pmix_list_t); PMIX_CONSTRUCT(&pmix_server_globals.iof_residuals, pmix_list_t); PMIX_CONSTRUCT(&pmix_server_globals.psets, pmix_list_t); PMIX_CONSTRUCT(&pmix_server_globals.grp_collectives, pmix_list_t); pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server init called"); /* setup the server verbosities */ if (0 < pmix_server_globals.get_verbose) { /* set default output */ pmix_server_globals.get_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_server_globals.get_output, pmix_server_globals.get_verbose); } if (0 < pmix_server_globals.connect_verbose) { /* set default output */ pmix_server_globals.connect_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_server_globals.connect_output, pmix_server_globals.connect_verbose); } if (0 < pmix_server_globals.fence_verbose) { /* set default output */ pmix_server_globals.fence_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_server_globals.fence_output, pmix_server_globals.fence_verbose); } if (0 < pmix_server_globals.pub_verbose) { /* set default output */ pmix_server_globals.pub_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_server_globals.pub_output, \ pmix_server_globals.pub_verbose); } if (0 < pmix_server_globals.spawn_verbose) { /* set default output */ pmix_server_globals.spawn_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_server_globals.spawn_output, pmix_server_globals.spawn_verbose); } if (0 < pmix_server_globals.event_verbose) { /* set default output */ pmix_server_globals.event_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_server_globals.event_output, pmix_server_globals.event_verbose); } if (0 < pmix_server_globals.iof_verbose) { /* set default output */ pmix_server_globals.iof_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_server_globals.iof_output, pmix_server_globals.iof_verbose); } /* setup the base verbosity */ if (0 < pmix_server_globals.base_verbose) { /* set default output */ pmix_server_globals.base_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_server_globals.base_output, pmix_server_globals.base_verbose); } if (0 < pmix_server_globals.group_verbose) { /* set default output */ pmix_server_globals.group_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_server_globals.group_output, pmix_server_globals.group_verbose); } /* get our available security modules */ security_mode = pmix_psec_base_get_available_modules(); /* get our available bfrop modules */ bfrops_mode = pmix_bfrops_base_get_available_modules(); /* get available gds modules */ gds_mode = pmix_gds_base_get_available_modules(); return PMIX_SUCCESS; } PMIX_EXPORT pmix_status_t PMIx_server_init(pmix_server_module_t *module, pmix_info_t info[], size_t ninfo) { pmix_ptl_posted_recv_t *req; pmix_status_t rc; size_t n; bool nspace_given = false, rank_given = false; bool share_topo = false; pmix_info_t ginfo, *iptr, evinfo[3]; char *evar, *nspace = NULL, *suri; pmix_rank_t rank = PMIX_RANK_INVALID; pmix_rank_info_t *rinfo; pmix_proc_type_t ptype = PMIX_PROC_TYPE_STATIC_INIT; pmix_buffer_t *bfr; pmix_cmd_t cmd; pmix_cb_t cb, *cbptr; pmix_lock_t releaselock; pmix_ptl_posted_recv_t *rcv; bool outputio; bool connect_optional = false; bool connect_directed = false; char *singleton = NULL; pmix_data_array_t *mau = NULL; pmix_kval_t *kptr; pmix_rshift_caddy_t *cd; // check if an init has been called if (pmix_atomic_test_and_set(&pmix_globals.init_called)) { // some init function was already called pmix_show_help("help-pmix-runtime.txt", "reentrant-init", true, "PMIx_server_init"); return PMIX_ERR_INIT; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server init called"); /* backward compatibility fix - remove any directive to use * the old usock component so we avoid a warning message */ if (NULL != (evar = getenv("PMIX_MCA_ptl"))) { if (0 == strcmp(evar, "usock")) { /* we cannot support a usock-only environment */ fprintf(stderr, "-------------------------------------------------------------------\n"); fprintf(stderr, "PMIx no longer supports the \"usock\" transport for client-server\n"); fprintf(stderr, "communication. A directive was detected that only allows that mode.\n"); fprintf(stderr, "We cannot continue - please remove that constraint and try again.\n"); fprintf(stderr, "-------------------------------------------------------------------\n"); return PMIX_ERR_INIT; } /* anything else should just be cleared */ pmix_unsetenv("PMIX_MCA_ptl", &environ); } /* init the parent procid to something innocuous */ PMIX_LOAD_PROCID(&myparent, NULL, PMIX_RANK_UNDEF); if (NULL != getenv("PMIX_LAUNCHER_RNDZ_URI") || NULL != getenv("PMIX_KEEPALIVE_PIPE")) { /* we have a parent tool, so default to * letting them output IOF */ outputio = false; } else { outputio = true; } PMIX_SET_PROC_TYPE(&ptype, PMIX_PROC_SERVER); /* setup the function pointers */ if (NULL != module) { pmix_host_server = *module; } if (NULL != info) { for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_GATEWAY)) { if (PMIX_INFO_TRUE(&info[n])) { PMIX_SET_PROC_TYPE(&ptype, PMIX_PROC_GATEWAY); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_SCHEDULER)) { if (PMIX_INFO_TRUE(&info[n])) { PMIX_SET_PROC_TYPE(&ptype, PMIX_PROC_SCHEDULER); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_SYS_CONTROLLER)) { if (PMIX_INFO_TRUE(&info[n])) { PMIX_SET_PROC_TYPE(&ptype, PMIX_PROC_SYS_CTRLR); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_TMPDIR)) { if (NULL != pmix_server_globals.tmpdir) { free(pmix_server_globals.tmpdir); } pmix_server_globals.tmpdir = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SYSTEM_TMPDIR)) { if (NULL != pmix_server_globals.system_tmpdir) { free(pmix_server_globals.system_tmpdir); } pmix_server_globals.system_tmpdir = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_NSPACE)) { nspace = info[n].value.data.string; nspace_given = true; } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_RANK)) { rank = info[n].value.data.rank; rank_given = true; } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_SHARE_TOPOLOGY)) { share_topo = true; } else if (PMIX_CHECK_KEY(&info[n], PMIX_IOF_LOCAL_OUTPUT)) { outputio = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SINGLETON)) { singleton = info[n].value.data.string; } else if (PMIX_CHECK_KEY(&info[n], PMIX_ALLOC_MAU)) { mau = info[n].value.data.darray; } else if (PMIX_CHECK_KEY(&info[n], PMIX_TOOL_CONNECT_OPTIONAL)) { connect_optional = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECT_TO_SYSTEM)) { if (PMIX_INFO_TRUE(&info[n])) { connect_directed = true; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECT_SYSTEM_FIRST)) { if (PMIX_INFO_TRUE(&info[n])) { connect_directed = true; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECT_TO_SCHEDULER)) { if (PMIX_INFO_TRUE(&info[n])) { connect_directed = true; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECT_TO_SYS_CONTROLLER)) { if (PMIX_INFO_TRUE(&info[n])) { connect_directed = true; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECTION_ORDER)) { if (PMIX_INFO_TRUE(&info[n])) { connect_directed = true; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_PIDINFO)) { if (PMIX_INFO_TRUE(&info[n])) { connect_directed = true; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_TOOL_ATTACHMENT_FILE)) { if (PMIX_INFO_TRUE(&info[n])) { connect_directed = true; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_LAUNCHER_RENDEZVOUS_FILE)) { if (PMIX_INFO_TRUE(&info[n])) { connect_directed = true; } } } } if (NULL == pmix_server_globals.tmpdir) { if (NULL == (evar = getenv("PMIX_SERVER_TMPDIR"))) { pmix_server_globals.tmpdir = strdup(pmix_tmp_directory()); } else { pmix_server_globals.tmpdir = strdup(evar); } } if (NULL == pmix_server_globals.system_tmpdir) { if (NULL == (evar = getenv("PMIX_SYSTEM_TMPDIR"))) { pmix_server_globals.system_tmpdir = strdup(pmix_tmp_directory()); } else { pmix_server_globals.system_tmpdir = strdup(evar); } } /* setup the runtime - this init's the globals, * opens and initializes the required frameworks */ if (PMIX_SUCCESS != (rc = pmix_rte_init(ptype.type, info, ninfo, NULL))) { PMIX_ERROR_LOG(rc); return rc; } /* if we were given a keepalive pipe, register an * event to capture the event */ if (NULL != (evar = getenv("PMIX_KEEPALIVE_PIPE"))) { rc = strtol(evar, NULL, 10); pmix_event_set(pmix_globals.evbase, &parentdied, rc, PMIX_EV_READ, pdiedfn, NULL); pmix_event_add(&parentdied, NULL); pmix_unsetenv("PMIX_KEEPALIVE_PIPE", &environ); pmix_fd_set_cloexec(rc); // don't let children inherit this } /* assign our internal bfrops module */ pmix_globals.mypeer->nptr->compat.bfrops = pmix_bfrops_base_assign_module(NULL); if (NULL == pmix_globals.mypeer->nptr->compat.bfrops) { PMIX_ERROR_LOG(rc); return rc; } /* set the buffer type accordingly if we are given any directives */ evar = getenv("PMIX_BFROP_BUFFER_TYPE"); if (NULL == evar) { /* just set to our default */ pmix_globals.mypeer->nptr->compat.type = pmix_bfrops_globals.default_type; } else if (0 == strcmp(evar, "PMIX_BFROP_BUFFER_FULLY_DESC")) { pmix_globals.mypeer->nptr->compat.type = PMIX_BFROP_BUFFER_FULLY_DESC; } else { pmix_globals.mypeer->nptr->compat.type = PMIX_BFROP_BUFFER_NON_DESC; } /* if we were passed directives, use them to guide our selection * of security modules */ evar = getenv("PMIX_SECURITY_MODE"); pmix_globals.mypeer->nptr->compat.psec = pmix_psec_base_assign_module(evar); if (NULL == pmix_globals.mypeer->nptr->compat.psec) { PMIX_ERROR_LOG(rc); return rc; } /* assign our internal gds module */ PMIX_INFO_LOAD(&ginfo, PMIX_GDS_MODULE, "hash", PMIX_STRING); pmix_globals.mypeer->nptr->compat.gds = pmix_gds_base_assign_module(&ginfo, 1); if (NULL == pmix_globals.mypeer->nptr->compat.gds) { PMIX_ERROR_LOG(rc); return rc; } PMIX_INFO_DESTRUCT(&ginfo); /* we are our own server until something else happens */ PMIX_RETAIN(pmix_globals.mypeer); pmix_client_globals.myserver = pmix_globals.mypeer; /* setup the server-specific globals */ if (PMIX_SUCCESS != (rc = pmix_server_initialize())) { PMIX_ERROR_LOG(rc); return rc; } /* setup the IO Forwarding recv */ rcv = PMIX_NEW(pmix_ptl_posted_recv_t); rcv->tag = PMIX_PTL_TAG_IOF; rcv->cbfunc = server_iof_handler; /* add it to the end of the list of recvs */ pmix_list_append(&pmix_ptl_base.posted_recvs, &rcv->super); /* set the default local output flag */ pmix_globals.iof_flags.local_output = outputio; if (nspace_given) { PMIX_LOAD_NSPACE(pmix_globals.myid.nspace, nspace); } else { /* look for our namespace, if one was given */ if (NULL == (evar = getenv("PMIX_SERVER_NAMESPACE"))) { /* use a fake namespace */ PMIX_LOAD_NSPACE(pmix_globals.myid.nspace, "pmix-server"); } else { PMIX_LOAD_NSPACE(pmix_globals.myid.nspace, evar); } } if (rank_given) { pmix_globals.myid.rank = rank; } else { /* look for our rank, if one was given */ mypid = getpid(); if (NULL == (evar = getenv("PMIX_SERVER_RANK"))) { /* use our pid */ pmix_globals.myid.rank = mypid; } else { pmix_globals.myid.rank = strtol(evar, NULL, 10); } } /* copy it into mypeer entries */ if (NULL == pmix_globals.mypeer->info) { rinfo = PMIX_NEW(pmix_rank_info_t); pmix_globals.mypeer->info = rinfo; } else { PMIX_RETAIN(pmix_globals.mypeer->info); rinfo = pmix_globals.mypeer->info; } if (NULL == pmix_globals.mypeer->nptr) { pmix_globals.mypeer->nptr = PMIX_NEW(pmix_namespace_t); /* ensure our own nspace is first on the list */ PMIX_RETAIN(pmix_globals.mypeer->nptr); pmix_list_prepend(&pmix_globals.nspaces, &pmix_globals.mypeer->nptr->super); } pmix_globals.mypeer->nptr->nspace = strdup(pmix_globals.myid.nspace); rinfo->pname.nspace = strdup(pmix_globals.mypeer->nptr->nspace); rinfo->pname.rank = pmix_globals.myid.rank; rinfo->realuid = pmix_globals.realuid; rinfo->uid = pmix_globals.uid; rinfo->realgid = pmix_globals.realgid; rinfo->gid = pmix_globals.gid; pmix_client_globals.myserver->info = pmix_globals.mypeer->info; /* open the pmdl framework and select the active modules for this environment */ rc = pmix_mca_base_framework_open(&pmix_pmdl_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { return rc; } if (PMIX_SUCCESS != (rc = pmix_pmdl_base_select())) { return rc; } /* pass any params read from the default MCA * param files thru the pmdl components so they can * check for their vars and deal with them */ pmix_pmdl.parse_file_envars(&pmix_mca_base_var_file_values); pmix_pmdl.parse_file_envars(&pmix_mca_base_var_override_values); /* open the psensor framework */ rc = pmix_mca_base_framework_open(&pmix_psensor_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { return rc; } if (PMIX_SUCCESS != (rc = pmix_psensor_base_select())) { return rc; } /* if we were started to support a singleton, register it now * so we won't reject it when it connects to us */ if (NULL != singleton) { rc = register_singleton(singleton); if (PMIX_SUCCESS != rc) { return rc; } } /* setup the wildcard recv for inbound messages from clients */ req = PMIX_NEW(pmix_ptl_posted_recv_t); req->tag = UINT32_MAX; req->cbfunc = pmix_server_message_handler; /* add it to the end of the list of recvs */ pmix_list_append(&pmix_ptl_base.posted_recvs, &req->super); /* if we are a gateway, setup our IOF events */ if (PMIX_PEER_IS_GATEWAY(pmix_globals.mypeer)) { /* setup IOF */ PMIX_IOF_SINK_DEFINE(&pmix_client_globals.iof_stdout, &pmix_globals.myid, 1, PMIX_FWD_STDOUT_CHANNEL, pmix_iof_write_handler); PMIX_IOF_SINK_DEFINE(&pmix_client_globals.iof_stderr, &pmix_globals.myid, 2, PMIX_FWD_STDERR_CHANNEL, pmix_iof_write_handler); } /* register our attributes */ if (PMIX_SUCCESS != (rc = pmix_register_server_attrs())) { return rc; } /* if we don't know our topology, we better get it now as we * increasingly rely on it - note that our host will hopefully * have passed it to us so we don't duplicate their storage! */ if (PMIX_SUCCESS != (rc = pmix_hwloc_setup_topology(info, ninfo))) { /* if they told us to share our topology and we cannot do so, * then that is a reportable error */ if (share_topo) { return rc; } } /* open the pnet and pgpu frameworks and select their active modules for this * environment Do this AFTER setting up the topology so the components can * check to see if they have any local assets */ rc = pmix_mca_base_framework_open(&pmix_pnet_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { return rc; } if (PMIX_SUCCESS != (rc = pmix_pnet_base_select())) { return rc; } rc = pmix_mca_base_framework_open(&pmix_pgpu_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { return rc; } if (PMIX_SUCCESS != (rc = pmix_pgpu_base_select())) { return rc; } rc = pmix_mca_base_framework_open(&pmix_pstat_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { return rc; } if (PMIX_SUCCESS != (rc = pmix_pstat_base_select())) { return rc; } /* start listening for connections */ rc = pmix_ptl_base_start_listening(info, ninfo); if (PMIX_SUCCESS != rc) { if (PMIX_ERR_SILENT != rc) { pmix_show_help("help-pmix-server.txt", "listener-thread-start", true); } return PMIX_ERR_INIT; } // if we were given an MAU, save it if (NULL != mau) { PMIX_KVAL_NEW(kptr, PMIX_ALLOC_MAU); kptr->value->type = PMIX_DATA_ARRAY; kptr->value->data.darray = mau; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); PMIX_RELEASE(kptr); // maintain accounting if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } // enable show_help subsystem pmix_atomic_store_int(&pmix_show_help_enabled, 1); /* see if they gave us a rendezvous URI to which we are to call back */ evar = getenv("PMIX_LAUNCHER_RNDZ_URI"); if (NULL != evar) { /* attach to the specified tool so it can * tell us what we are to do */ PMIX_INFO_CREATE(iptr, 3); PMIX_INFO_LOAD(&iptr[0], PMIX_SERVER_URI, evar, PMIX_STRING); rc = 2; // give us two seconds to connect PMIX_INFO_LOAD(&iptr[1], PMIX_TIMEOUT, &rc, PMIX_INT); /* since we are a server and they are a tool, we don't want * them to be our primary server to avoid circular logic */ PMIX_INFO_LOAD(&iptr[2], PMIX_PRIMARY_SERVER, NULL, PMIX_BOOL); cbptr = PMIX_NEW(pmix_cb_t); cbptr->info = iptr; cbptr->ninfo = 3; PMIX_THREADSHIFT(cbptr, pmix_tool_retry_attach); PMIX_WAIT_THREAD(&cbptr->lock); rc = cbptr->status; PMIX_RELEASE(cbptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return PMIX_ERR_UNREACH; } /* save our parent ID */ PMIX_KVAL_NEW(kptr, PMIX_PARENT_ID); kptr->value->type = PMIX_PROC; PMIX_PROC_CREATE(kptr->value->data.proc, 1); PMIx_Proc_load(kptr->value->data.proc, myparent.nspace, myparent.rank); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); PMIX_RELEASE(kptr); // maintain accounting if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* retrieve any job info it has for us */ bfr = PMIX_NEW(pmix_buffer_t); cmd = PMIX_REQ_CMD; PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, bfr, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); return rc; } /* send to the server */ PMIX_CONSTRUCT(&cb, pmix_cb_t); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, bfr, job_data, (void *) &cb); if (PMIX_SUCCESS != rc) { return rc; } /* wait for the data to return */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; PMIX_DESTRUCT(&cb); if (PMIX_SUCCESS != rc) { return rc; } /* restore our original primary server */ cbptr = PMIX_NEW(pmix_cb_t); cbptr->proc = &pmix_globals.myid; PMIX_THREADSHIFT(cbptr, pmix_tool_retry_set); /* wait for completion */ PMIX_WAIT_THREAD(&cbptr->lock); rc = cbptr->status; PMIX_RELEASE(cbptr); if (PMIX_SUCCESS != rc) { return rc; } /* wait for debugger attach here */ /* register for the debugger release notification */ PMIX_CONSTRUCT_LOCK(&releaselock); PMIX_INFO_LOAD(&evinfo[0], PMIX_EVENT_RETURN_OBJECT, &releaselock, PMIX_POINTER); PMIX_INFO_LOAD(&evinfo[1], PMIX_EVENT_HDLR_NAME, "WAIT-FOR-RELEASE", PMIX_STRING); PMIX_INFO_LOAD(&evinfo[2], PMIX_EVENT_ONESHOT, NULL, PMIX_BOOL); pmix_output_verbose(2, pmix_client_globals.event_output, "[%s:%d] WAITING IN INIT FOR RELEASE", pmix_globals.myid.nspace, pmix_globals.myid.rank); cd = PMIX_NEW(pmix_rshift_caddy_t); cd->codes = malloc(sizeof(int)); cd->codes[0] = PMIX_DEBUGGER_RELEASE; cd->ncodes = 1; cd->info = evinfo; cd->ninfo = 3; cd->evhdlr = notification_fn; cd->evregcbfn = evhandler_reg_callbk; cd->cbdata = cd; PMIX_RETAIN(cd); // so pmix_internal_reg_event_hdlr doesn't wind up releasing it PMIX_THREADSHIFT(cd, pmix_internal_reg_event_hdlr); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; PMIX_RELEASE(cd); PMIX_INFO_DESTRUCT(&evinfo[0]); PMIX_INFO_DESTRUCT(&evinfo[1]); PMIX_INFO_DESTRUCT(&evinfo[2]); if (0 > rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT_LOCK(&releaselock); return rc; } /* wait for release to arrive */ PMIX_WAIT_THREAD(&releaselock); PMIX_DESTRUCT_LOCK(&releaselock); } else if (connect_directed) { /* connect to another server, if the info's direct us to */ rc = pmix_ptl.connect_to_peer((struct pmix_peer_t *) pmix_client_globals.myserver, info, ninfo, &suri); if (PMIX_SUCCESS != rc && !connect_optional) { return rc; } /* store the URI for subsequent lookups */ PMIX_KVAL_NEW(kptr, PMIX_SERVER_URI); kptr->value->type = PMIX_STRING; pmix_asprintf(&kptr->value->data.string, "%s.%u;%s", pmix_client_globals.myserver->info->pname.nspace, pmix_client_globals.myserver->info->pname.rank, suri); free(suri); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); PMIX_RELEASE(kptr); // maintain accounting if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } // mark ourselves as initialized pmix_atomic_set_bool(&pmix_globals.initialized); return PMIX_SUCCESS; } PMIX_EXPORT pmix_status_t PMIx_server_finalize(void) { int i; pmix_peer_t *peer; pmix_namespace_t *ns; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } pmix_atomic_unset_bool(&pmix_globals.initialized); pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server finalize called"); /* wait here until all active events have been processed */ PMIx_Progress_thread_stop(NULL, 0); /* flush any residual IOF into their respective channels */ pmix_iof_flush_residuals(); /* flush anything that is still trying to be written out */ pmix_iof_static_dump_output(&pmix_client_globals.iof_stdout); pmix_iof_static_dump_output(&pmix_client_globals.iof_stderr); pmix_ptl_base_stop_listening(); for (i = 0; i < pmix_server_globals.clients.size; i++) { peer = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, i); if (NULL != peer) { /* ensure that we do the specified cleanup - if this is an * abnormal termination, then the peer object may not be * at zero refcount */ pmix_execute_epilog(&peer->epilog); PMIX_RELEASE(peer); } } PMIX_DESTRUCT(&pmix_server_globals.clients); PMIX_LIST_DESTRUCT(&pmix_server_globals.collectives); PMIX_LIST_DESTRUCT(&pmix_server_globals.remote_pnd); PMIX_LIST_DESTRUCT(&pmix_server_globals.local_reqs); PMIX_LIST_DESTRUCT(&pmix_server_globals.gdata); PMIX_LIST_DESTRUCT(&pmix_server_globals.events); // the list will be destructed in rte_finalize, but do the // epilog here PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { /* ensure that we do the specified cleanup - if this is an * abnormal termination, then the nspace object may not be * at zero refcount */ pmix_execute_epilog(&ns->epilog); } PMIX_LIST_DESTRUCT(&pmix_server_globals.iof); PMIX_LIST_DESTRUCT(&pmix_server_globals.iof_residuals); PMIX_LIST_DESTRUCT(&pmix_server_globals.psets); PMIX_LIST_DESTRUCT(&pmix_server_globals.grp_collectives); if (NULL != security_mode) { free(security_mode); } if (NULL != bfrops_mode) { free(bfrops_mode); } if (NULL != gds_mode) { free(gds_mode); } /* close the psensor framework */ (void) pmix_mca_base_framework_close(&pmix_psensor_base_framework); /* close the pnet framework */ (void) pmix_mca_base_framework_close(&pmix_pnet_base_framework); (void) pmix_mca_base_framework_close(&pmix_pgpu_base_framework); (void) pmix_mca_base_framework_close(&pmix_pstat_base_framework); pmix_rte_finalize(); if (NULL != pmix_globals.mypeer) { PMIX_RELEASE(pmix_globals.mypeer); } if (NULL != pmix_server_globals.tmpdir) { free(pmix_server_globals.tmpdir); } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server finalize complete"); /* finalize the class/object system */ pmix_class_finalize(); return PMIX_SUCCESS; } static void opcbfunc(pmix_status_t status, void *cbdata) { pmix_lock_t *lock = (pmix_lock_t *) cbdata; lock->status = status; PMIX_WAKEUP_THREAD(lock); } static void _register_nspace(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_namespace_t *nptr, *tmp; pmix_status_t rc; size_t i, m, ninfo; pmix_info_t *iptr; bool all_def; pmix_server_trkr_t *trk; pmix_namespace_t *ns; pmix_trkr_caddy_t *tcd; pmix_gds_base_module_t *gds; pmix_kval_t *kv; pmix_proc_t proc; PMIX_ACQUIRE_OBJECT(caddy); pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server _register_nspace %s", cd->proc.nspace); PMIX_HIDE_UNUSED_PARAMS(sd, args); /* see if we already have this nspace */ nptr = NULL; PMIX_LIST_FOREACH (tmp, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(tmp->nspace, cd->proc.nspace)) { nptr = tmp; break; } } if (NULL == nptr) { nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { rc = PMIX_ERR_NOMEM; goto release; } nptr->nspace = strdup(cd->proc.nspace); pmix_list_append(&pmix_globals.nspaces, &nptr->super); } if (0 > cd->nlocalprocs) { /* this is just an update, so we store it * in our hash datastore until someone * requests it */ gds = pmix_globals.mypeer->nptr->compat.gds; if (NULL != gds && NULL != gds->store) { for (i=0; i < cd->ninfo; i++) { if (PMIX_CHECK_KEY(&cd->info[i], PMIX_PROC_DATA)) { iptr = (pmix_info_t*)cd->info[i].value.data.darray->array; ninfo = cd->info[i].value.data.darray->size; /* the first position is the rank */ PMIX_LOAD_PROCID(&proc, cd->proc.nspace, iptr[0].value.data.rank); /* get the peer object for this rank */ for (m=1; m < ninfo; m++) { PMIX_KVAL_NEW(kv, iptr[m].key); PMIX_VALUE_XFER(rc, kv->value, &iptr[m].value); rc = gds->store(&proc, PMIX_REMOTE, kv); PMIX_RELEASE(kv); // maintain refcount if (PMIX_SUCCESS != rc) { goto release; } } } else if (PMIX_CHECK_KEY(&cd->info[i], PMIX_GROUP_CONTEXT_ID)) { PMIX_KVAL_NEW(kv, cd->info[i].key); PMIX_VALUE_XFER(rc, kv->value, &cd->info[i].value); gds->store(&proc, PMIX_GLOBAL, kv); PMIX_RELEASE(kv); // maintain refcount if (PMIX_SUCCESS != rc) { goto release; } } else if (PMIX_CHECK_KEY(&cd->info[i], PMIX_JOB_INFO_ARRAY)) { if (nptr->job_info_recvd) { // already have the job-level info for this namespace continue; } // first entry is the nspace, followed by the job info rc = gds->cache_job_info((struct pmix_namespace_t*)nptr, cd->info, cd->ninfo); if (PMIX_SUCCESS != rc) { goto release; } } } } rc = PMIX_SUCCESS; goto release; } nptr->nlocalprocs = cd->nlocalprocs; /* see if we already have everyone */ if (nptr->nlocalprocs == pmix_list_get_size(&nptr->ranks)) { nptr->all_registered = true; } /* check info directives to see if we want to store this info */ for (i = 0; i < cd->ninfo; i++) { if (0 == strcmp(cd->info[i].key, PMIX_REGISTER_NODATA)) { /* nope - so we are done */ rc = PMIX_SUCCESS; goto release; } } /* register nspace for each activate components */ PMIX_GDS_ADD_NSPACE(rc, nptr->nspace, cd->nlocalprocs, cd->info, cd->ninfo); if (PMIX_SUCCESS != rc) { goto release; } /* store this data in our own GDS module - we will retrieve * it later so it can be passed down to the launched procs * once they connect to us and we know what GDS module they * are using */ PMIX_GDS_CACHE_JOB_INFO(rc, pmix_globals.mypeer, nptr, cd->info, cd->ninfo); if (PMIX_SUCCESS != rc) { goto release; } // record that we recvd the job-level info for this namespace nptr->job_info_recvd = true; /* give the programming models a chance to add anything they need */ rc = pmix_pmdl.register_nspace(nptr); if (PMIX_SUCCESS != rc) { goto release; } /* check any pending trackers to see if they are * waiting for us. There is a slight race condition whereby * the host server could have spawned the local client and * it called back into the collective -before- our local event * would fire the register_client callback. Deal with that here. */ all_def = true; PMIX_LIST_FOREACH (trk, &pmix_server_globals.collectives, pmix_server_trkr_t) { /* if this tracker is already complete, then we * don't need to update it */ if (trk->def_complete) { continue; } /* the fact that the tracker is here means that the tracker was * created in response to at least one collective call being received * from a participant. However, not all local participants may have * already called the collective. While the collective created the * tracker, it would not have updated the number of local participants * from this nspace if they specified PMIX_RANK_WILDCARD in the list of * participants since the host hadn't yet called "register_nspace". * Take care of that here */ for (i = 0; i < trk->npcs; i++) { /* since we have to do this search, let's see * if the nspaces are all completely registered */ if (all_def) { /* so far, they have all been defined - check this one */ PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(trk->pcs[i].nspace, ns->nspace)) { if (SIZE_MAX == ns->nlocalprocs || !ns->all_registered) { all_def = false; } break; } } } /* now see if this nspace is the one we just registered */ if (0 != strncmp(trk->pcs[i].nspace, nptr->nspace, PMIX_MAX_NSLEN)) { /* if not, then we really can't say anything more about it as * we have no new information about this nspace */ continue; } /* if this request was for all participants from this nspace, then * we handle this case here */ if (PMIX_RANK_WILDCARD == trk->pcs[i].rank) { trk->nlocal = nptr->nlocalprocs; /* the total number of procs in this nspace was provided * in the data blob delivered to register_nspace, so check * to see if all the procs are local */ if (nptr->nprocs != nptr->nlocalprocs) { trk->local = false; } continue; } } /* update this tracker's status */ trk->def_complete = all_def; /* is this now locally completed? */ if (trk->def_complete && pmix_list_get_size(&trk->local_cbs) == trk->nlocal) { /* it did, so now we need to process it * we don't want to block someone * here, so kick any completed trackers into a * new event for processing */ PMIX_EXECUTE_COLLECTIVE(tcd, trk, pmix_server_execute_collective); } } /* also check any pending local modex requests to see if * someone has been waiting for a request on a remote proc * in one of our nspaces, but we didn't know all the local procs * and so couldn't determine the proc was remote */ pmix_pending_nspace_requests(nptr); rc = PMIX_SUCCESS; release: cd->opcbfunc(rc, cd->cbdata); PMIX_RELEASE(cd); } /* setup the data for a job */ PMIX_EXPORT pmix_status_t PMIx_server_register_nspace(const pmix_nspace_t nspace, int nlocalprocs, pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; pmix_status_t rc; pmix_lock_t mylock; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } cd = PMIX_NEW(pmix_setup_caddy_t); pmix_strncpy(cd->proc.nspace, nspace, PMIX_MAX_NSLEN); cd->nlocalprocs = nlocalprocs; cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* copy across the info array, if given */ if (0 < ninfo) { cd->ninfo = ninfo; cd->info = info; } /* if the provided callback is NULL, then substitute * our own internal cbfunc and block here */ if (NULL == cbfunc) { PMIX_CONSTRUCT_LOCK(&mylock); cd->opcbfunc = opcbfunc; cd->cbdata = &mylock; PMIX_THREADSHIFT(cd, _register_nspace); PMIX_WAIT_THREAD(&mylock); rc = mylock.status; PMIX_DESTRUCT_LOCK(&mylock); if (PMIX_SUCCESS == rc) { rc = PMIX_OPERATION_SUCCEEDED; } return rc; } /* we have to push this into our event library to avoid * potential threading issues */ PMIX_THREADSHIFT(cd, _register_nspace); return PMIX_SUCCESS; } void pmix_server_purge_events(pmix_peer_t *peer, pmix_proc_t *proc) { pmix_regevents_info_t *reginfo, *regnext; pmix_peer_events_info_t *prev, *pnext; pmix_iof_req_t *req; int i; pmix_notify_caddy_t *ncd; size_t n, m, p, ntgs; pmix_proc_t *tgs, *tgt; pmix_dmdx_local_t *dlcd, *dnxt; /* since the client is finalizing, remove them from any event * registrations they may still have on our list */ PMIX_LIST_FOREACH_SAFE (reginfo, regnext, &pmix_server_globals.events, pmix_regevents_info_t) { PMIX_LIST_FOREACH_SAFE (prev, pnext, ®info->peers, pmix_peer_events_info_t) { if ((NULL != peer && prev->peer == peer) || (NULL != proc && NULL != prev->peer->info && PMIX_CHECK_NAMES(proc, &prev->peer->info->pname))) { pmix_list_remove_item(®info->peers, &prev->super); PMIX_RELEASE(prev); if (0 == pmix_list_get_size(®info->peers)) { pmix_list_remove_item(&pmix_server_globals.events, ®info->super); PMIX_RELEASE(reginfo); break; } } } } /* since the client is finalizing, remove them from any IOF * registrations they may still have on our list */ for (i = 0; i < pmix_globals.iof_requests.size; i++) { if (NULL == (req = (pmix_iof_req_t *) pmix_pointer_array_get_item(&pmix_globals.iof_requests, i))) { continue; } /* protect against errors */ if (NULL == req->requestor || NULL == req->requestor->info) { pmix_pointer_array_set_item(&pmix_globals.iof_requests, i, NULL); PMIX_RELEASE(req); continue; } if (NULL != peer && NULL == peer->info) { continue; } if ((NULL != peer && NULL != peer->info && PMIX_CHECK_NAMES(&req->requestor->info->pname, &peer->info->pname)) || (NULL != proc && PMIX_CHECK_NAMES(&req->requestor->info->pname, proc))) { pmix_pointer_array_set_item(&pmix_globals.iof_requests, i, NULL); PMIX_RELEASE(req); } } /* see if this proc is involved in any direct modex requests */ PMIX_LIST_FOREACH_SAFE (dlcd, dnxt, &pmix_server_globals.local_reqs, pmix_dmdx_local_t) { if ((NULL != peer && NULL != peer->info && PMIX_CHECK_NAMES(&peer->info->pname, &dlcd->proc)) || (NULL != proc && PMIX_CHECK_PROCID(proc, &dlcd->proc))) { /* cleanup this request */ pmix_list_remove_item(&pmix_server_globals.local_reqs, &dlcd->super); /* we can release the dlcd item here because we are not * releasing the tracker held by the host - we are only * releasing one item on that tracker */ PMIX_RELEASE(dlcd); } } /* purge this client from any cached notifications */ for (i = 0; i < pmix_globals.max_events; i++) { pmix_hotel_knock(&pmix_globals.notifications, i, (void **) &ncd); if (NULL != ncd && NULL != ncd->targets && 0 < ncd->ntargets) { tgt = NULL; for (n = 0; n < ncd->ntargets; n++) { if ((NULL != peer && NULL != peer->info && PMIX_CHECK_NAMES(&peer->info->pname, &ncd->targets[n])) || (NULL != proc && PMIX_CHECK_PROCID(proc, &ncd->targets[n]))) { tgt = &ncd->targets[n]; break; } } if (NULL != tgt) { /* if this client was the only target, then just * evict the notification */ if (1 == ncd->ntargets) { pmix_hotel_checkout(&pmix_globals.notifications, i); PMIX_RELEASE(ncd); } else if (PMIX_RANK_WILDCARD == tgt->rank && NULL != proc && PMIX_RANK_WILDCARD == proc->rank) { /* we have to remove this target, but leave the rest */ ntgs = ncd->ntargets - 1; PMIX_PROC_CREATE(tgs, ntgs); p = 0; for (m = 0; m < ncd->ntargets; m++) { if (tgt != &ncd->targets[m]) { memcpy(&tgs[p], &ncd->targets[n], sizeof(pmix_proc_t)); ++p; } } PMIX_PROC_FREE(ncd->targets, ncd->ntargets); ncd->targets = tgs; ncd->ntargets = ntgs; } } } } if (NULL != peer) { /* ensure we honor any peer-level epilog requests */ pmix_execute_epilog(&peer->epilog); } } static void remove_client(pmix_namespace_t *nptr, pmix_proc_t *p) { pmix_rank_info_t *info, *inext; pmix_peer_t *peer; pmix_proc_t proc; PMIX_LIST_FOREACH_SAFE(info, inext, &nptr->ranks, pmix_rank_info_t) { if (NULL == p || info->pname.rank == p->rank) { if (NULL == p) { PMIX_LOAD_PROCID(&proc, info->pname.nspace, info->pname.rank); } else { memcpy(&proc, p, sizeof(pmix_proc_t)); } /* if this client failed to call finalize, we still need * to restore any allocations that were given to it */ peer = (pmix_peer_t *) pmix_pointer_array_get_item(&pmix_server_globals.clients, info->peerid); if (NULL == peer) { /* this peer never connected, and hence it won't finalize, * so account for it here */ nptr->nfinalized++; /* even if they never connected, resources were allocated * to them, so we need to ensure they are properly released */ pmix_pnet.child_finalized(&proc); } else { if (!peer->finalized) { /* this peer connected to us, but is being deregistered * without having finalized. This usually means an * abnormal termination that was picked up by * our host prior to our seeing the connection drop. * It is also possible that we missed the dropped * connection, so mark the peer as finalized so * we don't duplicate account for it and take care * of it here */ peer->finalized = true; nptr->nfinalized++; } /* resources may have been allocated to them, so * ensure they get cleaned up - this isn't true * for tools, so don't clean them up */ if (!PMIX_PEER_IS_TOOL(peer)) { pmix_pnet.child_finalized(&proc); pmix_psensor.stop(peer, NULL); } /* honor any registered epilogs */ pmix_execute_epilog(&peer->epilog); /* ensure we close the socket to this peer so we don't * generate "connection lost" events should it be * subsequently "killed" by the host */ CLOSE_THE_SOCKET(peer->sd); // remove it from our client array pmix_pointer_array_set_item(&pmix_server_globals.clients, info->peerid, NULL); PMIX_RELEASE(peer); } if (nptr->nlocalprocs == nptr->nfinalized) { pmix_pnet.local_app_finalized(nptr); } pmix_list_remove_item(&nptr->ranks, &info->super); PMIX_RELEASE(info); if (NULL != p) { break; } } } return; } static void _deregister_nspace(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_namespace_t *tmp, *nptr; pmix_status_t rc; PMIX_ACQUIRE_OBJECT(cd); pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server _deregister_nspace %s", cd->proc.nspace); PMIX_HIDE_UNUSED_PARAMS(sd, args); /* flush anything that is still trying to be written out */ pmix_iof_static_dump_output(&pmix_client_globals.iof_stdout); pmix_iof_static_dump_output(&pmix_client_globals.iof_stderr); /* release any job-level network resources */ pmix_pnet.deregister_nspace(cd->proc.nspace); /* release any programming model info */ pmix_pmdl.deregister_nspace(cd->proc.nspace); /* let our local storage clean up */ PMIX_GDS_DEL_NSPACE(rc, cd->proc.nspace); /* remove any event registrations, IOF registrations, and * cached notifications targeting procs from this nspace */ pmix_server_purge_events(NULL, &cd->proc); // find the nspace object nptr = NULL; PMIX_LIST_FOREACH (tmp, &pmix_globals.nspaces, pmix_namespace_t) { if (PMIX_CHECK_NSPACE(tmp->nspace, cd->proc.nspace)) { nptr = tmp; break; } } if (NULL == nptr) { /* nothing to do */ goto cleanup; } // ensure all local clients have been deregistered remove_client(nptr, NULL); /* perform any epilog */ pmix_execute_epilog(&nptr->epilog); /* remove and release it */ pmix_list_remove_item(&pmix_globals.nspaces, &nptr->super); PMIX_RELEASE(nptr); cleanup: /* release the caller */ cd->opcbfunc(rc, cd->cbdata); PMIX_RELEASE(cd); } PMIX_EXPORT void PMIx_server_deregister_nspace(const pmix_nspace_t nspace, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; pmix_lock_t mylock; pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server deregister nspace %s", nspace); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { if (NULL != cbfunc) { cbfunc(PMIX_ERR_INIT, cbdata); } return; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return; } cd = PMIX_NEW(pmix_setup_caddy_t); PMIX_LOAD_PROCID(&cd->proc, nspace, PMIX_RANK_WILDCARD); cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* if the provided callback is NULL, then substitute * our own internal cbfunc and block here */ if (NULL == cbfunc) { PMIX_CONSTRUCT_LOCK(&mylock); cd->opcbfunc = opcbfunc; cd->cbdata = &mylock; PMIX_THREADSHIFT(cd, _deregister_nspace); PMIX_WAIT_THREAD(&mylock); PMIX_DESTRUCT_LOCK(&mylock); return; } /* we have to push this into our event library to avoid * potential threading issues */ PMIX_THREADSHIFT(cd, _deregister_nspace); } static void _register_resources(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_kval_t *kv=NULL, kp; size_t n, m, ctxid; pmix_status_t rc = PMIX_SUCCESS; bool gotctxid = false; pmix_list_t grpinfo, endpts; pmix_info_caddy_t *ept=NULL, *g=NULL; pmix_info_t *iptr, *pinfo; size_t ninfo, npinfo; pmix_byte_object_t *pbo=NULL, bo; pmix_buffer_t jobinfo, bkt; int32_t cnt; char *nspace; pmix_proc_t *proc; pmix_scope_t scope; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_CONSTRUCT(&grpinfo, pmix_list_t); PMIX_CONSTRUCT(&endpts, pmix_list_t); for (n = 0; n < cd->ninfo; n++) { if (PMIX_CHECK_KEY(&cd->info[n], PMIX_GROUP_INFO_ARRAY) || PMIX_CHECK_KEY(&cd->info[n], PMIX_GROUP_INFO)) { g = PMIX_NEW(pmix_info_caddy_t); g->info = &cd->info[n]; pmix_list_append(&grpinfo, &g->super); } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_GROUP_ENDPT_DATA)) { ept = PMIX_NEW(pmix_info_caddy_t); ept->info = &cd->info[n]; ept->ninfo = 1; pmix_list_append(&endpts, &ept->super); } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_GROUP_CONTEXT_ID)) { rc = PMIx_Value_get_number(&cd->info[n].value, &ctxid, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } else { gotctxid = true; } } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_GROUP_JOB_INFO)) { pbo = (pmix_byte_object_t*)&cd->info[n].value.data.bo; } else { /* add any provided data to our global cache for all nspaces */ kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(cd->info[n].key); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_XFER(rc, kv->value, &cd->info[n].value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kv); break; } pmix_list_append(&pmix_server_globals.gdata, &kv->super); } } /* if endpt data was provided, then we need to * store it in our hash table */ if (0 < pmix_list_get_size(&endpts)) { /* Each list member points to a pmix_info_t that contains * a data array of info about that proc */ PMIX_LIST_FOREACH(ept, &endpts, pmix_info_caddy_t) { // contains an array of proc info pinfo = (pmix_info_t*)ept->info->value.data.darray->array; npinfo = ept->info->value.data.darray->size; // procID is in the first position proc = pinfo[0].value.data.proc; // scope is in the second position scope = pinfo[1].value.data.scope; // rest of the array contains endpts for (m=2; m < npinfo; m++) { kp.key = pinfo[m].key; kp.value = &pinfo[m].value; rc = pmix_globals.mypeer->nptr->compat.gds->store(proc, scope, &kp); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); continue; } } } } // if group info was provided, then we need to store it // in our hash table too if (0 < pmix_list_get_size(&grpinfo)) { // must have been given a context ID if (!gotctxid) { rc = PMIX_ERR_BAD_PARAM; goto release; } /* Each list member points to a pmix_info_t that contains * a data array of info from a given proc */ PMIX_LIST_FOREACH(g, &grpinfo, pmix_info_caddy_t) { iptr = (pmix_info_t*)g->info->value.data.darray->array; ninfo = g->info->value.data.darray->size; if (PMIX_CHECK_KEY(g->info, PMIX_GROUP_INFO)) { // this is just a single array of group info rc = pmix_server_process_grpinfo(ctxid, iptr, ninfo); if (PMIX_SUCCESS != rc) { goto release; } } else { // contains an array of group info arrays for (n=0; n < ninfo; n++) { pinfo = (pmix_info_t*)iptr[n].value.data.darray->array; npinfo = iptr[n].value.data.darray->size; rc = pmix_server_process_grpinfo(ctxid, pinfo, npinfo); if (PMIX_SUCCESS != rc) { goto release; } } } } } // if job info was provided, process it if (NULL != pbo) { /* load it for unpacking */ PMIX_CONSTRUCT(&jobinfo, pmix_buffer_t); PMIX_LOAD_BUFFER(pmix_globals.mypeer, &jobinfo, pbo->bytes, pbo->size); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &jobinfo, &bo, &cnt, PMIX_BYTE_OBJECT); while (PMIX_SUCCESS == rc) { /* load it for unpacking */ PMIX_CONSTRUCT(&bkt, pmix_buffer_t); PMIX_LOAD_BUFFER(pmix_globals.mypeer, &bkt, bo.bytes, bo.size); /* unpack the nspace for this blob */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &nspace, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&bkt); continue; } /* extract and process any proc-related info for this nspace */ PMIX_GDS_STORE_JOB_INFO(rc, pmix_globals.mypeer, nspace, &bkt); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } free(nspace); PMIX_DESTRUCT(&bkt); /* get the next one */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, &jobinfo, &bo, &cnt, PMIX_BYTE_OBJECT); } if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); } } release: cd->opcbfunc(rc, cd->cbdata); PMIX_RELEASE(cd); } pmix_status_t PMIx_server_register_resources(pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; pmix_lock_t mylock; pmix_status_t rc; pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server register resources"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } cd = PMIX_NEW(pmix_setup_caddy_t); cd->info = info; cd->ninfo = ninfo; cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* if the provided callback is NULL, then substitute * our own internal cbfunc and block here */ if (NULL == cbfunc) { PMIX_CONSTRUCT_LOCK(&mylock); cd->opcbfunc = opcbfunc; cd->cbdata = &mylock; PMIX_THREADSHIFT(cd, _register_resources); PMIX_WAIT_THREAD(&mylock); rc = mylock.status; if (PMIX_SUCCESS == rc) { rc = PMIX_OPERATION_SUCCEEDED; } PMIX_DESTRUCT_LOCK(&mylock); return rc; } /* we have to push this into our event library to avoid * potential threading issues */ PMIX_THREADSHIFT(cd, _register_resources); return PMIX_SUCCESS; } static void _deregister_resources(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_kval_t *kv; size_t n; PMIX_HIDE_UNUSED_PARAMS(sd, args); /* find any matches in our global cache and remove them */ for (n = 0; n < cd->ninfo; n++) { PMIX_LIST_FOREACH (kv, &pmix_server_globals.gdata, pmix_kval_t) { if (PMIX_CHECK_KEY(kv, cd->info[n].key)) { pmix_list_remove_item(&pmix_server_globals.gdata, &kv->super); PMIX_RELEASE(kv); break; } } } cd->opcbfunc(PMIX_SUCCESS, cd->cbdata); PMIX_RELEASE(cd); } pmix_status_t PMIx_server_deregister_resources(pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; pmix_lock_t mylock; pmix_status_t rc; pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server deregister resources"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } cd = PMIX_NEW(pmix_setup_caddy_t); cd->info = info; cd->ninfo = ninfo; cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* if the provided callback is NULL, then substitute * our own internal cbfunc and block here */ if (NULL == cbfunc) { PMIX_CONSTRUCT_LOCK(&mylock); cd->opcbfunc = opcbfunc; cd->cbdata = &mylock; PMIX_THREADSHIFT(cd, _deregister_resources); PMIX_WAIT_THREAD(&mylock); rc = mylock.status; if (PMIX_SUCCESS == rc) { rc = PMIX_OPERATION_SUCCEEDED; } PMIX_DESTRUCT_LOCK(&mylock); return rc; } /* we have to push this into our event library to avoid * potential threading issues */ PMIX_THREADSHIFT(cd, _deregister_resources); return PMIX_SUCCESS; } void pmix_server_execute_collective(int sd, short args, void *cbdata) { pmix_trkr_caddy_t *tcd = (pmix_trkr_caddy_t *) cbdata; pmix_server_trkr_t *trk = tcd->trk; pmix_server_caddy_t *cd; pmix_peer_t *peer; char *data = NULL; size_t sz = 0; pmix_byte_object_t bo; pmix_buffer_t bucket, pbkt; pmix_kval_t *kv; pmix_proc_t proc; bool first; pmix_status_t rc; pmix_list_t pnames; pmix_namelist_t *pn; bool found; pmix_cb_t cb; PMIX_ACQUIRE_OBJECT(tcd); PMIX_HIDE_UNUSED_PARAMS(sd, args); /* we don't need to check for non-NULL APIs here as * that was already done when the tracker was created */ if (PMIX_FENCENB_CMD == trk->type) { /* if the user asked us to collect data, then we have * to provide any locally collected data to the host * server so they can circulate it - only take data * from the specified procs as not everyone is necessarily * participating! And only take data intended for remote * distribution as local data will be added when we send * the result to our local clients */ if (trk->hybrid) { /* if this is a hybrid, then we pack everything using * the daemon-level bfrops module as each daemon is * going to have to unpack it, and then repack it for * each participant. */ peer = pmix_globals.mypeer; } else { /* in some error situations, the list of local callbacks can * be empty - if that happens, we just need to call the fence * function to prevent others from hanging */ if (0 == pmix_list_get_size(&trk->local_cbs)) { pmix_host_server.fence_nb(trk->pcs, trk->npcs, trk->info, trk->ninfo, data, sz, trk->modexcbfunc, trk); PMIX_RELEASE(tcd); return; } /* since all procs are the same, just use the first proc's module */ cd = (pmix_server_caddy_t *) pmix_list_get_first(&trk->local_cbs); peer = cd->peer; } PMIX_CONSTRUCT(&bucket, pmix_buffer_t); unsigned char tmp = (unsigned char) trk->collect_type; PMIX_BFROPS_PACK(rc, peer, &bucket, &tmp, 1, PMIX_BYTE); if (PMIX_COLLECT_YES == trk->collect_type) { pmix_output_verbose(2, pmix_server_globals.base_output, "fence - assembling data"); first = true; PMIX_CONSTRUCT(&pnames, pmix_list_t); PMIX_LIST_FOREACH (cd, &trk->local_cbs, pmix_server_caddy_t) { /* see if we have already gotten the contribution from * this proc */ found = false; PMIX_LIST_FOREACH (pn, &pnames, pmix_namelist_t) { if (pn->pname == &cd->peer->info->pname) { /* got it */ found = true; break; } } if (found) { continue; } else { pn = PMIX_NEW(pmix_namelist_t); pn->pname = &cd->peer->info->pname; } if (trk->hybrid || first) { /* setup the nspace */ pmix_strncpy(proc.nspace, cd->peer->info->pname.nspace, PMIX_MAX_NSLEN); first = false; } proc.rank = cd->peer->info->pname.rank; /* get any remote contribution - note that there * may not be a contribution */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &proc; cb.scope = PMIX_REMOTE; cb.copy = true; PMIX_GDS_FETCH_KV(rc, peer, &cb); if (PMIX_SUCCESS == rc) { /* pack the returned kvals */ PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); /* start with the proc id */ PMIX_BFROPS_PACK(rc, peer, &pbkt, &proc, 1, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&bucket); return; } PMIX_LIST_FOREACH (kv, &cb.kvs, pmix_kval_t) { PMIX_BFROPS_PACK(rc, peer, &pbkt, kv, 1, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&bucket); return; } } /* extract the resulting byte object */ PMIX_UNLOAD_BUFFER(&pbkt, bo.bytes, bo.size); PMIX_DESTRUCT(&pbkt); /* now pack that into the bucket for return */ PMIX_BFROPS_PACK(rc, peer, &bucket, &bo, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); PMIX_BYTE_OBJECT_DESTRUCT(&bo); PMIX_DESTRUCT(&bucket); PMIX_RELEASE(tcd); return; } } PMIX_DESTRUCT(&cb); } PMIX_LIST_DESTRUCT(&pnames); } PMIX_UNLOAD_BUFFER(&bucket, data, sz); PMIX_DESTRUCT(&bucket); pmix_host_server.fence_nb(trk->pcs, trk->npcs, trk->info, trk->ninfo, data, sz, trk->modexcbfunc, trk); } else if (PMIX_CONNECTNB_CMD == trk->type) { pmix_host_server.connect(trk->pcs, trk->npcs, trk->info, trk->ninfo, trk->op_cbfunc, trk); } else if (PMIX_DISCONNECTNB_CMD == trk->type) { pmix_host_server.disconnect(trk->pcs, trk->npcs, trk->info, trk->ninfo, trk->op_cbfunc, trk); } else { /* unknown type */ PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND); pmix_list_remove_item(&pmix_server_globals.collectives, &trk->super); PMIX_RELEASE(trk); } PMIX_RELEASE(tcd); } static void _register_client(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_rank_info_t *info; pmix_namespace_t *nptr, *ns; pmix_server_trkr_t *trk; pmix_trkr_caddy_t *tcd; bool all_def; size_t i; pmix_status_t rc; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server _register_client for nspace %s rank %d %s object", cd->proc.nspace, cd->proc.rank, (NULL == cd->server_object) ? "NULL" : "NON-NULL"); /* see if we already have this nspace */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(ns->nspace, cd->proc.nspace)) { nptr = ns; break; } } if (NULL == nptr) { /* there is no requirement in the Standard that hosts register * an nspace prior to registering clients for that nspace. So * if we didn't find it, just add it to our collection now in * anticipation of eventually getting a "register_nspace" call */ nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { rc = PMIX_ERR_NOMEM; goto cleanup; } nptr->nspace = strdup(cd->proc.nspace); pmix_list_append(&pmix_globals.nspaces, &nptr->super); } /* setup a peer object for this client - since the host server * only deals with the original processes and not any clones, * we know this function will be called only once per rank */ info = PMIX_NEW(pmix_rank_info_t); if (NULL == info) { rc = PMIX_ERR_NOMEM; goto cleanup; } info->pname.nspace = strdup(nptr->nspace); info->pname.rank = cd->proc.rank; info->uid = cd->uid; info->gid = cd->gid; info->server_object = cd->server_object; pmix_list_append(&nptr->ranks, &info->super); /* see if we have everyone - note that nlocalprocs is set to * a default value to ensure we don't execute this * test until the host calls "register_nspace" */ if (SIZE_MAX != nptr->nlocalprocs && nptr->nlocalprocs == pmix_list_get_size(&nptr->ranks)) { nptr->all_registered = true; /* check any pending trackers to see if they are * waiting for us. There is a slight race condition whereby * the host server could have spawned the local client and * it called back into the collective -before- our local event * would fire the register_client callback. Deal with that here. */ all_def = true; PMIX_LIST_FOREACH (trk, &pmix_server_globals.collectives, pmix_server_trkr_t) { /* if this tracker is already complete, then we * don't need to update it */ if (trk->def_complete) { continue; } /* the fact that the tracker is here means that the tracker was * created in response to at least one collective call being received * from a participant. However, not all local participants may have * already called the collective. While the collective created the * tracker, it would not have updated the number of local participants * from this nspace UNLESS the collective involves all procs in the * nspace (i.e., they specified PMIX_RANK_WILDCARD in the list of * participants) AND the host already provided the number of local * procs for this nspace by calling "register_nspace". So avoid that * scenario here to avoid double-counting */ for (i = 0; i < trk->npcs; i++) { /* since we have to do this search, let's see * if the nspaces are all completely registered */ if (all_def) { /* so far, they have all been defined - check this one */ PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(trk->pcs[i].nspace, ns->nspace)) { if (SIZE_MAX == ns->nlocalprocs || !ns->all_registered) { all_def = false; } break; } } } /* now see if this nspace is the one to which the client we just * registered belongs */ if (0 != strncmp(trk->pcs[i].nspace, nptr->nspace, PMIX_MAX_NSLEN)) { /* if not, then we really can't say anything more about it as * we have no new information about this nspace */ continue; } /* if this request was for all participants from this nspace, then * we handle this case elsewhere */ if (PMIX_RANK_WILDCARD == trk->pcs[i].rank) { continue; } /* see if the rank we just registered is a participant */ if (cd->proc.rank == trk->pcs[i].rank) { /* yes, we are included */ ++trk->nlocal; } } /* update this tracker's status */ trk->def_complete = all_def; /* is this now locally completed? */ if (trk->def_complete && pmix_list_get_size(&trk->local_cbs) == trk->nlocal) { /* it did, so now we need to process it * we don't want to block someone * here, so kick any completed trackers into a * new event for processing */ PMIX_EXECUTE_COLLECTIVE(tcd, trk, pmix_server_execute_collective); } } /* also check any pending local modex requests to see if * someone has been waiting for a request on a remote proc * in one of our nspaces, but we didn't know all the local procs * and so couldn't determine the proc was remote */ pmix_pending_nspace_requests(nptr); } rc = PMIX_SUCCESS; cleanup: /* let the caller know we are done */ cd->opcbfunc(rc, cd->cbdata); PMIX_RELEASE(cd); } PMIX_EXPORT pmix_status_t PMIx_server_register_client(const pmix_proc_t *proc, uid_t uid, gid_t gid, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; pmix_status_t rc; pmix_lock_t mylock; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server register client %s:%d", proc->nspace, proc->rank); cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } pmix_strncpy(cd->proc.nspace, proc->nspace, PMIX_MAX_NSLEN); cd->proc.rank = proc->rank; cd->uid = uid; cd->gid = gid; cd->server_object = server_object; cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* if the provided callback is NULL, then substitute * our own internal cbfunc and block here */ if (NULL == cbfunc) { PMIX_CONSTRUCT_LOCK(&mylock); cd->opcbfunc = opcbfunc; cd->cbdata = &mylock; PMIX_THREADSHIFT(cd, _register_client); PMIX_WAIT_THREAD(&mylock); rc = mylock.status; PMIX_DESTRUCT_LOCK(&mylock); if (PMIX_SUCCESS == rc) { rc = PMIX_OPERATION_SUCCEEDED; } return rc; } /* we have to push this into our event library to avoid * potential threading issues */ PMIX_THREADSHIFT(cd, _register_client); return PMIX_SUCCESS; } static void _deregister_client(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_namespace_t *nptr, *tmp; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server _deregister_client for nspace %s rank %d", cd->proc.nspace, cd->proc.rank); /* see if we already have this nspace */ nptr = NULL; PMIX_LIST_FOREACH (tmp, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(tmp->nspace, cd->proc.nspace)) { nptr = tmp; break; } } if (NULL == nptr) { /* nothing to do */ goto cleanup; } /* find and remove this client */ remove_client(nptr, &cd->proc); cleanup: cd->opcbfunc(PMIX_SUCCESS, cd->cbdata); PMIX_RELEASE(cd); } PMIX_EXPORT void PMIx_server_deregister_client(const pmix_proc_t *proc, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; pmix_lock_t mylock; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { if (NULL != cbfunc) { cbfunc(PMIX_ERR_INIT, cbdata); } return; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server deregister client %s:%d", proc->nspace, proc->rank); cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { if (NULL != cbfunc) { cbfunc(PMIX_ERR_NOMEM, cbdata); } return; } pmix_strncpy(cd->proc.nspace, proc->nspace, PMIX_MAX_NSLEN); cd->proc.rank = proc->rank; cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* if the provided callback is NULL, then substitute * our own internal cbfunc and block here */ if (NULL == cbfunc) { PMIX_CONSTRUCT_LOCK(&mylock); cd->opcbfunc = opcbfunc; cd->cbdata = &mylock; PMIX_THREADSHIFT(cd, _deregister_client); PMIX_WAIT_THREAD(&mylock); PMIX_DESTRUCT_LOCK(&mylock); return; } /* we have to push this into our event library to avoid * potential threading issues */ PMIX_THREADSHIFT(cd, _deregister_client); } /* setup the envars for a child process */ PMIX_EXPORT pmix_status_t PMIx_server_setup_fork(const pmix_proc_t *proc, char ***env) { char rankstr[128]; pmix_listener_t *lt; pmix_status_t rc; char **varnames; int n; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:server setup_fork for nspace %s rank %u", proc->nspace, proc->rank); /* pass the nspace */ PMIx_Setenv("PMIX_NAMESPACE", proc->nspace, true, env); /* pass the rank */ (void) pmix_snprintf(rankstr, 127, "%u", proc->rank); PMIx_Setenv("PMIX_RANK", rankstr, true, env); /* pass our rendezvous info */ lt = &pmix_ptl_base.listener; if (NULL != lt->uri && NULL != lt->varname) { varnames = PMIx_Argv_split(lt->varname, ':'); for (n = 0; NULL != varnames[n]; n++) { PMIx_Setenv(varnames[n], lt->uri, true, env); } PMIx_Argv_free(varnames); } /* pass our active security modules */ PMIx_Setenv("PMIX_SECURITY_MODE", security_mode, true, env); /* pass the type of buffer we are using */ if (PMIX_BFROP_BUFFER_FULLY_DESC == pmix_globals.mypeer->nptr->compat.type) { PMIx_Setenv("PMIX_BFROP_BUFFER_TYPE", "PMIX_BFROP_BUFFER_FULLY_DESC", true, env); } else { PMIx_Setenv("PMIX_BFROP_BUFFER_TYPE", "PMIX_BFROP_BUFFER_NON_DESC", true, env); } /* pass our available gds modules */ PMIx_Setenv("PMIX_GDS_MODULE", gds_mode, true, env); /* get any PTL contribution such as tmpdir settings for session files */ if (PMIX_SUCCESS != (rc = pmix_ptl_base_setup_fork(proc, env))) { PMIX_ERROR_LOG(rc); return rc; } /* get any network contribution */ if (PMIX_SUCCESS != (rc = pmix_pnet.setup_fork(proc, env))) { PMIX_ERROR_LOG(rc); return rc; } /* get any GDS contributions */ if (PMIX_SUCCESS != (rc = pmix_gds_base_setup_fork(proc, env))) { PMIX_ERROR_LOG(rc); return rc; } /* get any contribution for the specific programming * model/implementation, if known */ if (PMIX_SUCCESS != (rc = pmix_pmdl.setup_fork(proc, env))) { PMIX_ERROR_LOG(rc); return rc; } /* ensure we agree on our hostname */ PMIx_Setenv("PMIX_HOSTNAME", pmix_globals.hostname, true, env); /* communicate our version */ PMIx_Setenv("PMIX_VERSION", PMIX_VERSION, true, env); /* pass any global contributions */ if (NULL != pmix_server_globals.genvars) { for (n = 0; NULL != pmix_server_globals.genvars[n]; n++) { PMIx_Argv_append_nosize(env, pmix_server_globals.genvars[n]); } } return PMIX_SUCCESS; } /*************************************************************************************************** * Support calls from the host server down to us requesting direct modex data provided by one * * of our local clients * ***************************************************************************************************/ static void _dmodex_req(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_rank_info_t *info, *iptr; pmix_namespace_t *nptr, *ns; char *data = NULL; size_t sz = 0; pmix_dmdx_remote_t *dcd; pmix_status_t rc; pmix_buffer_t pbkt; pmix_kval_t *kv; pmix_cb_t cb; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(2, pmix_server_globals.base_output, "DMODX LOOKING FOR %s", PMIX_NAME_PRINT(&cd->proc)); /* this should be one of my clients, but a race condition * could cause this request to arrive prior to us having * been informed of it - so first check to see if we know * about this nspace yet */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(ns->nspace, cd->proc.nspace)) { nptr = ns; break; } } if (NULL == nptr) { /* we don't know this namespace yet, and so we obviously * haven't received the data from this proc yet - defer * the request until we do */ dcd = PMIX_NEW(pmix_dmdx_remote_t); if (NULL == dcd) { rc = PMIX_ERR_NOMEM; goto cleanup; } dcd->cd = cd; pmix_list_append(&pmix_server_globals.remote_pnd, &dcd->super); return; } /* They are asking for job level data for this process */ if (PMIX_RANK_WILDCARD == cd->proc.rank) { /* fetch the job-level info for this nspace */ /* this is going to a remote peer, so inform the gds * that we need an actual copy of the data */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &cd->proc; cb.scope = PMIX_REMOTE; cb.copy = true; PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS == rc) { /* assemble the provided data into a byte object */ PMIX_LIST_FOREACH (kv, &cb.kvs, pmix_kval_t) { PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &pbkt, kv, 1, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&cb); goto cleanup; } } } PMIX_DESTRUCT(&cb); PMIX_UNLOAD_BUFFER(&pbkt, data, sz); PMIX_DESTRUCT(&pbkt); goto cleanup; } /* see if we have this peer in our list */ info = NULL; PMIX_LIST_FOREACH (iptr, &nptr->ranks, pmix_rank_info_t) { if (iptr->pname.rank == cd->proc.rank) { info = iptr; break; } } if (NULL == info) { /* rank isn't known yet - defer * the request until we do */ dcd = PMIX_NEW(pmix_dmdx_remote_t); dcd->cd = cd; pmix_list_append(&pmix_server_globals.remote_pnd, &dcd->super); return; } /* have we received the modex from this proc yet - if * not, then defer */ if (!info->modex_recvd) { /* track the request so we can fulfill it once * data is recvd */ dcd = PMIX_NEW(pmix_dmdx_remote_t); dcd->cd = cd; pmix_list_append(&pmix_server_globals.remote_pnd, &dcd->super); return; } /* collect the remote/global data from this proc */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &cd->proc; cb.scope = PMIX_REMOTE; cb.copy = true; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS == rc) { /* assemble the provided data into a byte object */ PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); PMIX_LIST_FOREACH (kv, &cb.kvs, pmix_kval_t) { PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &pbkt, kv, 1, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&cb); goto cleanup; } } PMIX_UNLOAD_BUFFER(&pbkt, data, sz); PMIX_DESTRUCT(&pbkt); } PMIX_DESTRUCT(&cb); cleanup: /* execute the callback */ cd->cbfunc(rc, data, sz, cd->cbdata); if (NULL != data) { free(data); } PMIX_RELEASE(cd); } PMIX_EXPORT pmix_status_t PMIx_server_dmodex_request(const pmix_proc_t *proc, pmix_dmodex_response_fn_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* protect against bozo */ if (NULL == cbfunc || NULL == proc) { return PMIX_ERR_BAD_PARAM; } pmix_output_verbose(2, pmix_server_globals.base_output, "%s pmix:server dmodex request for proc %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_NAME_PRINT(proc)); cd = PMIX_NEW(pmix_setup_caddy_t); pmix_strncpy(cd->proc.nspace, proc->nspace, PMIX_MAX_NSLEN); cd->proc.rank = proc->rank; cd->cbfunc = cbfunc; cd->cbdata = cbdata; /* we have to push this into our event library to avoid * potential threading issues */ PMIX_THREADSHIFT(cd, _dmodex_req); return PMIX_SUCCESS; } static void _store_internal(int sd, short args, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; pmix_proc_t proc; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_strncpy(proc.nspace, cd->pname.nspace, PMIX_MAX_NSLEN); proc.rank = cd->pname.rank; PMIX_GDS_STORE_KV(cd->status, pmix_globals.mypeer, &proc, PMIX_INTERNAL, cd->kv); PMIX_WAKEUP_THREAD(&cd->lock); } PMIX_EXPORT pmix_status_t PMIx_Store_internal(const pmix_proc_t *proc, const char key[], pmix_value_t *val) { pmix_shift_caddy_t *cd; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } if (NULL == key || PMIX_MAX_KEYLEN < pmix_keylen(key)) { return PMIX_ERR_BAD_PARAM; } /* setup to thread shift this request */ cd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } if (NULL == proc) { cd->pname.nspace = strdup(pmix_globals.myid.nspace); cd->pname.rank = pmix_globals.myid.rank; } else { cd->pname.nspace = strdup(proc->nspace); cd->pname.rank = proc->rank; } cd->kv = PMIX_NEW(pmix_kval_t); if (NULL == cd->kv) { PMIX_RELEASE(cd); return PMIX_ERR_NOMEM; } cd->kv->key = strdup(key); cd->kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_BFROPS_VALUE_XFER(rc, pmix_globals.mypeer, cd->kv->value, val); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd); return rc; } PMIX_THREADSHIFT(cd, _store_internal); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; PMIX_RELEASE(cd); return rc; } PMIX_EXPORT pmix_status_t PMIx_generate_regex(const char *input, char **regexp) { if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } return pmix_preg.generate_node_regex(input, regexp); } PMIX_EXPORT pmix_status_t PMIx_generate_ppn(const char *input, char **regexp) { if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } return pmix_preg.generate_ppn(input, regexp); } static void _setup_op(pmix_status_t rc, void *cbdata) { pmix_setup_caddy_t *fcd = (pmix_setup_caddy_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(rc); if (NULL != fcd->info) { PMIX_INFO_FREE(fcd->info, fcd->ninfo); } PMIX_RELEASE(fcd); } static void _setup_app(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_setup_caddy_t *fcd = NULL; pmix_status_t rc; pmix_list_t ilist; pmix_kval_t *kv; size_t n; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_CONSTRUCT(&ilist, pmix_list_t); /* pass to the network libraries */ if (PMIX_SUCCESS != (rc = pmix_pnet.allocate(cd->nspace, cd->info, cd->ninfo, &ilist))) { goto depart; } /* pass to the programming model libraries */ if (PMIX_SUCCESS != (rc = pmix_pmdl.harvest_envars(cd->nspace, cd->info, cd->ninfo, &ilist))) { goto depart; } /* setup the return callback */ fcd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == fcd) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto depart; } /* if anything came back, construct an info array */ if (0 < (fcd->ninfo = pmix_list_get_size(&ilist))) { PMIX_INFO_CREATE(fcd->info, fcd->ninfo); if (NULL == fcd->info) { rc = PMIX_ERR_NOMEM; PMIX_RELEASE(fcd); goto depart; } n = 0; PMIX_LIST_FOREACH (kv, &ilist, pmix_kval_t) { pmix_strncpy(fcd->info[n].key, kv->key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&fcd->info[n].value, kv->value); ++n; } } depart: /* always execute the callback to avoid hanging */ if (NULL != cd->setupcbfunc) { if (NULL == fcd) { cd->setupcbfunc(rc, NULL, 0, cd->cbdata, NULL, NULL); } else { cd->setupcbfunc(rc, fcd->info, fcd->ninfo, cd->cbdata, _setup_op, fcd); } } /* cleanup memory */ PMIX_LIST_DESTRUCT(&ilist); if (NULL != cd->nspace) { free(cd->nspace); } PMIX_RELEASE(cd); } pmix_status_t PMIx_server_setup_application(const pmix_nspace_t nspace, pmix_info_t info[], size_t ninfo, pmix_setup_application_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* need to threadshift this request */ cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } if (NULL != nspace) { cd->nspace = strdup(nspace); } cd->info = info; cd->ninfo = ninfo; cd->setupcbfunc = cbfunc; cd->cbdata = cbdata; PMIX_THREADSHIFT(cd, _setup_app); return PMIX_SUCCESS; } static void _setup_local_support(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_status_t rc; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); /* pass to the network libraries */ rc = pmix_pnet.setup_local_network(cd->nspace, cd->info, cd->ninfo); /* pass the info back */ if (NULL != cd->opcbfunc) { cd->opcbfunc(rc, cd->cbdata); } /* cleanup memory */ if (NULL != cd->nspace) { free(cd->nspace); } PMIX_RELEASE(cd); } pmix_status_t PMIx_server_setup_local_support(const pmix_nspace_t nspace, pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; pmix_status_t rc; pmix_lock_t mylock; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* need to threadshift this request */ cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } if (NULL != nspace) { cd->nspace = strdup(nspace); } cd->info = info; cd->ninfo = ninfo; cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* if the provided callback is NULL, then substitute * our own internal cbfunc and block here */ if (NULL == cbfunc) { PMIX_CONSTRUCT_LOCK(&mylock); cd->opcbfunc = opcbfunc; cd->cbdata = &mylock; PMIX_THREADSHIFT(cd, _setup_local_support); PMIX_WAIT_THREAD(&mylock); rc = mylock.status; PMIX_DESTRUCT_LOCK(&mylock); if (PMIX_SUCCESS == rc) { rc = PMIX_OPERATION_SUCCEEDED; } return rc; } PMIX_THREADSHIFT(cd, _setup_local_support); return PMIX_SUCCESS; } static void _iofdeliver(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_iof_req_t *req; bool found = false; pmix_iof_cache_t *iof; int i; size_t n; pmix_status_t rc; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(2, pmix_server_globals.iof_output, "PMIX:SERVER delivering IOF from %s on channel %s with %d bytes", PMIX_NAME_PRINT(cd->procs), PMIx_IOF_channel_string(cd->channels), (int)cd->bo->size); /* output it locally if requested */ rc = pmix_iof_write_output(cd->procs, cd->channels, cd->bo); if (0 > rc) { goto done; } /* cycle across our list of IOF requests and see who wants * this channel from this source */ for (i = 0; i < pmix_globals.iof_requests.size; i++) { req = (pmix_iof_req_t *) pmix_pointer_array_get_item(&pmix_globals.iof_requests, i); if (NULL == req) { continue; } rc = pmix_iof_process_iof(cd->channels, cd->procs, cd->bo, cd->info, cd->ninfo, req); if (PMIX_OPERATION_SUCCEEDED == rc) { /* flag that we do have at least one registrant for this info, * so there is no need to cache it */ found = true; rc = PMIX_SUCCESS; } } /* if nobody has registered for this yet, then cache it */ if (!found) { pmix_output_verbose(2, pmix_server_globals.iof_output, "PMIx:SERVER caching IOF %d", (int)cd->bo->size); if (pmix_server_globals.max_iof_cache == pmix_list_get_size(&pmix_server_globals.iof)) { /* remove the oldest cached message */ iof = (pmix_iof_cache_t *) pmix_list_remove_first(&pmix_server_globals.iof); if (NULL != iof) { PMIX_RELEASE(iof); } } /* add this output to our cache so it is cached until someone * registers to receive it */ iof = PMIX_NEW(pmix_iof_cache_t); memcpy(&iof->source, cd->procs, sizeof(pmix_proc_t)); iof->channel = cd->channels; /* copy the data */ PMIX_BYTE_OBJECT_CREATE(iof->bo, 1); if (0 < cd->bo->size) { iof->bo->bytes = (char *) malloc(cd->bo->size); memcpy(iof->bo->bytes, cd->bo->bytes, cd->bo->size); } iof->bo->size = cd->bo->size; if (0 < cd->ninfo) { PMIX_INFO_CREATE(iof->info, cd->ninfo); iof->ninfo = cd->ninfo; for (n = 0; n < iof->ninfo; n++) { PMIX_INFO_XFER(&iof->info[n], &cd->info[n]); } } pmix_list_append(&pmix_server_globals.iof, &iof->super); rc = PMIX_SUCCESS; } done: if (NULL != cd->opcbfunc) { cd->opcbfunc(rc, cd->cbdata); } /* release the caddy */ cd->procs = NULL; cd->nprocs = 0; cd->info = NULL; cd->ninfo = 0; cd->bo = NULL; PMIX_RELEASE(cd); } pmix_status_t PMIx_server_IOF_deliver(const pmix_proc_t *source, pmix_iof_channel_t channel, const pmix_byte_object_t *bo, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; pmix_lock_t mylock; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* need to threadshift this request */ cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->procs = (pmix_proc_t *) source; cd->nprocs = 1; cd->channels = channel; cd->bo = (pmix_byte_object_t *) bo; cd->info = (pmix_info_t *) info; cd->ninfo = ninfo; cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* if the provided callback is NULL, then substitute * our own internal cbfunc and block here */ if (NULL == cbfunc) { PMIX_CONSTRUCT_LOCK(&mylock); cd->opcbfunc = opcbfunc; cd->cbdata = &mylock; PMIX_THREADSHIFT(cd, _iofdeliver); PMIX_WAIT_THREAD(&mylock); rc = mylock.status; PMIX_DESTRUCT_LOCK(&mylock); if (PMIX_SUCCESS == rc) { rc = PMIX_OPERATION_SUCCEEDED; } return rc; } PMIX_THREADSHIFT(cd, _iofdeliver); return PMIX_SUCCESS; } static void cirelease(void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; PMIX_ACQUIRE_OBJECT(cd); if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } PMIX_RELEASE(cd); } static void clct(int sd, short args, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t*)cbdata; pmix_list_t inventory; pmix_data_array_t darray; pmix_status_t rc; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_CONSTRUCT(&inventory, pmix_list_t); /* collect the pnet inventory */ rc = pmix_pnet.collect_inventory(cd->directives, cd->ndirs, &inventory); if (PMIX_SUCCESS != rc) { goto report; } /* collect the pgpu inventory */ rc = pmix_pgpu.collect_inventory(cd->directives, cd->ndirs, &inventory); if (PMIX_SUCCESS != rc) { goto report; } /* convert list to an array of info */ rc = PMIx_Info_list_convert((void*)&inventory, &darray); if (PMIX_ERR_EMPTY == rc) { rc = PMIX_SUCCESS; } else if (PMIX_SUCCESS == rc) { cd->info = (pmix_info_t*)darray.array; cd->ninfo = darray.size; } report: if (NULL != cd->cbfunc.infocbfunc) { cd->cbfunc.infocbfunc(rc, cd->info, cd->ninfo, cd->cbdata, cirelease, cd); } PMIX_LIST_DESTRUCT(&inventory); return; } pmix_status_t PMIx_server_collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_info_cbfunc_t cbfunc, void *cbdata) { pmix_shift_caddy_t *cd; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* need to threadshift this request */ cd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->directives = directives; cd->ndirs = ndirs; cd->cbfunc.infocbfunc = cbfunc; cd->cbdata = cbdata; PMIX_THREADSHIFT(cd, clct); return PMIX_SUCCESS; } static void dlinv(int sd, short args, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; pmix_status_t rc; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); rc = pmix_pnet.deliver_inventory(cd->info, cd->ninfo, cd->directives, cd->ndirs); if (PMIX_SUCCESS != rc) { goto report; } rc = pmix_pgpu.deliver_inventory(cd->info, cd->ninfo, cd->directives, cd->ndirs); report: if (NULL != cd->cbfunc.opcbfn) { cd->cbfunc.opcbfn(rc, cd->cbdata); } PMIX_RELEASE(cd); return; } pmix_status_t PMIx_server_deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_shift_caddy_t *cd; pmix_lock_t mylock; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* need to threadshift this request */ cd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->lock.active = false; cd->info = info; cd->ninfo = ninfo; cd->directives = directives; cd->ndirs = ndirs; cd->cbfunc.opcbfn = cbfunc; cd->cbdata = cbdata; /* if the provided callback is NULL, then substitute * our own internal cbfunc and block here */ if (NULL == cbfunc) { PMIX_CONSTRUCT_LOCK(&mylock); cd->cbfunc.opcbfn = opcbfunc; cd->cbdata = &mylock; PMIX_THREADSHIFT(cd, dlinv); PMIX_WAIT_THREAD(&mylock); rc = mylock.status; PMIX_DESTRUCT_LOCK(&mylock); if (PMIX_SUCCESS == rc) { rc = PMIX_OPERATION_SUCCEEDED; } return rc; } PMIX_THREADSHIFT(cd, dlinv); return PMIX_SUCCESS; } pmix_status_t PMIx_server_generate_locality_string(const pmix_cpuset_t *cpuset, char **locality) { pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* just pass this down */ rc = pmix_hwloc_generate_locality_string(cpuset, locality); return rc; } pmix_status_t PMIx_server_generate_cpuset_string(const pmix_cpuset_t *cpuset, char **cpuset_string) { pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* just pass this down */ rc = pmix_hwloc_generate_cpuset_string(cpuset, cpuset_string); return rc; } pmix_status_t PMIx_server_generate_cpuset(const char *cpuset_string, pmix_cpuset_t *cpuset) { pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* just pass this down */ rc = pmix_hwloc_parse_cpuset_string(cpuset_string, cpuset); return rc; } typedef struct { pmix_info_t *info; size_t ninfo; } mydata_t; static void release_info(pmix_status_t status, void *cbdata) { mydata_t *cd = (mydata_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_ACQUIRE_OBJECT(cd); PMIX_INFO_FREE(cd->info, cd->ninfo); free(cd); } static void psetdef(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; /* the PMIx server needs to cache the process sets so it can * respond to queries for names and memberships */ mydata_t *mydat; pmix_data_array_t *darray; pmix_proc_t *ptr; pmix_pset_t *ps; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); mydat = (mydata_t *) malloc(sizeof(mydata_t)); mydat->ninfo = 3; PMIX_INFO_CREATE(mydat->info, mydat->ninfo); PMIX_INFO_LOAD(&mydat->info[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&mydat->info[1], PMIX_PSET_NAME, cd->nspace, PMIX_STRING); PMIX_DATA_ARRAY_CREATE(darray, cd->nprocs, PMIX_PROC); PMIX_LOAD_KEY(mydat->info[2].key, PMIX_PSET_MEMBERS); mydat->info[2].value.type = PMIX_DATA_ARRAY; mydat->info[2].value.data.darray = darray; ptr = (pmix_proc_t *) darray->array; memcpy(ptr, cd->procs, cd->nprocs * sizeof(pmix_proc_t)); PMIx_Notify_event(PMIX_PROCESS_SET_DEFINE, &pmix_globals.myid, PMIX_RANGE_LOCAL, mydat->info, mydat->ninfo, release_info, (void *) mydat); /* now record the process set */ ps = PMIX_NEW(pmix_pset_t); ps->name = strdup(cd->nspace); ps->members = (pmix_proc_t *) malloc(cd->nprocs * sizeof(pmix_proc_t)); memcpy(ps->members, cd->procs, cd->nprocs * sizeof(pmix_proc_t)); ps->nmembers = cd->nprocs; pmix_list_append(&pmix_server_globals.psets, &ps->super); PMIX_WAKEUP_THREAD(&cd->lock); } pmix_status_t PMIx_server_define_process_set(const pmix_proc_t *members, size_t nmembers, const char *pset_name) { pmix_setup_caddy_t cd; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* need to threadshift this request */ PMIX_CONSTRUCT(&cd, pmix_setup_caddy_t); cd.nspace = (char*)pset_name; cd.procs = (pmix_proc_t *) members; cd.nprocs = nmembers; cd.opcbfunc = opcbfunc; cd.cbdata = &cd.lock; PMIX_THREADSHIFT(&cd, psetdef); PMIX_WAIT_THREAD(&cd.lock); /* protect the input */ cd.procs = NULL; cd.nprocs = 0; PMIX_DESTRUCT(&cd); return PMIX_SUCCESS; } static void psetdel(int sd, short args, void *cbdata) { /* the PMIx server needs to delete the process set from its list */ pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; mydata_t *mydat; pmix_pset_t *ps; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, args); mydat = (mydata_t *) malloc(sizeof(mydata_t)); mydat->ninfo = 2; PMIX_INFO_CREATE(mydat->info, mydat->ninfo); PMIX_INFO_LOAD(&mydat->info[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&mydat->info[1], PMIX_PSET_NAME, cd->nspace, PMIX_STRING); PMIx_Notify_event(PMIX_PROCESS_SET_DELETE, &pmix_globals.myid, PMIX_RANGE_LOCAL, mydat->info, mydat->ninfo, release_info, (void *) mydat); /* now find this process set */ PMIX_LIST_FOREACH (ps, &pmix_server_globals.psets, pmix_pset_t) { if (0 == strcmp(cd->nspace, ps->name)) { pmix_list_remove_item(&pmix_server_globals.psets, &ps->super); PMIX_RELEASE(ps); break; } } PMIX_WAKEUP_THREAD(&cd->lock); } pmix_status_t PMIx_server_delete_process_set(char *pset_name) { pmix_setup_caddy_t cd; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* need to threadshift this request */ PMIX_CONSTRUCT(&cd, pmix_setup_caddy_t); cd.nspace = pset_name; cd.opcbfunc = opcbfunc; cd.cbdata = &cd.lock; PMIX_THREADSHIFT(&cd, psetdel); PMIX_WAIT_THREAD(&cd.lock); PMIX_DESTRUCT(&cd); return PMIX_SUCCESS; } /**** THE FOLLOWING CALLBACK FUNCTIONS ARE USED BY THE HOST SERVER **** **** THEY THEREFORE CAN OCCUR IN EITHER THE HOST SERVER'S THREAD **** **** CONTEXT, OR IN OUR OWN THREAD CONTEXT IF THE CALLBACK OCCURS **** **** IMMEDIATELY. THUS ANYTHING THAT ACCESSES A GLOBAL ENTITY **** **** MUST BE PUSHED INTO AN EVENT FOR PROTECTION ****/ static void _opcbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t*)scd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(scd); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(scd); return; } /* setup the reply with the returned status */ if (NULL == (reply = PMIX_NEW(pmix_buffer_t))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } /* the function that created the server_caddy did a * retain on the peer, so we don't have to worry about * it still being present - send a copy to the originator */ PMIX_PTL_SEND_ONEWAY(rc, cd->peer, reply, cd->hdr.tag); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } if (scd->enviro) { /* ensure that we know the peer has finalized else we * will generate an event when the socket closes - yes, * it should have been done, but it is REALLY important * that it be set */ cd->peer->finalized = true; } cleanup: /* cleanup */ PMIX_RELEASE(cd); PMIX_RELEASE(scd); } static void op_cbfunc(pmix_status_t status, void *cbdata) { pmix_shift_caddy_t *scd; pmix_server_caddy_t *cd = (pmix_server_caddy_t*)cbdata; pmix_output_verbose(2, pmix_server_globals.base_output, "server:op_cbfunc called with %s status", PMIx_Error_string(status)); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } /* need to thread-shift this callback */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } scd->status = status; scd->cbdata = cbdata; scd->enviro = false; // flag that we are not finalizing the peer PMIX_THREADSHIFT(scd, _opcbfunc); } static void op_cbfunc2(pmix_status_t status, void *cbdata) { pmix_shift_caddy_t *scd; pmix_server_caddy_t *cd = (pmix_server_caddy_t*)cbdata; pmix_output_verbose(2, pmix_server_globals.base_output, "server:op_cbfunc2 called with %s status", PMIx_Error_string(status)); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } /* need to thread-shift this callback */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } scd->status = status; scd->cbdata = cbdata; scd->enviro = true; // flag that we are finalizing this peer PMIX_THREADSHIFT(scd, _opcbfunc); } static void _resopcbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scdwrapper = (pmix_shift_caddy_t *) cbdata; pmix_setup_caddy_t *scd = (pmix_setup_caddy_t*)scdwrapper->cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) scd->cbdata; pmix_buffer_t *reply = NULL; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(scdwrapper); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { goto cleanup; } /* setup the reply with the returned status */ if (NULL == (reply = PMIX_NEW(pmix_buffer_t))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scdwrapper->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* the function that created the server_caddy did a * retain on the peer, so we don't have to worry about * it still being present - send a copy to the originator */ PMIX_PTL_SEND_ONEWAY(rc, cd->peer, reply, cd->hdr.tag); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } return; /* cleanup */ cleanup: PMIX_RELEASE(cd); if (NULL != scd->nspace) { free(scd->nspace); } PMIX_RELEASE(scd); PMIX_RELEASE(scdwrapper); if (NULL != reply) { PMIX_RELEASE(reply); } } static void resop_cbfunc(pmix_status_t status, void *cbdata) { pmix_shift_caddy_t *scd; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)cbdata; pmix_output_verbose(2, pmix_server_globals.base_output, "server:resop_cbfunc called with %s status", PMIx_Error_string(status)); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } /* need to thread-shift this callback */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } scd->status = status; scd->cbdata = cbdata; PMIX_THREADSHIFT(scd, _resopcbfunc); } static void _spcb(int sd, short args, void *cbdata) { pmix_shift_caddy_t *cd = (pmix_shift_caddy_t *) cbdata; pmix_buffer_t *reply; pmix_status_t rc; pmix_proc_t proc; pmix_cb_t cb; pmix_kval_t *kv; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cd); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { goto cleanup; } /* setup the reply with the returned status */ if (NULL == (reply = PMIX_NEW(pmix_buffer_t))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->cd->peer, reply, &cd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } /* pass back the name of the nspace */ PMIX_BFROPS_PACK(rc, cd->cd->peer, reply, &cd->pname.nspace, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } if (PMIX_SUCCESS == cd->status) { /* add the job-level info, if we have it */ PMIX_LOAD_PROCID(&proc, cd->pname.nspace, PMIX_RANK_WILDCARD); /* this is going to a local client, so let the gds * have the option of returning a copy of the data, * or a pointer to local storage */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &proc; cb.scope = PMIX_SCOPE_UNDEF; cb.copy = false; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS == rc) { PMIX_LIST_FOREACH (kv, &cb.kvs, pmix_kval_t) { PMIX_BFROPS_PACK(rc, cd->cd->peer, reply, kv, 1, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); PMIX_DESTRUCT(&cb); goto cleanup; } } PMIX_DESTRUCT(&cb); } } /* the function that created the server_caddy did a * retain on the peer, so we don't have to worry about * it still being present - tell the originator the result */ PMIX_SERVER_QUEUE_REPLY(rc, cd->cd->peer, cd->cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: /* cleanup */ PMIX_RELEASE(cd->cd); PMIX_RELEASE(cd); } static void spawn_cbfunc(pmix_status_t status, char *nspace, void *cbdata) { pmix_shift_caddy_t *cd; pmix_server_caddy_t *scd = (pmix_server_caddy_t *) cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); return; } /* need to thread-shift this request */ cd = PMIX_NEW(pmix_shift_caddy_t); cd->status = status; if (NULL != nspace) { cd->pname.nspace = strdup(nspace); } cd->cd = (pmix_server_caddy_t *) cbdata; PMIX_THREADSHIFT(cd, _spcb); } static void _lkupcbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t *) cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) scd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(scd); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { goto cleanup; } /* no need to thread-shift as no global data is accessed */ /* setup the reply with the returned status */ if (NULL == (reply = PMIX_NEW(pmix_buffer_t))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } if (NULL != scd->pdata) { /* pack the returned data objects */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->ndata, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, scd->pdata, scd->ndata, PMIX_PDATA); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } PMIX_PDATA_FREE(scd->pdata, scd->npdata); } /* the function that created the server_caddy did a * retain on the peer, so we don't have to worry about * it still being present - tell the originator the result */ PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: /* cleanup */ PMIX_RELEASE(cd); PMIX_RELEASE(scd); } static void lookup_cbfunc(pmix_status_t status, pmix_pdata_t pdata[], size_t ndata, void *cbdata) { pmix_server_caddy_t *cd = (pmix_server_caddy_t *)cbdata; pmix_shift_caddy_t *scd; size_t n; pmix_status_t rc; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } /* need to thread-shift this request */ scd = PMIX_NEW(pmix_shift_caddy_t); scd->status = status; if (NULL != pdata) { scd->ndata = ndata; PMIX_PDATA_CREATE(scd->pdata, scd->ndata); for (n=0; n < scd->ndata; n++) { memcpy(&scd->pdata[n].proc, &pdata[n].proc, sizeof(pmix_proc_t)); memcpy(scd->pdata[n].key, pdata[n].key, sizeof(pmix_key_t)); PMIX_BFROPS_VALUE_XFER(rc, cd->peer, &scd->pdata[n].value, &pdata[n].value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } } scd->cbdata = cbdata; PMIX_THREADSHIFT(scd, _lkupcbfunc); } /* fence modex calls return here when the host RM has completed * the operation - any enclosed data is provided to us as a blob * which contains byte objects, one for each set of data. Our * peer servers will have packed the blobs using our common * GDS module, so use the mypeer one to unpack them */ static void _mdxcbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t *) cbdata; pmix_server_trkr_t *tracker = scd->tracker; pmix_buffer_t xfer, *reply; pmix_server_caddy_t *cd, *nxt; pmix_status_t rc = PMIX_SUCCESS, ret; pmix_nspace_caddy_t *nptr; pmix_list_t nslist; bool found; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(scd); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); return; } if (NULL == tracker) { /* give them a release if they want it - this should * never happen, but protect against the possibility */ if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->cbdata); } PMIX_RELEASE(scd); return; } /* if we get here, then there are processes waiting * for a response */ /* if the timer is active, clear it */ if (tracker->event_active) { pmix_event_del(&tracker->ev); } /* pass the blobs being returned */ PMIX_CONSTRUCT(&xfer, pmix_buffer_t); PMIX_CONSTRUCT(&nslist, pmix_list_t); if (PMIX_SUCCESS != scd->status) { rc = scd->status; goto finish_collective; } if (PMIX_COLLECT_INVALID == tracker->collect_type) { rc = PMIX_ERR_INVALID_ARG; goto finish_collective; } /* Collect the list of unique nspaces so we store the * data so each namespace can access it */ PMIX_LIST_FOREACH (cd, &tracker->local_cbs, pmix_server_caddy_t) { // see if we already have this nspace found = false; PMIX_LIST_FOREACH (nptr, &nslist, pmix_nspace_caddy_t) { if (0 == strcmp(nptr->ns->nspace, cd->peer->nptr->nspace)) { found = true; break; } } if (!found) { // add it nptr = PMIX_NEW(pmix_nspace_caddy_t); PMIX_RETAIN(cd->peer->nptr); nptr->ns = cd->peer->nptr; pmix_list_append(&nslist, &nptr->super); } } // Skip storing the data if we didn't collect it if (NULL == scd->data) { rc = PMIX_SUCCESS; goto finish_collective; } /* pass the blobs being returned */ PMIX_LOAD_BUFFER_NON_DESTRUCT(pmix_globals.mypeer, &xfer, scd->data, scd->ndata); PMIX_GDS_STORE_MODEX(rc, &xfer, tracker); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } /* do NOT destruct the xfer buffer as that would release the payload! */ finish_collective: /* loop across all procs in the tracker, sending them the reply */ PMIX_LIST_FOREACH_SAFE (cd, nxt, &tracker->local_cbs, pmix_server_caddy_t) { reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { break; } /* setup the reply, starting with the returned status */ PMIX_BFROPS_PACK(ret, cd->peer, reply, &rc, 1, PMIX_STATUS); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); goto cleanup; } /* let the gds have a chance to add any data it needs * for providing access to any collected data */ PMIX_GDS_MARK_MODEX_COMPLETE(rc, cd->peer, &nslist, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); PMIX_ERROR_LOG(rc); goto cleanup; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:modex_cbfunc reply being sent to %s:%u", cd->peer->info->pname.nspace, cd->peer->info->pname.rank); PMIX_SERVER_QUEUE_REPLY(ret, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != ret) { PMIX_RELEASE(reply); } /* remove this entry */ pmix_list_remove_item(&tracker->local_cbs, &cd->super); PMIX_RELEASE(cd); } cleanup: /* Protect data from being free'd because RM pass * the pointer that is set to the middle of some * buffer (the case with SLURM). * RM is responsible on the release of the buffer */ xfer.base_ptr = NULL; xfer.bytes_used = 0; PMIX_DESTRUCT(&xfer); pmix_list_remove_item(&pmix_server_globals.collectives, &tracker->super); PMIX_RELEASE(tracker); PMIX_LIST_DESTRUCT(&nslist); /* we are done */ if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } PMIX_RELEASE(scd); } static void modex_cbfunc(pmix_status_t status, const char *data, size_t ndata, void *cbdata, pmix_release_cbfunc_t relfn, void *relcbd) { pmix_server_trkr_t *tracker = (pmix_server_trkr_t *) cbdata; pmix_shift_caddy_t *scd; pmix_output_verbose(2, pmix_server_globals.base_output, "server:modex_cbfunc called with %d bytes", (int) ndata); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return; } /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); /* nothing we can do */ if (NULL != relfn) { relfn(cbdata); } return; } scd->status = status; scd->data = data; scd->ndata = ndata; scd->tracker = tracker; scd->cbfunc.relfn = relfn; scd->relcbdata = relcbd; PMIX_THREADSHIFT(scd, _mdxcbfunc); } static void _getcbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t *) cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) scd->cbdata; pmix_buffer_t *reply, buf; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); PMIX_RELEASE(cd); return; } if (NULL == cd) { /* nothing to do - but be sure to give them * a release if they want it */ goto cleanup; } /* setup the reply, starting with the returned status */ reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { rc = PMIX_ERR_NOMEM; goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* if there are data, pack the blob being returned */ if (NULL != scd->data) { PMIX_CONSTRUCT(&buf, pmix_buffer_t); PMIX_LOAD_BUFFER(cd->peer, &buf, scd->data, scd->ndata); PMIX_BFROPS_COPY_PAYLOAD(rc, cd->peer, reply, &buf); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); PMIX_DESTRUCT(&buf); goto cleanup; } buf.base_ptr = NULL; buf.bytes_used = 0; PMIX_DESTRUCT(&buf); } /* send the data to the requestor */ pmix_output_verbose(2, pmix_server_globals.base_output, "server:get_cbfunc reply being sent to %s:%u with status %s", cd->peer->info->pname.nspace, cd->peer->info->pname.rank, PMIx_Error_string(scd->status)); pmix_output_hexdump(10, pmix_server_globals.base_output, reply->base_ptr, (reply->bytes_used < 256 ? reply->bytes_used : 256)); PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: /* if someone wants a release, give it to them */ if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } if (NULL != cd) { PMIX_RELEASE(cd); } PMIX_RELEASE(scd); } static void get_cbfunc(pmix_status_t status, const char *data, size_t ndata, void *cbdata, pmix_release_cbfunc_t relfn, void *relcbd) { pmix_shift_caddy_t *scd; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ if (NULL != relfn) { relfn(cbdata); } return; } scd->status = status; scd->data = data; scd->ndata = ndata; scd->cbdata = cbdata; scd->cbfunc.relfn = relfn; scd->relcbdata = relcbd; PMIX_THREADSHIFT(scd, _getcbfunc); } static void _cnct(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t *) cbdata; pmix_server_trkr_t *tracker = scd->tracker; pmix_buffer_t *reply, pbkt; pmix_byte_object_t bo; pmix_status_t rc; int i; pmix_server_caddy_t *cd; char **nspaces = NULL; bool found; pmix_proc_t proc; pmix_cb_t cb; pmix_kval_t *kptr; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(scd); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); return; } if (NULL == tracker) { /* nothing to do */ return; } /* if we get here, then there are processes waiting * for a response */ /* if the timer is active, clear it */ if (tracker->event_active) { pmix_event_del(&tracker->ev); } /* find the unique nspaces that are participating */ PMIX_LIST_FOREACH (cd, &tracker->local_cbs, pmix_server_caddy_t) { if (NULL == nspaces) { PMIx_Argv_append_nosize(&nspaces, cd->peer->info->pname.nspace); } else { found = false; for (i = 0; NULL != nspaces[i]; i++) { if (0 == strcmp(nspaces[i], cd->peer->info->pname.nspace)) { found = true; break; } } if (!found) { PMIx_Argv_append_nosize(&nspaces, cd->peer->info->pname.nspace); } } } /* loop across all local procs in the tracker, sending them the reply */ PMIX_LIST_FOREACH (cd, &tracker->local_cbs, pmix_server_caddy_t) { /* setup the reply, starting with the returned status */ reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); rc = PMIX_ERR_NOMEM; goto cleanup; } /* start with the status */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } if (PMIX_SUCCESS == scd->status) { /* loop across all participating nspaces and include their * job-related info */ for (i = 0; NULL != nspaces[i]; i++) { /* if this is the local proc's own nspace, then * ignore it - it already has this info */ if (0 == strncmp(nspaces[i], cd->peer->info->pname.nspace, PMIX_MAX_NSLEN)) { continue; } /* this is a local request, so give the gds the option * of returning a copy of the data, or a pointer to * local storage */ /* add the job-level info, if necessary */ PMIX_LOAD_PROCID(&proc, nspaces[i], PMIX_RANK_WILDCARD); PMIX_CONSTRUCT(&cb, pmix_cb_t); /* this is for a local client, so give the gds the * option of returning a complete copy of the data, * or returning a pointer to local storage */ cb.proc = &proc; cb.scope = PMIX_SCOPE_UNDEF; cb.copy = false; PMIX_GDS_FETCH_KV(rc, cd->peer, &cb); if (PMIX_SUCCESS != rc) { /* try getting it from our storage */ PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); PMIX_DESTRUCT(&cb); goto error; } } PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); /* pack the nspace name */ PMIX_BFROPS_PACK(rc, cd->peer, &pbkt, &nspaces[i], 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&cb); goto error; } PMIX_LIST_FOREACH (kptr, &cb.kvs, pmix_kval_t) { PMIX_BFROPS_PACK(rc, cd->peer, &pbkt, kptr, 1, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&cb); goto error; } } PMIX_DESTRUCT(&cb); if (PMIX_PEER_IS_V1(cd->peer) || PMIX_PEER_IS_V20(cd->peer)) { PMIX_BFROPS_PACK(rc, cd->peer, reply, &pbkt, 1, PMIX_BUFFER); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&cb); goto error; } } else { PMIX_UNLOAD_BUFFER(&pbkt, bo.bytes, bo.size); PMIX_BFROPS_PACK(rc, cd->peer, reply, &bo, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&cb); goto error; } } PMIX_DESTRUCT(&pbkt); } } pmix_output_verbose(2, pmix_server_globals.connect_output, "server:cnct_cbfunc reply being sent to %s", PMIX_PEER_PRINT(cd->peer)); PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); } } goto cleanup; error: reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); rc = PMIX_ERR_NOMEM; goto cleanup; } /* return an error status so they don't hang */ scd->status = rc; PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: if (NULL != nspaces) { PMIx_Argv_free(nspaces); } pmix_list_remove_item(&pmix_server_globals.collectives, &tracker->super); PMIX_RELEASE(tracker); /* we are done */ PMIX_RELEASE(scd); } static void cnct_cbfunc(pmix_status_t status, void *cbdata) { pmix_server_trkr_t *tracker = (pmix_server_trkr_t *) cbdata; pmix_shift_caddy_t *scd; pmix_output_verbose(2, pmix_server_globals.connect_output, "server:cnct_cbfunc called"); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return; } /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ return; } scd->status = status; scd->tracker = tracker; PMIX_THREADSHIFT(scd, _cnct); } static void _discnct(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t *) cbdata; pmix_server_trkr_t *tracker = scd->tracker; pmix_buffer_t *reply; pmix_status_t rc; pmix_server_caddy_t *cd; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(scd); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); return; } if (NULL == tracker) { /* nothing to do */ return; } /* if we get here, then there are processes waiting * for a response */ /* if the timer is active, clear it */ if (tracker->event_active) { pmix_event_del(&tracker->ev); } /* loop across all local procs in the tracker, sending them the reply */ PMIX_LIST_FOREACH (cd, &tracker->local_cbs, pmix_server_caddy_t) { /* setup the reply */ reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); rc = PMIX_ERR_NOMEM; goto cleanup; } /* return the status */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } pmix_output_verbose(2, pmix_server_globals.connect_output, "server:cnct_cbfunc reply being sent to %s:%u", cd->peer->info->pname.nspace, cd->peer->info->pname.rank); PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } } cleanup: /* cleanup the tracker -- the host RM is responsible for * telling us when to remove the nspace from our data */ pmix_list_remove_item(&pmix_server_globals.collectives, &tracker->super); PMIX_RELEASE(tracker); /* we are done */ PMIX_RELEASE(scd); } static void discnct_cbfunc(pmix_status_t status, void *cbdata) { pmix_server_trkr_t *tracker = (pmix_server_trkr_t *) cbdata; pmix_shift_caddy_t *scd; pmix_output_verbose(2, pmix_server_globals.base_output, "server:discnct_cbfunc called on nspace %s", (NULL == tracker) ? "NULL" : tracker->pname.nspace); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return; } /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ return; } scd->status = status; scd->tracker = tracker; PMIX_THREADSHIFT(scd, _discnct); } static void _evcbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)scd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(scd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:events_cbfunc called status = %s", PMIx_Error_string(scd->status)); reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: PMIX_RELEASE(cd); PMIX_RELEASE(scd); } static void events_cbfunc(pmix_status_t status, void *cbdata) { pmix_shift_caddy_t *scd; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)cbdata; pmix_output_verbose(2, pmix_server_globals.base_output, "server:events_cbfunc called"); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ return; } scd->status = status; scd->cbdata = cbdata; PMIX_THREADSHIFT(scd, _evcbfunc); } static void _alloccbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_query_caddy_t *qcd = (pmix_query_caddy_t *)scd->cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) qcd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { if (NULL != qcd->queries) { PMIX_QUERY_FREE(qcd->queries, qcd->nqueries); } if (NULL != qcd->info) { PMIX_INFO_FREE(qcd->info, qcd->ninfo); } PMIX_RELEASE(cd); PMIX_RELEASE(qcd); PMIX_RELEASE(scd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:alloc callback with status %s", PMIx_Error_string(scd->status)); reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } /* pack the returned data */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < scd->ninfo) { PMIX_BFROPS_PACK(rc, cd->peer, reply, scd->info, scd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: // cleanup if (NULL != qcd->queries) { PMIX_QUERY_FREE(qcd->queries, qcd->nqueries); } if (NULL != qcd->info) { PMIX_INFO_FREE(qcd->info, qcd->ninfo); } if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } PMIX_RELEASE(cd); PMIX_RELEASE(qcd); PMIX_RELEASE(scd); } static void alloc_cbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *scd; pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) qcd->cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { if (NULL != qcd->queries) { PMIX_QUERY_FREE(qcd->queries, qcd->nqueries); } if (NULL != qcd->info) { PMIX_INFO_FREE(qcd->info, qcd->ninfo); } PMIX_RELEASE(cd); PMIX_RELEASE(qcd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:alloc_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ return; } scd->status = status; scd->info = info; scd->ninfo = ninfo; scd->cbdata = cbdata; scd->cbfunc.relfn = release_fn; scd->relcbdata = release_cbdata; PMIX_THREADSHIFT(scd, _alloccbfunc); } static void _qrycbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scdwrapper = (pmix_shift_caddy_t*)cbdata; pmix_server_caddy_t *scd = (pmix_server_caddy_t*)scdwrapper->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); PMIX_RELEASE(scdwrapper); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:query callback with status %s", PMIx_Error_string(scdwrapper->status)); reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, scd->peer, reply, &scdwrapper->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } /* pack the returned data */ PMIX_BFROPS_PACK(rc, scd->peer, reply, &scdwrapper->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < scdwrapper->ninfo) { PMIX_BFROPS_PACK(rc, scd->peer, reply, scdwrapper->info, scdwrapper->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } /* cache the data for any future requests */ complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, scd->peer, scd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: // cleanup if (NULL != scdwrapper->cbfunc.relfn) { scdwrapper->cbfunc.relfn(scdwrapper->relcbdata); } PMIX_RELEASE(scd); PMIX_RELEASE(scdwrapper); } static void query_cbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *scd; pmix_server_caddy_t *cd = (pmix_server_caddy_t*)cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:query_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ return; } scd->status = status; scd->info = info; scd->ninfo = ninfo; scd->cbdata = cbdata; scd->cbfunc.relfn = release_fn; scd->relcbdata = release_cbdata; PMIX_THREADSHIFT(scd, _qrycbfunc); } static void _sctrl_cbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scdwrapper = (pmix_shift_caddy_t*)cbdata; pmix_shift_caddy_t *scd = (pmix_shift_caddy_t *)scdwrapper->cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)scd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(scd); PMIX_RELEASE(scdwrapper); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:session_ctrl callback with status %s", PMIx_Error_string(scdwrapper->status)); reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scdwrapper->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } /* pack the returned data */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scdwrapper->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < scdwrapper->ninfo) { PMIX_BFROPS_PACK(rc, cd->peer, reply, scdwrapper->info, scdwrapper->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: if (NULL != scd->info) { PMIX_INFO_FREE(scd->info, scd->ninfo); } if (NULL != scdwrapper->cbfunc.relfn) { scdwrapper->cbfunc.relfn(scdwrapper->relcbdata); } PMIX_RELEASE(scd); PMIX_RELEASE(cd); PMIX_RELEASE(scdwrapper); } static void sessctrl_cbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *scdwrapper; pmix_shift_caddy_t *scd = (pmix_shift_caddy_t *)cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)scd->cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(scd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:sessctrl_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scdwrapper = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scdwrapper) { /* nothing we can do */ return; } scdwrapper->status = status; scdwrapper->info = info; scdwrapper->ninfo = ninfo; scdwrapper->cbdata = cbdata; scdwrapper->cbfunc.relfn = release_fn; scdwrapper->relcbdata = release_cbdata; PMIX_THREADSHIFT(scdwrapper, _sctrl_cbfunc); } static void _jctrl_cbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) scd->cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) qcd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(qcd); PMIX_RELEASE(scd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:_jctrl_cbfunc callback with status %s", PMIx_Error_string(scd->status)); reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } /* pack the returned data */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < scd->ninfo) { PMIX_BFROPS_PACK(rc, cd->peer, reply, scd->info, scd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: if (NULL != qcd->queries) { PMIX_QUERY_FREE(qcd->queries, qcd->nqueries); } if (NULL != qcd->info) { PMIX_INFO_FREE(qcd->info, qcd->ninfo); } if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } PMIX_RELEASE(qcd); PMIX_RELEASE(cd); PMIX_RELEASE(scd); } static void jctrl_cbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *scd; pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) qcd->cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(qcd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:jctrl_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ return; } scd->status = status; scd->info = info; scd->ninfo = ninfo; scd->cbdata = cbdata; scd->cbfunc.relfn = release_fn; scd->relcbdata = release_cbdata; PMIX_THREADSHIFT(scd, _jctrl_cbfunc); } static void _mon_cbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) scd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(scd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:_mon_cbfunc callback with status %s", PMIx_Error_string(scd->status)); reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } /* pack the returned data */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < scd->ninfo) { PMIX_BFROPS_PACK(rc, cd->peer, reply, scd->info, scd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: PMIX_RELEASE(cd); if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } PMIX_RELEASE(scd); } static void monitor_cbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *scd; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:monitor_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ return; } scd->status = status; scd->info = info; scd->ninfo = ninfo; scd->cbdata = cbdata; scd->cbfunc.relfn = release_fn; scd->relcbdata = release_cbdata; PMIX_THREADSHIFT(scd, _mon_cbfunc); } static void _cred_cbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) scd->cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) qcd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(qcd); PMIX_RELEASE(scd); return; } pmix_output_verbose(2, pmix_globals.debug_output, "pmix:get credential callback with status %s", PMIx_Error_string(scd->status)); reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } /* pack the status */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS == scd->status) { /* pack the returned credential */ PMIX_BFROPS_PACK(rc, cd->peer, reply, scd->bo, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } /* pack any returned data */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < scd->ninfo) { PMIX_BFROPS_PACK(rc, cd->peer, reply, scd->info, scd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: if (NULL != qcd->info) { PMIX_INFO_FREE(qcd->info, qcd->ninfo); } if (NULL != scd->bo) { PMIX_BYTE_OBJECT_FREE(scd->bo, 1); } PMIX_RELEASE(qcd); PMIX_RELEASE(cd); PMIX_RELEASE(scd); } static void cred_cbfunc(pmix_status_t status, pmix_byte_object_t *credential, pmix_info_t info[], size_t ninfo, void *cbdata) { pmix_shift_caddy_t *scd; pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) qcd->cbdata; pmix_status_t rc; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(qcd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:cred_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ return; } scd->status = status; scd->info = info; scd->ninfo = ninfo; // need to copy this as they may not hold it for us PMIX_BFROPS_COPY(rc, cd->peer, (void**)&scd->bo, credential, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd); PMIX_RELEASE(qcd); PMIX_RELEASE(scd); return; } scd->cbdata = cbdata; PMIX_THREADSHIFT(scd, _cred_cbfunc); } static void _valcbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) scd->cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) qcd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(qcd); PMIX_RELEASE(scd); return; } pmix_output_verbose(2, pmix_globals.debug_output, "pmix:validate credential callback with status %s", PMIx_Error_string(scd->status)); reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } /* pack any returned data */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < scd->ninfo) { PMIX_BFROPS_PACK(rc, cd->peer, reply, scd->info, scd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: if (NULL != qcd->info) { PMIX_INFO_FREE(qcd->info, qcd->ninfo); } if (NULL != scd->info) { PMIX_INFO_FREE(scd->info, scd->ninfo); } PMIX_RELEASE(qcd); PMIX_RELEASE(cd); PMIX_RELEASE(scd); } static void validate_cbfunc(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *cbdata) { pmix_shift_caddy_t *scd; pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) qcd->cbdata; pmix_status_t rc; size_t n; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(qcd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:validate_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ return; } scd->status = status; // need to copy the info as they may not hold it for us if (NULL != info) { scd->ninfo = ninfo; PMIX_INFO_CREATE(scd->info, scd->ninfo); for (n=0; n < scd->ninfo; n++) { rc = PMIx_Info_xfer(&scd->info[n], &info[n]); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_INFO_FREE(scd->info, scd->ninfo); PMIX_RELEASE(scd); return; } } } scd->cbdata = cbdata; PMIX_THREADSHIFT(scd, _valcbfunc); } static void _iofreg(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_server_caddy_t *scd = (pmix_server_caddy_t *) cd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; pmix_iof_req_t *req; pmix_iof_cache_t *iof, *inxt; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cd); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); PMIX_RELEASE(cd); return; } /* setup the reply to the requestor */ reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); rc = PMIX_ERR_NOMEM; goto cleanup; } /* start with the status */ PMIX_BFROPS_PACK(rc, scd->peer, reply, &cd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } /* was the request a success? */ if (PMIX_SUCCESS != cd->status) { /* find and remove the tracker */ req = (pmix_iof_req_t *) pmix_pointer_array_get_item(&pmix_globals.iof_requests, cd->ncodes); if (NULL != req) { PMIX_RELEASE(req); } pmix_pointer_array_set_item(&pmix_globals.iof_requests, cd->ncodes, NULL); } else { /* return our reference ID for this handler */ PMIX_BFROPS_PACK(rc, scd->peer, reply, &cd->ncodes, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } } pmix_output_verbose(2, pmix_server_globals.iof_output, "server:_iofreg reply being sent to %s:%u", scd->peer->info->pname.nspace, scd->peer->info->pname.rank); PMIX_SERVER_QUEUE_REPLY(rc, scd->peer, scd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } /* if the request succeeded, then process any cached IO - doing it here * guarantees that the IO will be received AFTER the client gets the * refid response */ if (PMIX_SUCCESS == cd->status) { /* get the request */ req = (pmix_iof_req_t *) pmix_pointer_array_get_item(&pmix_globals.iof_requests, cd->ncodes); if (NULL != req) { PMIX_LIST_FOREACH_SAFE (iof, inxt, &pmix_server_globals.iof, pmix_iof_cache_t) { rc = pmix_iof_process_iof(iof->channel, &iof->source, iof->bo, iof->info, iof->ninfo, req); if (PMIX_OPERATION_SUCCEEDED == rc) { pmix_list_remove_item(&pmix_server_globals.iof, &iof->super); PMIX_RELEASE(iof); } } } } cleanup: /* release the cached info */ if (NULL != cd->procs) { PMIX_PROC_FREE(cd->procs, cd->nprocs); } PMIX_INFO_FREE(cd->info, cd->ninfo); /* we are done */ PMIX_RELEASE(cd); } static void iof_cbfunc(pmix_status_t status, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } pmix_output_verbose(2, pmix_server_globals.iof_output, "server:iof_cbfunc called with status %d", status); if (NULL == cd) { /* nothing to do */ return; } cd->status = status; /* need to thread-shift this callback as it accesses global data */ PMIX_THREADSHIFT(cd, _iofreg); } static void _iofdreg(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scdwrapper = (pmix_shift_caddy_t*)cbdata; pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) scdwrapper->cbdata; pmix_server_caddy_t *scd = (pmix_server_caddy_t *) cd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cd); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); PMIX_RELEASE(cd); PMIX_RELEASE(scdwrapper); return; } /* setup the reply to the requestor */ reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); rc = PMIX_ERR_NOMEM; goto cleanup; } /* its just the status */ PMIX_BFROPS_PACK(rc, scd->peer, reply, &scdwrapper->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); goto cleanup; } pmix_output_verbose(2, pmix_server_globals.iof_output, "server:_iofreg reply being sent to %s:%u", scd->peer->info->pname.nspace, scd->peer->info->pname.rank); PMIX_SERVER_QUEUE_REPLY(rc, scd->peer, scd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: PMIX_RELEASE(scd); PMIX_RELEASE(cd); PMIX_RELEASE(scdwrapper); } static void iofdereg(pmix_status_t status, void *cbdata) { pmix_shift_caddy_t *scdwrapper; pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_server_caddy_t *scd = (pmix_server_caddy_t *) cd->cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); PMIX_RELEASE(cd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:_iofdereg called with %s status", PMIx_Error_string(status)); /* need to thread-shift this callback */ scdwrapper = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scdwrapper) { /* nothing we can do */ PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } scdwrapper->status = status; scdwrapper->cbdata = cbdata; PMIX_THREADSHIFT(scdwrapper, _iofdreg); } static void _fabcbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) scd->cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) qcd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); PMIX_RELEASE(qcd); PMIX_RELEASE(cd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:fabric callback with status %s", PMIx_Error_string(scd->status)); reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } /* pack the returned data */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < scd->ninfo) { PMIX_BFROPS_PACK(rc, cd->peer, reply, scd->info, scd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: if (NULL != qcd->queries) { PMIX_QUERY_FREE(qcd->queries, qcd->nqueries); } if (NULL != qcd->info) { PMIX_INFO_FREE(qcd->info, qcd->ninfo); } if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } PMIX_RELEASE(cd); PMIX_RELEASE(qcd); PMIX_RELEASE(scd); } static void fabric_cbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *scd; pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) qcd->cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(qcd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:fabric_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); /* nothing we can do */ if (NULL != release_fn) { release_fn(release_cbdata); } return; } scd->status = status; scd->info = info; scd->ninfo = ninfo; scd->cbdata = cbdata; scd->cbfunc.relfn = release_fn; scd->relcbdata = release_cbdata; PMIX_THREADSHIFT(scd, _fabcbfunc); } static void _distcbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)scd->cbdata; pmix_buffer_t *reply; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); PMIX_RELEASE(cd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "pmix:fabric callback with status %s", PMIx_Error_string(scd->status)); reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } /* pack the returned data */ PMIX_BFROPS_PACK(rc, cd->peer, reply, &scd->ndist, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < scd->ndist) { PMIX_BFROPS_PACK(rc, cd->peer, reply, scd->dist, scd->ndist, PMIX_DEVICE_DIST); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: PMIX_RELEASE(cd); if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } PMIX_RELEASE(scd); } static void dist_cbfunc(pmix_status_t status, pmix_device_distance_t *dist, size_t ndist, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *scd; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:dist_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); /* nothing we can do */ if (NULL != release_fn) { release_fn(release_cbdata); } return; } scd->status = status; scd->dist = dist; scd->ndist = ndist; scd->cbdata = cbdata; scd->cbfunc.relfn = release_fn; scd->relcbdata = release_cbdata; PMIX_THREADSHIFT(scd, _distcbfunc); } static void _respeerscbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)scd->cbdata; pmix_buffer_t *reply; pmix_status_t rc, ret; pmix_value_t *val; pmix_proc_t *pa = NULL; size_t np = 0; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cd); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); PMIX_RELEASE(scd); return; } ret = scd->status; if (PMIX_SUCCESS == ret) { // array return should be in first info if (0 == scd->ninfo) { // they didn't return anything ret = PMIX_ERR_NOT_FOUND; goto done; } val = &scd->info[0].value; if (PMIX_DATA_ARRAY != val->type || PMIX_PROC != val->data.darray->type) { PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL); ret = PMIX_ERR_INVALID_VAL; goto done; } pa = (pmix_proc_t*)val->data.darray->array; np = val->data.darray->size; } else { /* attempt to locally resolve the request */ PMIX_THREADSHIFT(cd, pmix_server_locally_resolve_peers); // give the host its release if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } PMIX_RELEASE(scd); return; } done: reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &ret, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS == ret) { PMIX_BFROPS_PACK(rc, cd->peer, reply, &np, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < np) { PMIX_BFROPS_PACK(rc, cd->peer, reply, pa, np, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: PMIX_RELEASE(cd); if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } PMIX_RELEASE(scd); } static void respeers_cbfunc(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *scd; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:respeers_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); /* nothing we can do */ if (NULL != release_fn) { release_fn(release_cbdata); } return; } scd->status = status; scd->info = info; scd->ninfo = ninfo; scd->cbdata = cbdata; scd->cbfunc.relfn = release_fn; scd->relcbdata = release_cbdata; PMIX_THREADSHIFT(scd, _respeerscbfunc); } static void _resnodescbfunc(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t*)cbdata; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)scd->cbdata; pmix_buffer_t *reply; pmix_status_t rc, ret; pmix_value_t *val; char *nodelist = NULL; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cd); if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); PMIX_RELEASE(cd); return; } ret = scd->status; if (PMIX_SUCCESS == ret) { // array return should be in first info if (0 == scd->ninfo) { // they didn't return anything ret = PMIX_ERR_NOT_FOUND; goto done; } val = &scd->info[0].value; if (PMIX_STRING != val->type) { PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL); ret = PMIX_ERR_INVALID_VAL; goto done; } nodelist = val->data.string; } else { /* attempt to locally resolve the request */ PMIX_THREADSHIFT(cd, pmix_server_locally_resolve_node); // give the host its release if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } PMIX_RELEASE(scd); return; } done: reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); goto cleanup; } PMIX_BFROPS_PACK(rc, cd->peer, reply, &ret, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS == ret) { PMIX_BFROPS_PACK(rc, cd->peer, reply, &nodelist, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } complete: // send reply PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } cleanup: PMIX_RELEASE(cd); // give the caller their release if (NULL != scd->cbfunc.relfn) { scd->cbfunc.relfn(scd->relcbdata); } PMIX_RELEASE(scd); } static void resnodes_cbfunc(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *scd; pmix_server_caddy_t *cd = (pmix_server_caddy_t *)cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } pmix_output_verbose(2, pmix_server_globals.base_output, "server:resnodes_cbfunc called"); /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); /* nothing we can do */ if (NULL != release_fn) { release_fn(release_cbdata); } return; } scd->status = status; scd->info = info; scd->ninfo = ninfo; scd->cbdata = cbdata; scd->cbfunc.relfn = release_fn; scd->relcbdata = release_cbdata; PMIX_THREADSHIFT(scd, _resnodescbfunc); } /* the switchyard is the primary message handling function. It's purpose * is to take incoming commands (packed into a buffer), unpack them, * and then call the corresponding host server's function to execute * them. Some commands involve only a single proc (i.e., the one * sending the command) and can be executed while we wait. In these cases, * the switchyard will construct and pack a reply buffer to be returned * to the sender. * * Other cases (either multi-process collective or cmds that require * an async reply) cannot generate an immediate reply. In these cases, * the reply buffer will be NULL. An appropriate callback function will * be called that will be responsible for eventually replying to the * calling processes. * * Should an error be encountered at any time within the switchyard, an * error reply buffer will be returned so that the caller can be notified, * thereby preventing the process from hanging. */ static pmix_status_t server_switchyard(pmix_peer_t *peer, uint32_t tag, pmix_buffer_t *buf) { pmix_status_t rc = PMIX_ERR_NOT_SUPPORTED; int32_t cnt; pmix_cmd_t cmd; pmix_server_caddy_t *cd; pmix_proc_t proc; pmix_buffer_t *reply; /* protect against zero-byte buffers - these can come if the * connection is dropped due to a process failure */ if (PMIX_BUFFER_IS_EMPTY(buf)) { return PMIX_ERR_LOST_CONNECTION; } /* retrieve the cmd */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cmd, &cnt, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } pmix_output_verbose(2, pmix_server_globals.base_output, "%s recvd pmix cmd %s from %s bytes %u", PMIX_NAME_PRINT(&pmix_globals.myid), pmix_command_string(cmd), PMIX_PEER_PRINT(peer), (unsigned int) buf->bytes_used); /* if I am a tool, all I can do is relay this to my primary server * if I am connected - if not connected, then I must return an error */ if (PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { rc = pmix_tool_relay_op(cmd, peer, buf, tag); if (PMIX_ERR_NOT_SUPPORTED != rc) { return rc; } /* if the tool relay doesn't support it, let it * be processed by the logic tree */ } /* if I am a server, then redirect the cmd to the appropriate * function for processing */ if (PMIX_REQ_CMD == cmd) { reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } PMIX_GDS_REGISTER_JOB_INFO(rc, peer, reply); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(reply); return rc; } PMIX_SERVER_QUEUE_REPLY(rc, peer, tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } peer->nptr->ndelivered++; return PMIX_SUCCESS; } if (PMIX_ABORT_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_abort(peer, buf, op_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_COMMIT_CMD == cmd) { rc = pmix_server_commit(peer, buf); if (!PMIX_PEER_IS_V1(peer)) { reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } PMIX_BFROPS_PACK(rc, peer, reply, &rc, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } PMIX_SERVER_QUEUE_REPLY(rc, peer, tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } } return PMIX_SUCCESS; // don't reply twice } if (PMIX_FENCENB_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_fence(cd, buf, modex_cbfunc, op_cbfunc))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_GETNB_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_get(buf, get_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_FINALIZE_CMD == cmd) { peer->nptr->nfinalized++; /* purge events */ pmix_server_purge_events(peer, NULL); PMIX_GDS_CADDY(cd, peer, tag); /* call the local server, if supported */ if (NULL != pmix_host_server.client_finalized && PMIX_PEER_IS_CLIENT(peer)) { pmix_strncpy(proc.nspace, peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = peer->info->pname.rank; /* now tell the host server */ rc = pmix_host_server.client_finalized(&proc, peer->info->server_object, op_cbfunc2, cd); if (PMIX_SUCCESS == rc) { /* don't reply to them ourselves - we will do so when the host * server calls us back */ return rc; } else if (PMIX_OPERATION_SUCCEEDED == rc) { /* they did it atomically */ rc = PMIX_SUCCESS; } /* if the call doesn't succeed (e.g., they provided the stub * but return NOT_SUPPORTED), then the callback function * won't be called, but we still need to cleanup * any lingering references to this peer and answer * the client. Thus, we call the callback function ourselves * in this case */ op_cbfunc2(rc, cd); /* return SUCCESS as the cbfunc generated the return msg * and released the cd object */ return PMIX_SUCCESS; } /* if the host doesn't provide a client_finalized function, * we still need to ensure that we cleanup any lingering * references to this peer. We use the callback function * here as well to ensure the client gets its required * response and that we delay before cleaning up the * connection*/ op_cbfunc2(PMIX_SUCCESS, cd); /* return SUCCESS as the cbfunc generated the return msg * and released the cd object */ return PMIX_SUCCESS; } if (PMIX_PUBLISHNB_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_publish(peer, buf, op_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_LOOKUPNB_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_lookup(peer, buf, lookup_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_UNPUBLISHNB_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_unpublish(peer, buf, op_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_SPAWNNB_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_spawn(peer, buf, spawn_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_CONNECTNB_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); rc = pmix_server_connect(cd, buf, cnct_cbfunc); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); } return rc; } if (PMIX_DISCONNECTNB_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); rc = pmix_server_disconnect(cd, buf, discnct_cbfunc); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); } return rc; } if (PMIX_REGEVENTS_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_register_events(peer, buf, events_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_DEREGEVENTS_CMD == cmd) { pmix_server_deregister_events(peer, buf); return PMIX_SUCCESS; } if (PMIX_NOTIFY_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); rc = pmix_server_event_recvd_from_client(peer, buf, events_cbfunc, cd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); } return rc; } if (PMIX_QUERY_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); rc = pmix_server_query(peer, buf, query_cbfunc, cd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); } return rc; } if (PMIX_LOG_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_log(peer, buf, op_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_ALLOC_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_alloc(peer, buf, alloc_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_JOB_CONTROL_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_job_ctrl(peer, buf, jctrl_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_MONITOR_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_monitor(peer, buf, monitor_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_GET_CREDENTIAL_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_get_credential(peer, buf, cred_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_VALIDATE_CRED_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_validate_credential(peer, buf, validate_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_IOF_PULL_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_iofreg(peer, buf, iof_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_IOF_PUSH_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_iofstdin(peer, buf, op_cbfunc, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_IOF_DEREG_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_iofdereg(peer, buf, iofdereg, cd))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_GROUP_CONSTRUCT_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_group(cd, buf, PMIX_GROUP_CONSTRUCT))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd); } return rc; } if (PMIX_GROUP_DESTRUCT_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_group(cd, buf, PMIX_GROUP_DESTRUCT))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_FABRIC_REGISTER_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_fabric_register(cd, buf, fabric_cbfunc))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_FABRIC_UPDATE_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_fabric_update(cd, buf, fabric_cbfunc))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_COMPUTE_DEVICE_DISTANCES_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_device_dists(cd, buf, dist_cbfunc))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_REFRESH_CACHE == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_refresh_cache(cd, buf, op_cbfunc))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_RESBLK_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_resblk(cd, buf, resop_cbfunc))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_SESSION_CTRL_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_session_ctrl(cd, buf, sessctrl_cbfunc))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_RESOLVE_PEERS_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_resolve_peers(cd, buf, respeers_cbfunc))) { PMIX_RELEASE(cd); } return rc; } if (PMIX_RESOLVE_NODE_CMD == cmd) { PMIX_GDS_CADDY(cd, peer, tag); if (PMIX_SUCCESS != (rc = pmix_server_resolve_node(cd, buf, resnodes_cbfunc))) { PMIX_RELEASE(cd); } return rc; } return PMIX_ERR_NOT_SUPPORTED; } void pmix_server_message_handler(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_peer_t *peer = (pmix_peer_t *) pr; pmix_buffer_t *reply; pmix_status_t rc, ret; pmix_output_verbose(2, pmix_server_globals.base_output, "SWITCHYARD for %s:%u:%d", peer->info->pname.nspace, peer->info->pname.rank, peer->sd); PMIX_HIDE_UNUSED_PARAMS(cbdata); ret = server_switchyard(peer, hdr->tag, buf); /* send the return, if there was an error returned */ if (PMIX_SUCCESS != ret) { reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } if (PMIX_OPERATION_SUCCEEDED == ret) { ret = PMIX_SUCCESS; } PMIX_BFROPS_PACK(rc, pr, reply, &ret, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } PMIX_SERVER_QUEUE_REPLY(rc, peer, hdr->tag, reply); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(reply); } } } pmix-6.1.1~rc2/src/server/pmix_server_connect.c0000664000175000017500000004051315203536752022015 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2020 IBM Corporation. All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_TIME_H # include #endif #include #ifndef MAX # define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #include "src/class/pmix_hotel.h" #include "src/class/pmix_list.h" #include "src/common/pmix_attributes.h" #include "src/common/pmix_iof.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/mca/plog/plog.h" #include "src/mca/pnet/pnet.h" #include "src/mca/psensor/psensor.h" #include "src/mca/ptl/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/client/pmix_client_ops.h" #include "pmix_server_ops.h" pmix_status_t pmix_server_disconnect(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc) { int32_t cnt; pmix_status_t rc; pmix_info_t *info = NULL; size_t nprocs, ninfo, ninf; pmix_server_trkr_t *trk; pmix_proc_t *procs = NULL; /* unpack the number of procs */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &nprocs, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* there must be at least one proc - we do not allow the client * to send us NULL proc as the server has no idea what to do * with that situation. Instead, the client should at least send * us their own namespace for the use-case where the connection * spans all procs in that namespace */ if (nprocs < 1) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); rc = PMIX_ERR_BAD_PARAM; goto cleanup; } /* unpack the procs */ PMIX_PROC_CREATE(procs, nprocs); if (NULL == procs) { rc = PMIX_ERR_NOMEM; goto cleanup; } cnt = nprocs; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, procs, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* sort the procs */ qsort(procs, nprocs, sizeof(pmix_proc_t), pmix_util_compare_proc); /* unpack the number of provided info structs */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &ninf, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { return rc; } ninfo = ninf + 2; PMIX_INFO_CREATE(info, ninfo); if (NULL == info) { rc = PMIX_ERR_NOMEM; goto cleanup; } /* store the default response */ rc = PMIX_SUCCESS; PMIX_INFO_LOAD(&info[ninf+1], PMIX_LOCAL_COLLECTIVE_STATUS, &rc, PMIX_STATUS); PMIX_INFO_LOAD(&info[ninf], PMIX_SORTED_PROC_ARRAY, NULL, PMIX_BOOL); if (0 < ninf) { /* unpack the info */ cnt = ninf; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { goto cleanup; } } /* find/create the local tracker for this operation */ if (NULL == (trk = pmix_server_get_tracker(NULL, procs, nprocs, PMIX_DISCONNECTNB_CMD))) { /* we don't have this tracker yet, so get a new one */ if (NULL == (trk = pmix_server_new_tracker(NULL, procs, nprocs, PMIX_DISCONNECTNB_CMD))) { /* only if a bozo error occurs */ PMIX_ERROR_LOG(PMIX_ERROR); rc = PMIX_ERROR; goto cleanup; } trk->op_cbfunc = cbfunc; } /* if the info keys have not been provided yet, pass * them along here */ if (NULL == trk->info && NULL != info) { trk->info = info; trk->ninfo = ninfo; info = NULL; ninfo = 0; } /* add this contributor to the tracker so they get * notified when we are done */ pmix_list_append(&trk->local_cbs, &cd->super); /* if all local contributions have been received, * let the local host's server know that we are at the * "fence" point - they will callback once the [dis]connect * across all participants has been completed */ if (trk->def_complete && pmix_list_get_size(&trk->local_cbs) == trk->nlocal) { if (trk->local) { /* the operation is being atomically completed and the host will * not be calling us back - ensure we notify all participants. * the cbfunc thread-shifts the call prior to processing, * so it is okay to call it directly from here */ trk->host_called = false; // the host will not be calling us back cbfunc(PMIX_SUCCESS, trk); /* ensure that the switchyard doesn't release the caddy */ rc = PMIX_SUCCESS; } else if (NULL == pmix_host_server.disconnect) { PMIX_RELEASE(trk); rc = PMIX_ERR_NOT_SUPPORTED; goto cleanup; } else { trk->host_called = true; rc = pmix_host_server.disconnect(trk->pcs, trk->npcs, trk->info, trk->ninfo, cbfunc, trk); if (PMIX_SUCCESS != rc && PMIX_OPERATION_SUCCEEDED != rc) { /* clear the caddy from this tracker so it can be * released upon return - the switchyard will send an * error to this caller, and so the op completion * function doesn't need to do so */ pmix_list_remove_item(&trk->local_cbs, &cd->super); cd->trk = NULL; /* we need to ensure that all other local participants don't * just hang waiting for the error return, so execute * the op completion function - it threadshifts the call * prior to processing, so it is okay to call it directly * from here */ trk->host_called = false; // the host will not be calling us back cbfunc(rc, trk); } else if (PMIX_OPERATION_SUCCEEDED == rc) { /* the operation was atomically completed and the host will * not be calling us back - ensure we notify all participants. * the cbfunc thread-shifts the call prior to processing, * so it is okay to call it directly from here */ trk->host_called = false; // the host will not be calling us back cbfunc(PMIX_SUCCESS, trk); /* ensure that the switchyard doesn't release the caddy */ rc = PMIX_SUCCESS; } } } else { rc = PMIX_SUCCESS; } cleanup: if (NULL != info) { PMIX_INFO_FREE(info, ninfo); } return rc; } static void connect_timeout(int sd, short args, void *cbdata) { pmix_server_trkr_t *trk = (pmix_server_trkr_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(2, pmix_server_globals.connect_output, "ALERT: connect timeout fired"); /* execute the provided callback function with the error */ if (NULL != trk->op_cbfunc) { trk->op_cbfunc(PMIX_ERR_TIMEOUT, trk); return; // the cbfunc will have cleaned up the tracker } trk->event_active = false; PMIX_RELEASE(trk); } pmix_status_t pmix_server_connect(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc) { int32_t cnt; pmix_status_t rc; pmix_proc_t *procs = NULL; pmix_info_t *info = NULL, *iptr, endpt; size_t nprocs, ninfo, n, ninf; pmix_server_trkr_t *trk; struct timeval tv = {0, 0}; pmix_output_verbose(2, pmix_server_globals.connect_output, "recvd CONNECT from peer %s:%d", cd->peer->info->pname.nspace, cd->peer->info->pname.rank); /* unpack the number of procs */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &nprocs, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* there must be at least one proc - we do not allow the client * to send us NULL proc as the server has no idea what to do * with that situation. Instead, the client should at least send * us their own namespace for the use-case where the connection * spans all procs in that namespace */ if (nprocs < 1) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); rc = PMIX_ERR_BAD_PARAM; goto cleanup; } /* unpack the procs */ PMIX_PROC_CREATE(procs, nprocs); if (NULL == procs) { rc = PMIX_ERR_NOMEM; goto cleanup; } cnt = nprocs; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, procs, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* sort the procs */ qsort(procs, nprocs, sizeof(pmix_proc_t), pmix_util_compare_proc); /* unpack the number of provided info structs */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &ninf, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } ninfo = ninf + 2; PMIX_INFO_CREATE(info, ninfo); if (NULL == info) { rc = PMIX_ERR_NOMEM; goto cleanup; } /* store the default response */ rc = PMIX_SUCCESS; PMIX_INFO_LOAD(&info[ninf+1], PMIX_LOCAL_COLLECTIVE_STATUS, &rc, PMIX_STATUS); PMIX_INFO_LOAD(&info[ninf], PMIX_SORTED_PROC_ARRAY, NULL, PMIX_BOOL); if (0 < ninf) { /* unpack the info */ cnt = ninf; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* check for a timeout */ for (n = 0; n < ninf; n++) { if (0 == strncmp(info[n].key, PMIX_TIMEOUT, PMIX_MAX_KEYLEN)) { tv.tv_sec = info[n].value.data.uint32; break; } } } /* find/create the local tracker for this operation */ if (NULL == (trk = pmix_server_get_tracker(NULL, procs, nprocs, PMIX_CONNECTNB_CMD))) { /* we don't have this tracker yet, so get a new one */ if (NULL == (trk = pmix_server_new_tracker(NULL, procs, nprocs, PMIX_CONNECTNB_CMD))) { /* only if a bozo error occurs */ PMIX_ERROR_LOG(PMIX_ERROR); /* DO NOT HANG */ if (NULL != cbfunc) { cbfunc(PMIX_ERROR, cd); } rc = PMIX_ERROR; goto cleanup; } trk->op_cbfunc = cbfunc; } /* if the info keys have not been provided yet, pass * them along here */ if (NULL == trk->info && NULL != info) { trk->info = info; trk->ninfo = ninfo; info = NULL; ninfo = 0; } // see if they provided endpt info cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &endpt, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } if (PMIX_SUCCESS == rc) { // add the endpt to the end ninf = trk->ninfo + 1; PMIX_INFO_CREATE(iptr, ninf); for (n=0; n < trk->ninfo; n++) { PMIX_INFO_XFER(&iptr[n], &trk->info[n]); } PMIX_INFO_XFER(&iptr[trk->ninfo], &endpt); PMIX_INFO_FREE(trk->info, trk->ninfo); PMIX_INFO_DESTRUCT(&endpt); trk->info = iptr; trk->ninfo = ninf; } // see if they provided job-level info cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &endpt, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } if (PMIX_SUCCESS == rc) { // add the info to the end ninf = trk->ninfo + 1; PMIX_INFO_CREATE(iptr, ninf); for (n=0; n < trk->ninfo; n++) { PMIX_INFO_XFER(&iptr[n], &trk->info[n]); } PMIX_INFO_XFER(&iptr[trk->ninfo], &endpt); PMIX_INFO_FREE(trk->info, trk->ninfo); PMIX_INFO_DESTRUCT(&endpt); trk->info = iptr; trk->ninfo = ninf; } /* add this contributor to the tracker so they get * notified when we are done */ pmix_list_append(&trk->local_cbs, &cd->super); /* if all local contributions have been received, * let the local host's server know that we are at the * "fence" point - they will callback once the [dis]connect * across all participants has been completed */ if (trk->def_complete && pmix_list_get_size(&trk->local_cbs) == trk->nlocal) { /* if all the participants are local, then we don't need the host */ if (trk->local) { /* the operation is being atomically completed and the host will * not be calling us back - ensure we notify all participants. * the cbfunc thread-shifts the call prior to processing, * so it is okay to call it directly from here */ trk->host_called = false; // the host will not be calling us back cbfunc(PMIX_SUCCESS, trk); /* ensure that the switchyard doesn't release the caddy */ rc = PMIX_SUCCESS; } else if (NULL == pmix_host_server.connect) { PMIX_RELEASE(trk); rc = PMIX_ERR_NOT_SUPPORTED; goto cleanup; } else { trk->host_called = true; rc = pmix_host_server.connect(trk->pcs, trk->npcs, trk->info, trk->ninfo, cbfunc, trk); if (PMIX_SUCCESS != rc && PMIX_OPERATION_SUCCEEDED != rc) { /* clear the caddy from this tracker so it can be * released upon return - the switchyard will send an * error to this caller, and so the op completion * function doesn't need to do so */ pmix_list_remove_item(&trk->local_cbs, &cd->super); cd->trk = NULL; /* we need to ensure that all other local participants don't * just hang waiting for the error return, so execute * the op completion function - it threadshifts the call * prior to processing, so it is okay to call it directly * from here */ trk->host_called = false; // the host will not be calling us back cbfunc(rc, trk); } else if (PMIX_OPERATION_SUCCEEDED == rc) { /* the operation was atomically completed and the host will * not be calling us back - ensure we notify all participants. * the cbfunc thread-shifts the call prior to processing, * so it is okay to call it directly from here */ trk->host_called = false; // the host will not be calling us back cbfunc(PMIX_SUCCESS, trk); /* ensure that the switchyard doesn't release the caddy */ rc = PMIX_SUCCESS; } } } else { rc = PMIX_SUCCESS; } /* if a timeout was specified, set it */ if (PMIX_SUCCESS == rc && 0 < tv.tv_sec) { PMIX_RETAIN(trk); PMIX_THREADSHIFT_DELAY(trk, connect_timeout, tv.tv_sec); trk->event_active = true; } cleanup: if (NULL != procs) { PMIX_PROC_FREE(procs, nprocs); } if (NULL != info) { PMIX_INFO_FREE(info, ninfo); } return rc; } pmix-6.1.1~rc2/src/server/pmix_server_ops.h0000664000175000017500000004255215203536752021177 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2020 IBM Corporation. All rights reserved. * Copyright (c) 2016-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ */ #ifndef PMIX_SERVER_OPS_H #define PMIX_SERVER_OPS_H #include #ifdef HAVE_SYS_TYPES_H # include #endif #include "src/include/pmix_config.h" #include "pmix_common.h" #include "pmix_server.h" #include "src/class/pmix_hotel.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_hash.h" #define PMIX_IOF_HOTEL_SIZE 256 #define PMIX_IOF_MAX_STAY 300000000 typedef struct { pmix_object_t super; pmix_event_t ev; pmix_server_trkr_t *trk; } pmix_trkr_caddy_t; PMIX_CLASS_DECLARATION(pmix_trkr_caddy_t); typedef struct { pmix_object_t super; pmix_event_t ev; pmix_lock_t lock; pmix_peer_t *peer; char *nspace; pmix_status_t status; pmix_status_t *codes; size_t ncodes; pmix_proc_t proc; pmix_proc_t *procs; size_t nprocs; uid_t uid; gid_t gid; void *server_object; int nlocalprocs; pmix_info_t *info; size_t ninfo; pmix_resource_unit_t *units; size_t nunits; bool copied; char **keys; pmix_app_t *apps; size_t napps; pmix_iof_channel_t channels; pmix_iof_flags_t flags; pmix_byte_object_t *bo; size_t nbo; /* timestamp receipt of the notification so we * can evict the oldest one if we get overwhelmed */ time_t ts; /* what room of the hotel they are in */ int room; pmix_op_cbfunc_t opcbfunc; pmix_dmodex_response_fn_t cbfunc; pmix_setup_application_cbfunc_t setupcbfunc; pmix_lookup_cbfunc_t lkcbfunc; pmix_spawn_cbfunc_t spcbfunc; void *cbdata; } pmix_setup_caddy_t; PMIX_CLASS_DECLARATION(pmix_setup_caddy_t); /* define a callback function returning inventory */ typedef void (*pmix_inventory_cbfunc_t)(pmix_status_t status, pmix_list_t *inventory, void *cbdata); /* define an object for rolling up the inventory*/ typedef struct { pmix_object_t super; pmix_lock_t lock; pmix_event_t ev; pmix_status_t status; int requests; int replies; pmix_list_t payload; // list of pmix_kval_t containing the replies pmix_info_t *info; size_t ninfo; pmix_inventory_cbfunc_t cbfunc; pmix_info_cbfunc_t infocbfunc; pmix_op_cbfunc_t opcbfunc; void *cbdata; } pmix_inventory_rollup_t; PMIX_CLASS_DECLARATION(pmix_inventory_rollup_t); typedef struct { pmix_list_item_t super; pmix_setup_caddy_t *cd; } pmix_dmdx_remote_t; PMIX_CLASS_DECLARATION(pmix_dmdx_remote_t); typedef struct { pmix_list_item_t super; pmix_proc_t proc; // id of proc whose data is being requested pmix_list_t loc_reqs; // list of pmix_dmdx_request_t elem is keeping track of // all local ranks that are interested in this namespace-rank pmix_info_t *info; // array of info structs for this request size_t ninfo; // number of info structs } pmix_dmdx_local_t; PMIX_CLASS_DECLARATION(pmix_dmdx_local_t); typedef struct { pmix_list_item_t super; pmix_event_t ev; bool event_active; pmix_dmdx_local_t *lcd; char *key; pmix_modex_cbfunc_t cbfunc; // cbfunc to be executed when data is available void *cbdata; } pmix_dmdx_request_t; PMIX_CLASS_DECLARATION(pmix_dmdx_request_t); /* event/error registration book keeping */ typedef struct { pmix_list_item_t super; pmix_peer_t *peer; bool enviro_events; pmix_proc_t *affected; size_t naffected; } pmix_peer_events_info_t; PMIX_CLASS_DECLARATION(pmix_peer_events_info_t); typedef struct { pmix_list_item_t super; pmix_list_t peers; // list of pmix_peer_events_info_t int code; } pmix_regevents_info_t; PMIX_CLASS_DECLARATION(pmix_regevents_info_t); typedef struct { pmix_list_item_t super; pmix_group_t *grp; pmix_rank_t rank; size_t idx; } pmix_group_caddy_t; PMIX_CLASS_DECLARATION(pmix_group_caddy_t); typedef struct { pmix_list_item_t super; pmix_proc_t source; pmix_iof_channel_t channel; pmix_byte_object_t *bo; pmix_info_t *info; size_t ninfo; } pmix_iof_cache_t; PMIX_CLASS_DECLARATION(pmix_iof_cache_t); typedef struct { pmix_list_item_t super; char *name; pmix_proc_t *members; size_t nmembers; } pmix_pset_t; PMIX_CLASS_DECLARATION(pmix_pset_t); typedef struct { pmix_list_t nspaces; // list of pmix_nspace_t for the nspaces we know about pmix_pointer_array_t clients; // array of pmix_peer_t local clients pmix_list_t collectives; // list of active pmix_server_trkr_t pmix_list_t remote_pnd; // list of pmix_dmdx_remote_t awaiting arrival of data fror servicing // remote req's pmix_list_t local_reqs; // list of pmix_dmdx_local_t awaiting arrival of data from local neighbours pmix_list_t gdata; // cache of data given to me for passing to all clients char **genvars; // argv array of envars given to me for passing to all clients pmix_list_t events; // list of pmix_regevents_info_t registered events pmix_list_t iof; // IO to be forwarded to clients pmix_list_t iof_residuals; // leftover bytes waiting for newline pmix_list_t psets; // list of known psets and memberships size_t max_iof_cache; // max number of IOF messages to cache bool tool_connections_allowed; char *tmpdir; // temporary directory for this server char *system_tmpdir; // system tmpdir bool fence_localonly_opt; // local-only fence optimization pmix_list_t grp_collectives; // group-op collectives pmix_pointer_array_t monitors; // monitoring operations // verbosity for server get operations int get_output; int get_verbose; // verbosity for server connect operations int connect_output; int connect_verbose; // verbosity for server fence operations int fence_output; int fence_verbose; // verbosity for server pub operations int pub_output; int pub_verbose; // verbosity for server spawn operations int spawn_output; int spawn_verbose; // verbosity for server event operations int event_output; int event_verbose; // verbosity for server iof operations int iof_output; int iof_verbose; // verbosity for basic server functions int base_output; int base_verbose; // verbosity for server group operations int group_output; int group_verbose; } pmix_server_globals_t; #define PMIX_GDS_CADDY(c, p, t) \ do { \ (c) = PMIX_NEW(pmix_server_caddy_t); \ (c)->hdr.tag = (t); \ PMIX_RETAIN((p)); \ (c)->peer = (p); \ } while (0) #define PMIX_SETUP_COLLECTIVE(c, t) \ do { \ (c) = PMIX_NEW(pmix_trkr_caddy_t); \ (c)->trk = (t); \ } while (0) #define PMIX_EXECUTE_COLLECTIVE(c, t, f) \ do { \ PMIX_SETUP_COLLECTIVE(c, t); \ pmix_event_assign(&((c)->ev), pmix_globals.evbase, -1, EV_WRITE, (f), (c)); \ pmix_event_active(&((c)->ev), EV_WRITE, 1); \ } while (0) PMIX_EXPORT bool pmix_server_trk_update(pmix_server_trkr_t *trk); PMIX_EXPORT void pmix_pending_nspace_requests(pmix_namespace_t *nptr); PMIX_EXPORT pmix_status_t pmix_pending_resolve(pmix_namespace_t *nptr, pmix_rank_t rank, pmix_status_t status, pmix_scope_t scope, pmix_dmdx_local_t *lcd); PMIX_EXPORT pmix_status_t pmix_server_abort(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_commit(pmix_peer_t *peer, pmix_buffer_t *buf); PMIX_EXPORT pmix_status_t pmix_server_fence(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_modex_cbfunc_t modexcbfunc, pmix_op_cbfunc_t opcbfunc); PMIX_EXPORT pmix_status_t pmix_server_get(pmix_buffer_t *buf, pmix_modex_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_publish(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_lookup(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_lookup_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_unpublish(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_spawn(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_spawn_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT void pmix_server_spawn_parser(pmix_peer_t *peer, pmix_iof_channel_t *channels, pmix_iof_flags_t *flags, pmix_info_t *info, size_t ninfo); PMIX_EXPORT pmix_status_t pmix_server_process_iof(pmix_setup_caddy_t *cd, char nspace[]); PMIX_EXPORT void pmix_server_spcbfunc(pmix_status_t status, char nspace[], void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_connect(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_server_disconnect(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_server_notify_error(pmix_status_t status, pmix_proc_t procs[], size_t nprocs, pmix_proc_t error_procs[], size_t error_nprocs, pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_register_events(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT void pmix_server_deregister_events(pmix_peer_t *peer, pmix_buffer_t *buf); PMIX_EXPORT pmix_status_t pmix_server_query(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_log(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_alloc(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_job_ctrl(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_monitor(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_get_credential(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_credential_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_validate_credential(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_validation_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_iofreg(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_iofstdin(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_iofdereg(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_group(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_group_operation_t op); PMIX_EXPORT pmix_status_t pmix_server_event_recvd_from_client(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT void pmix_server_execute_collective(int sd, short args, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_initialize(void); PMIX_EXPORT void pmix_server_message_handler(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); PMIX_EXPORT void pmix_server_purge_events(pmix_peer_t *peer, pmix_proc_t *proc); PMIX_EXPORT pmix_status_t pmix_server_fabric_register(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_server_fabric_update(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_server_fabric_get_vertex_info(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_server_fabric_get_device_index(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_server_device_dists(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_device_dist_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_server_refresh_cache(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_server_resblk(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_server_session_ctrl(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_server_resolve_peers(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc); PMIX_EXPORT void pmix_server_locally_resolve_peers(int sd, short args, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_resolve_node(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc); PMIX_EXPORT void pmix_server_locally_resolve_node(int sd, short args, void *cbdata); PMIX_EXPORT pmix_status_t pmix_server_process_grpinfo(size_t ctxid, pmix_info_t *pinfo, size_t npinfo); PMIX_EXPORT extern pmix_server_module_t pmix_host_server; PMIX_EXPORT extern pmix_server_globals_t pmix_server_globals; static inline pmix_peer_t* pmix_get_peer_object(const pmix_proc_t *proc) { pmix_peer_t *peer; int n; for (n=0; n < pmix_server_globals.clients.size; n++) { peer = (pmix_peer_t *) pmix_pointer_array_get_item(&pmix_server_globals.clients, n); if (NULL == peer) { continue; } if (PMIX_CHECK_NSPACE(proc->nspace, peer->info->pname.nspace) && proc->rank == peer->info->pname.rank) { return peer; } } return NULL; } // Utilities PMIX_EXPORT pmix_server_trkr_t *pmix_server_get_tracker(char *id, pmix_proc_t *procs, size_t nprocs, pmix_cmd_t type); PMIX_EXPORT pmix_server_trkr_t *pmix_server_new_tracker(char *id, pmix_proc_t *procs, size_t nprocs, pmix_cmd_t type); PMIX_EXPORT pmix_status_t pmix_server_collect_data(pmix_server_trkr_t *trk, pmix_buffer_t *buf); #endif // PMIX_SERVER_OPS_H pmix-6.1.1~rc2/src/server/Makefile.include0000664000175000017500000000135515203536752020660 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2014-2020 Intel, Inc. All rights reserved. # Copyright (c) 2014 Artem Y. Polyakov . # All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2024-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # EXTRA_DIST += server/help-pmix-server.txt headers += \ server/pmix_server_ops.h sources += \ server/pmix_server.c \ server/pmix_server_ops.c \ server/pmix_server_get.c \ server/pmix_server_group.c \ server/pmix_server_fence.c \ server/pmix_server_connect.c \ server/pmix_server_resolve.c pmix-6.1.1~rc2/src/server/pmix_server_group.c0000664000175000017500000010357215203536752021525 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2020 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_TIME_H # include #endif #include #ifndef MAX # define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #include "src/class/pmix_hotel.h" #include "src/class/pmix_list.h" #include "src/common/pmix_attributes.h" #include "src/common/pmix_iof.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/mca/plog/plog.h" #include "src/mca/pnet/pnet.h" #include "src/mca/psensor/psensor.h" #include "src/mca/ptl/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/client/pmix_client_ops.h" #include "pmix_server_ops.h" /* DEFINE A LOCAL GROUP COLLECTIVE TRACKER AND SHIFTER */ typedef struct { pmix_list_item_t super; char *id; int grpop; // the group operation being tracked pmix_event_t ev; bool event_active; bool need_cxtid; pmix_proc_t *pcs; size_t npcs; pmix_info_t *info; size_t ninfo; pmix_list_t mbrs; // list of grp_trk_t bool def_complete; // all local procs have been registered and the trk definition is complete uint32_t nlocal; // number of local participants uint32_t local_cnt; // number of local participants who have contributed } grp_block_t; static void gbcon(grp_block_t *p) { p->id = NULL; p->grpop = PMIX_GROUP_NONE; p->event_active = false; p->need_cxtid = false; p->pcs = NULL; p->npcs = 0; p->info = NULL; p->ninfo = 0; PMIX_CONSTRUCT(&p->mbrs, pmix_list_t); p->def_complete = false; p->nlocal = 0; p->local_cnt = 0; } static void gbdes(grp_block_t *p) { if (NULL != p->id) { free(p->id); } if (NULL != p->pcs) { PMIX_PROC_FREE(p->pcs, p->npcs); } if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->ninfo); } PMIX_LIST_DESTRUCT(&p->mbrs); } static PMIX_CLASS_INSTANCE(grp_block_t, pmix_list_item_t, gbcon, gbdes); typedef struct { pmix_list_item_t super; pmix_event_t ev; bool event_active; pmix_lock_t lock; char *id; grp_block_t *blk; bool host_called; bool hybrid; pmix_proc_t *pcs; size_t npcs; pmix_info_t *info; size_t ninfo; pmix_list_t local_cbs; // list of pmix_server_caddy_t for sending result to the local participants } grp_trk_t; static void gtcon(grp_trk_t *t) { t->event_active = false; PMIX_CONSTRUCT_LOCK(&t->lock); t->id = NULL; t->blk = NULL; t->host_called = false; t->hybrid = false; t->pcs = NULL; t->npcs = 0; t->info = NULL; t->ninfo = 0; PMIX_CONSTRUCT(&t->local_cbs, pmix_list_t); } static void gtdes(grp_trk_t *t) { PMIX_DESTRUCT_LOCK(&t->lock); if (NULL != t->blk) { PMIX_RELEASE(t->blk); } PMIX_LIST_DESTRUCT(&t->local_cbs); } static PMIX_CLASS_INSTANCE(grp_trk_t, pmix_list_item_t, gtcon, gtdes); typedef struct { pmix_object_t super; pmix_event_t ev; pmix_lock_t lock; pmix_status_t status; pmix_info_t *info; size_t ninfo; grp_block_t *blk; pmix_release_cbfunc_t relfn; void *cbdata; } grp_shifter_t; static void scon(grp_shifter_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); p->info = NULL; p->ninfo = 0; p->blk = NULL; p->relfn = NULL; p->cbdata = NULL; } static void sdes(grp_shifter_t *p) { PMIX_DESTRUCT_LOCK(&p->lock); } PMIX_EXPORT PMIX_CLASS_INSTANCE(grp_shifter_t, pmix_object_t, scon, sdes); /* DEFINE LOCAL FUNCTIONS */ static pmix_status_t aggregate_info(grp_block_t *blk); static void check_definition_complete(grp_block_t *blk) { pmix_namespace_t *ns, *nptr; pmix_rank_info_t *info; size_t i; uint32_t nlocal = 0; grp_trk_t *trk; if (blk->def_complete) { return; } PMIX_LIST_FOREACH(trk, &blk->mbrs, grp_trk_t) { for (i = 0; i < trk->npcs; i++) { /* is this nspace known to us? */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(trk->pcs[i].nspace, ns->nspace)) { nptr = ns; break; } } if (NULL == nptr) { /* we don't know about this nspace - we need to * wait until it has been registered */ return; } /* it is possible we know about this nspace because the host * has registered one or more clients via "register_client", * but the host has not yet called "register_nspace". There is * a very tiny race condition whereby this can happen due * to event-driven processing, but account for it here */ if (SIZE_MAX == nptr->nlocalprocs) { /* delay processing until this nspace is registered */ return; } if (0 == nptr->nlocalprocs) { /* the host has informed us that this nspace has no local procs */ pmix_output_verbose(5, pmix_server_globals.fence_output, "pmix_server_new_tracker: nspace %s has no local procs", trk->pcs[i].nspace); continue; } /* if they want all the local members of this nspace, then * add them in here. They told us how many procs will be * local to us from this nspace, but we don't know their * ranks. So as long as they want _all_ of them, we can * handle that case regardless of whether the individual * clients have been "registered" */ if (PMIX_RANK_WILDCARD == trk->pcs[i].rank) { nlocal += nptr->nlocalprocs; continue; } /* They don't want all the local clients, or they are at * least listing them individually. Check if all the clients * for this nspace have been registered via "register_client" * so we know the specific ranks on this node */ if (!nptr->all_registered) { /* nope, so no point in going further on this one - we'll * process it once all the procs are known */ pmix_output_verbose(5, pmix_server_globals.fence_output, "pmix_server_new_tracker: all clients not registered nspace %s", trk->pcs[i].nspace); return; } /* is this one of my local ranks? */ PMIX_LIST_FOREACH (info, &nptr->ranks, pmix_rank_info_t) { if (trk->pcs[i].rank == info->pname.rank) { pmix_output_verbose(5, pmix_server_globals.fence_output, "adding local proc %s.%d to tracker", info->pname.nspace, info->pname.rank); /* track the count */ nlocal++; break; } } } } // if we get here, then we have completed definition of the block blk->def_complete = true; blk->nlocal = nlocal; } static pmix_status_t get_tracker(char *grpid, bool bootstrap, bool follower, pmix_proc_t *procs, size_t nprocs, pmix_info_t *info, size_t ninfo, grp_block_t **block, grp_trk_t **tracker) { grp_block_t *blk; grp_trk_t *trk; if (follower || bootstrap) { // bootstrap operations maintain independent trackers // since we don't know who is going to participate as // a leader goto newblock; } // see if we already have a block for this ID PMIX_LIST_FOREACH(blk, &pmix_server_globals.grp_collectives, grp_block_t) { if (0 == strcmp(grpid, blk->id)) { // we do - pass it back *block = blk; // new signature, so create a tracker for it trk = PMIX_NEW(grp_trk_t); PMIX_RETAIN(blk); trk->blk = blk; trk->npcs = nprocs; PMIX_PROC_CREATE(trk->pcs, trk->npcs); memcpy(trk->pcs, procs, nprocs * sizeof(pmix_proc_t)); trk->info = info; trk->ninfo = ninfo; pmix_list_append(&blk->mbrs, &trk->super); *tracker = trk; check_definition_complete(blk); return PMIX_SUCCESS; } } newblock: // new block blk = PMIX_NEW(grp_block_t); blk->id = strdup(grpid); pmix_list_append(&pmix_server_globals.grp_collectives, &blk->super); *block = blk; // setup a tracker for it trk = PMIX_NEW(grp_trk_t); PMIX_RETAIN(blk); trk->npcs = nprocs; if (NULL != procs) { PMIX_PROC_CREATE(trk->pcs, trk->npcs); memcpy(trk->pcs, procs, nprocs * sizeof(pmix_proc_t)); } trk->blk = blk; trk->info = info; trk->ninfo = ninfo; pmix_list_append(&blk->mbrs, &trk->super); if (follower || bootstrap) { blk->def_complete = true; } else { check_definition_complete(blk); } *tracker = trk; return PMIX_SUCCESS; } pmix_status_t pmix_server_process_grpinfo(size_t ctxid, pmix_info_t *pinfo, size_t npinfo) { size_t m; pmix_kval_t kp; pmix_value_t val; pmix_data_array_t darray; pmix_info_t *piptr; pmix_status_t rc; pmix_proc_t procid; // the first element in the array must be the procID // of the process that contributed this info if (!PMIX_CHECK_KEY(&pinfo[0], PMIX_PROCID)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } memcpy(&procid, pinfo[0].value.data.proc, sizeof(pmix_proc_t)); /* reconstruct each value as a qualified one based * on the ctxid */ PMIX_CONSTRUCT(&kp, pmix_kval_t); kp.value = &val; kp.key = PMIX_QUALIFIED_VALUE; val.type = PMIX_DATA_ARRAY; for (m=1; m < npinfo; m++) { PMIX_DATA_ARRAY_CONSTRUCT(&darray, 2, PMIX_INFO); piptr = (pmix_info_t*)darray.array; /* the primary value is in the first position */ PMIX_INFO_XFER(&piptr[0], &pinfo[m]); /* add the context ID qualifier */ PMIX_INFO_LOAD(&piptr[1], PMIX_GROUP_CONTEXT_ID, &ctxid, PMIX_SIZE); PMIX_INFO_SET_QUALIFIER(&piptr[1]); /* add it to the kval */ val.data.darray = &darray; /* store it */ PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &procid, PMIX_GLOBAL, &kp); PMIX_DATA_ARRAY_DESTRUCT(&darray); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } return PMIX_SUCCESS; } static void _grpcbfunc(int sd, short args, void *cbdata) { grp_shifter_t *scd = (grp_shifter_t *) cbdata; grp_block_t *blk = scd->blk, *bk; char *id; pmix_group_operation_t op; grp_trk_t *trk; pmix_server_caddy_t *cd; pmix_buffer_t *reply; pmix_status_t ret, rc; size_t n, ctxid = SIZE_MAX, nmembers = 0; pmix_proc_t *members = NULL; bool ctxid_given = false; pmix_info_t *iptr, *pinfo; size_t ninfo, npinfo; pmix_list_t grpinfo; pmix_info_caddy_t *g=NULL; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(scd); if (NULL == blk) { /* give them a release if they want it - this should * never happen, but protect against the possibility */ if (NULL != scd->relfn) { scd->relfn(scd->cbdata); } PMIX_RELEASE(scd); return; } PMIX_CONSTRUCT(&grpinfo, pmix_list_t); /* see if this group was assigned a context ID or collected data */ for (n = 0; n < scd->ninfo; n++) { if (PMIX_CHECK_KEY(&scd->info[n], PMIX_GROUP_CONTEXT_ID)) { ret = PMIx_Value_get_number(&scd->info[n].value, &ctxid, PMIX_SIZE); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); } else { ctxid_given = true; } } else if (PMIX_CHECK_KEY(&scd->info[n], PMIX_GROUP_MEMBERSHIP)) { members = (pmix_proc_t*)scd->info[n].value.data.darray->array; nmembers = scd->info[n].value.data.darray->size; } else if (PMIX_CHECK_KEY(&scd->info[n], PMIX_GROUP_INFO_ARRAY) || PMIX_CHECK_KEY(&scd->info[n], PMIX_GROUP_INFO)) { g = PMIX_NEW(pmix_info_caddy_t); g->info = &scd->info[n]; pmix_list_append(&grpinfo, &g->super); } } // preserve the group id id = strdup(blk->id); op = blk->grpop; // if group info was provided, then we need to store it // in our hash table too if (0 < pmix_list_get_size(&grpinfo)) { // must have been given a context ID if (!ctxid_given) { if (NULL != scd->relfn) { scd->relfn(scd->cbdata); } PMIX_RELEASE(scd); PMIX_LIST_DESTRUCT(&grpinfo); return; } /* Each list member points to a pmix_info_t that contains * a data array of info from a given proc */ PMIX_LIST_FOREACH(g, &grpinfo, pmix_info_caddy_t) { iptr = (pmix_info_t*)g->info->value.data.darray->array; ninfo = g->info->value.data.darray->size; if (PMIX_CHECK_KEY(g->info, PMIX_GROUP_INFO)) { // this is just a single array of group info rc = pmix_server_process_grpinfo(ctxid, iptr, ninfo); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); if (NULL != scd->relfn) { scd->relfn(scd->cbdata); } PMIX_RELEASE(scd); PMIX_LIST_DESTRUCT(&grpinfo); return; } } else { // contains an array of group info arrays for (n=0; n < ninfo; n++) { pinfo = (pmix_info_t*)iptr[n].value.data.darray->array; npinfo = iptr[n].value.data.darray->size; rc = pmix_server_process_grpinfo(ctxid, pinfo, npinfo); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); if (NULL != scd->relfn) { scd->relfn(scd->cbdata); } PMIX_RELEASE(scd); PMIX_LIST_DESTRUCT(&grpinfo); return; } } } } } // because bootstrap will have added multiple blocks to the collectives // for each bootstrap operation, cycle across the list to find them all PMIX_LIST_FOREACH(bk, &pmix_server_globals.grp_collectives, grp_block_t) { if (0 != strcmp(id, bk->id)) { continue; } PMIX_LIST_FOREACH(trk, &bk->mbrs, grp_trk_t) { pmix_output_verbose(2, pmix_server_globals.group_output, "server:grpcbfunc processing WITH %d CALLBACKS", (int) pmix_list_get_size(&trk->local_cbs)); /* loop across all procs in the tracker, sending them the reply */ PMIX_LIST_FOREACH (cd, &trk->local_cbs, pmix_server_caddy_t) { reply = PMIX_NEW(pmix_buffer_t); if (NULL == reply) { break; } /* setup the reply, starting with the returned status */ PMIX_BFROPS_PACK(ret, cd->peer, reply, &scd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(reply); break; } if (PMIX_SUCCESS == scd->status && PMIX_GROUP_CONSTRUCT == op) { /* add the final membership */ PMIX_BFROPS_PACK(ret, cd->peer, reply, &nmembers, 1, PMIX_SIZE); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(reply); break; } if (0 < nmembers) { PMIX_BFROPS_PACK(ret, cd->peer, reply, members, nmembers, PMIX_PROC); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(reply); break; } } /* if a ctxid was provided, pass it along */ PMIX_BFROPS_PACK(ret, cd->peer, reply, &ctxid_given, 1, PMIX_BOOL); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(reply); break; } if (ctxid_given) { PMIX_BFROPS_PACK(ret, cd->peer, reply, &ctxid, 1, PMIX_SIZE); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(reply); break; } } /* add any group info */ ninfo = pmix_list_get_size(&grpinfo); PMIX_BFROPS_PACK(ret, cd->peer, reply, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(reply); break; } if (0 < ninfo) { PMIX_LIST_FOREACH(g, &grpinfo, pmix_info_caddy_t) { PMIX_BFROPS_PACK(ret, cd->peer, reply, g->info, 1, PMIX_INFO); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(reply); break; } } } } pmix_output_verbose(2, pmix_server_globals.group_output, "server:grp_cbfunc reply being sent to %s:%u", cd->peer->info->pname.nspace, cd->peer->info->pname.rank); PMIX_SERVER_QUEUE_REPLY(ret, cd->peer, cd->hdr.tag, reply); if (PMIX_SUCCESS != ret) { PMIX_RELEASE(reply); } } } /* remove the block from the list */ pmix_list_remove_item(&pmix_server_globals.grp_collectives, &bk->super); PMIX_RELEASE(bk); } /* we are done */ free(id); if (NULL != scd->relfn) { scd->relfn(scd->cbdata); } PMIX_RELEASE(scd); } static void grpcbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t relfn, void *relcbd) { grp_block_t *blk = (grp_block_t *) cbdata; grp_shifter_t *scd; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(blk); return; } pmix_output_verbose(2, pmix_server_globals.group_output, "server:grpcbfunc called with %d info", (int) ninfo); if (NULL == blk) { /* nothing to do - but be sure to give them * a release if they want it */ if (NULL != relfn) { relfn(relcbd); } return; } /* need to thread-shift this callback as it accesses global data */ scd = PMIX_NEW(grp_shifter_t); if (NULL == scd) { /* nothing we can do */ if (NULL != relfn) { relfn(cbdata); } return; } scd->status = status; scd->info = info; scd->ninfo = ninfo; scd->blk = blk; scd->relfn = relfn; scd->cbdata = relcbd; PMIX_THREADSHIFT(scd, _grpcbfunc); } static pmix_status_t aggregate_info(grp_block_t *blk) { grp_trk_t *trk; pmix_list_t ilist, nmlist, plist; size_t n, m, j, k, niptr; pmix_info_t *iptr; bool found, nmfound; pmix_info_caddy_t *icd; pmix_proclist_t *nm; pmix_proc_t *nmarray, *trkarray, *tmp; size_t nmsize, trksize, bt, bt2; pmix_status_t rc; // only keep unique entries PMIX_CONSTRUCT(&ilist, pmix_list_t); PMIX_CONSTRUCT(&plist, pmix_list_t); PMIX_LIST_FOREACH(trk, &blk->mbrs, grp_trk_t) { // aggregate procs for (n=0; n < trk->npcs; n++) { found = false; for (m=0; m < blk->npcs; m++) { if (PMIX_CHECK_PROCID(&trk->pcs[n], &blk->pcs[m])) { found = true; // preserve WILDCARD rank if (PMIX_RANK_WILDCARD == trk->pcs[n].rank) { blk->pcs[m].rank = PMIX_RANK_WILDCARD; } break; } } if (!found) { nm = PMIX_NEW(pmix_proclist_t); memcpy(&nm->proc, &trk->pcs[n], sizeof(pmix_proc_t)); pmix_list_append(&plist, &nm->super); } } // aggregate info structs for (n=0; n < trk->ninfo; n++) { found = false; for (m=0; m < blk->ninfo; m++) { // if the keys match, then aggregate the values if (PMIX_CHECK_KEY(&trk->info[n], blk->info[m].key)) { // check a few critical keys if (PMIX_CHECK_KEY(&blk->info[m], PMIX_GROUP_ADD_MEMBERS)) { // aggregate the members nmarray = (pmix_proc_t*)blk->info[m].value.data.darray->array; nmsize = blk->info[m].value.data.darray->size; trkarray = (pmix_proc_t*)trk->info[n].value.data.darray->array; trksize = trk->info[n].value.data.darray->size; PMIX_CONSTRUCT(&nmlist, pmix_list_t); // sadly, an exhaustive search for (k=0; k < trksize; k++) { nmfound = false; for (j=0; j < nmsize; j++) { if (PMIX_CHECK_PROCID(&nmarray[j], &trkarray[k])) { // if the new one is rank=WILDCARD, then ensure // we keep it as wildcard if (PMIX_RANK_WILDCARD == trkarray[k].rank) { nmarray[j].rank = PMIX_RANK_WILDCARD; } nmfound = true; break; } } if (!nmfound) { nm = PMIX_NEW(pmix_proclist_t); memcpy(&nm->proc, &trkarray[k], sizeof(pmix_proc_t)); pmix_list_append(&nmlist, &nm->super); } } // create the replacement array, if needed if (0 < pmix_list_get_size(&nmlist)) { bt = nmsize + pmix_list_get_size(&nmlist); PMIX_PROC_CREATE(tmp, bt); memcpy(tmp, nmarray, nmsize * sizeof(pmix_proc_t)); j = nmsize; PMIX_LIST_FOREACH(nm, &nmlist, pmix_proclist_t) { memcpy(&tmp[j], &nm->proc, sizeof(pmix_proc_t)); ++j; } PMIX_PROC_FREE(nmarray, nmsize); blk->info[m].value.data.darray->array = tmp; blk->info[m].value.data.darray->size = bt; } PMIX_LIST_DESTRUCT(&nmlist); } else if (PMIX_CHECK_KEY(&blk->info[m], PMIX_GROUP_BOOTSTRAP)) { // the numbers must match rc = PMIx_Value_get_number(&blk->info[m].value, &bt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&ilist); return rc; } rc = PMIx_Value_get_number(&trk->info[n].value, &bt2, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&ilist); return rc; } if (bt != bt2) { PMIX_LIST_DESTRUCT(&ilist); return PMIX_ERR_BAD_PARAM; } } else if (PMIX_CHECK_KEY(&blk->info[m], PMIX_PROC_DATA) || PMIX_CHECK_KEY(&blk->info[m], PMIX_GROUP_INFO)) { // keep the duplicates icd = PMIX_NEW(pmix_info_caddy_t); icd->info = &trk->info[n]; icd->ninfo = 1; pmix_list_append(&ilist, &icd->super); } found = true; break; } } if (!found) { // add this one in icd = PMIX_NEW(pmix_info_caddy_t); icd->info = &trk->info[n]; icd->ninfo = 1; pmix_list_append(&ilist, &icd->super); } } } if (0 < pmix_list_get_size(&plist)) { m = blk->npcs + pmix_list_get_size(&plist); PMIX_PROC_CREATE(tmp, m); if (NULL != blk->pcs) { memcpy(tmp, blk->pcs, blk->npcs * sizeof(pmix_proc_t)); } n = blk->npcs; PMIX_LIST_FOREACH(nm, &plist, pmix_proclist_t) { memcpy(&tmp[n], &nm->proc, sizeof(pmix_proc_t)); n++; } if (NULL != blk->pcs) { PMIX_PROC_FREE(blk->pcs, blk->npcs); } blk->pcs = tmp; blk->npcs = m; } if (0 < pmix_list_get_size(&ilist)) { niptr = blk->ninfo + pmix_list_get_size(&ilist); PMIX_INFO_CREATE(iptr, niptr); for (n=0; n < blk->ninfo; n++) { PMIX_INFO_XFER(&iptr[n], &blk->info[n]); } n = blk->ninfo; PMIX_LIST_FOREACH(icd, &ilist, pmix_info_caddy_t) { PMIX_INFO_XFER(&iptr[n], icd->info); ++n; } PMIX_INFO_FREE(blk->info, blk->ninfo); blk->info = iptr; blk->ninfo = niptr; /* cleanup */ } PMIX_LIST_DESTRUCT(&ilist); PMIX_LIST_DESTRUCT(&plist); return PMIX_SUCCESS; } /* we are being called from the PMIx server's switchyard function, * which means we are in an event and can access global data */ pmix_status_t pmix_server_group(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_group_operation_t op) { pmix_peer_t *peer = (pmix_peer_t *) cd->peer; int32_t cnt; pmix_status_t rc; char *grpid; pmix_proc_t *procs = NULL; pmix_info_t *info = NULL; size_t n, ninfo, ninf, nprocs; grp_block_t *blk; grp_trk_t *trk; bool need_cxtid = false; bool bootstrap = false; bool follower = false; pmix_output_verbose(2, pmix_server_globals.group_output, "recvd grpconstruct cmd from %s", PMIX_PEER_PRINT(cd->peer)); /* check if our host supports group operations */ if (NULL == pmix_host_server.group) { /* cannot support it */ return PMIX_ERR_NOT_SUPPORTED; } /* unpack the group ID */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &grpid, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } /* unpack the number of procs */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &nprocs, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } if (0 < nprocs) { PMIX_PROC_CREATE(procs, nprocs); if (NULL == procs) { rc = PMIX_ERR_NOMEM; goto error; } cnt = nprocs; PMIX_BFROPS_UNPACK(rc, peer, buf, procs, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_PROC_FREE(procs, nprocs); goto error; } } else { // if no procs were given, then this must be a follower follower = true; } /* unpack the number of directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninf, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } ninfo = ninf + 1; PMIX_INFO_CREATE(info, ninfo); /* store default response */ rc = PMIX_SUCCESS; PMIX_INFO_LOAD(&info[ninf], PMIX_LOCAL_COLLECTIVE_STATUS, &rc, PMIX_STATUS); if (0 < ninf) { cnt = ninf; PMIX_BFROPS_UNPACK(rc, peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } } /* check directives */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_GROUP_ASSIGN_CONTEXT_ID)) { need_cxtid = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_GROUP_BOOTSTRAP)) { // we don't care what the number is, we only care that // bootstrap is being given bootstrap = true; } } /* find/create the local tracker for this operation */ rc = get_tracker(grpid, bootstrap, follower, procs, nprocs, info, ninfo, &blk, &trk); if (PMIX_EXISTS == rc) { // we extended the trk's info array PMIX_INFO_FREE(info, ninfo); info = NULL; ninfo = 0; } // grpid has been copied into the tracker free(grpid); // mark as a construct op blk->grpop = op; // track ctx id request if (!blk->need_cxtid) { blk->need_cxtid = need_cxtid; } // track the callback pmix_list_append(&trk->local_cbs, &cd->super); if (follower || bootstrap) { /* this is an add-member, so pass it up by itself. We cannot * know if there will be a group leader calling from this node, * so we cannot aggregate info from this proc. We therefore pass * everything up separately and rely on the host to properly * deal with it */ rc = pmix_host_server.group(PMIX_GROUP_CONSTRUCT, blk->id, procs, nprocs, trk->info, trk->ninfo, grpcbfunc, blk); if (PMIX_OPERATION_SUCCEEDED == rc) { // the host will not be calling back /* let the grpcbfunc threadshift the result */ grpcbfunc(PMIX_SUCCESS, NULL, 0, blk, NULL, NULL); return PMIX_SUCCESS; } if (PMIX_SUCCESS != rc) { pmix_list_remove_item(&trk->local_cbs, &cd->super); // the trk will be released when we release the blk pmix_list_remove_item(&pmix_server_globals.grp_collectives, &blk->super); PMIX_RELEASE(blk); return rc; } return PMIX_SUCCESS; } /* are we locally complete? */ if (!blk->def_complete || pmix_list_get_size(&blk->mbrs) != blk->nlocal) { /* if we are not locally complete, then we are done */ return PMIX_SUCCESS; } pmix_output_verbose(2, pmix_server_globals.group_output, "local group op complete with %d procs", (int) trk->npcs); rc = aggregate_info(blk); if (PMIX_SUCCESS != rc) { pmix_list_remove_item(&trk->local_cbs, &cd->super); // the trk will be released when we release the blk pmix_list_remove_item(&pmix_server_globals.grp_collectives, &blk->super); PMIX_RELEASE(blk); return rc; } rc = pmix_host_server.group(op, blk->id, trk->pcs, trk->npcs, blk->info, blk->ninfo, grpcbfunc, blk); if (PMIX_SUCCESS != rc) { if (PMIX_OPERATION_SUCCEEDED == rc) { /* let the grpcbfunc threadshift the result */ grpcbfunc(PMIX_SUCCESS, NULL, 0, blk, NULL, NULL); return PMIX_SUCCESS; } /* remove the tracker from the list */ pmix_list_remove_item(&pmix_server_globals.grp_collectives, &blk->super); PMIX_RELEASE(blk); return rc; } return PMIX_SUCCESS; error: if (NULL != info) { PMIX_INFO_FREE(info, ninfo); } return rc; } pmix-6.1.1~rc2/src/server/help-pmix-server.txt0000664000175000017500000000112415203536752021540 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2024-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # # [listener-thread-start] The PMIx server's listener thread failed to start. We cannot continue. # [collection-mismatch] Collection strategy during a collective operation (e.g., PMIx_Fence) is not homogeneous - at least one participating node has a collection strategy (i.e., collect vs non-collect) that differs from the other nodes. This must be corrected in order for us to proceed. pmix-6.1.1~rc2/src/server/pmix_server_ops.c0000664000175000017500000030645115203536752021173 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2020 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix_server.h" #include "src/mca/pcompress/pcompress.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_TIME_H # include #endif #include #ifndef MAX # define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #include "src/class/pmix_hotel.h" #include "src/class/pmix_list.h" #include "src/common/pmix_attributes.h" #include "src/common/pmix_iof.h" #include "src/common/pmix_monitor.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/mca/plog/base/base.h" #include "src/mca/pnet/pnet.h" #include "src/mca/psensor/psensor.h" #include "src/mca/ptl/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/client/pmix_client_ops.h" #include "pmix_server_ops.h" pmix_server_module_t pmix_host_server = { .client_connected = NULL, .client_finalized = NULL, .abort = NULL, .fence_nb = NULL, .direct_modex = NULL, .publish = NULL, .lookup = NULL, .unpublish = NULL, .spawn = NULL, .connect = NULL, .disconnect = NULL, .register_events = NULL, .deregister_events = NULL, .listener = NULL, .notify_event = NULL, .query = NULL, .tool_connected = NULL, .tool_connected2 = NULL, .log = NULL, .log2 = NULL, .allocate = NULL, .job_control = NULL, .monitor = NULL, .get_credential = NULL, .validate_credential = NULL, .iof_pull = NULL, .push_stdin = NULL, .group = NULL, .fabric = NULL, .client_connected2 = NULL, .session_control = NULL }; static void abcbfn(pmix_status_t status, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t*)cbdata; if (NULL != cd->opcbfunc) { cd->opcbfunc(status, cd->cbdata); } PMIX_RELEASE(cd); } pmix_status_t pmix_server_abort(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; int32_t cnt; pmix_status_t rc; pmix_proc_t proc; pmix_output_verbose(2, pmix_server_globals.base_output, "recvd ABORT"); cd = PMIX_NEW(pmix_setup_caddy_t); cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); return rc; } /* unpack the message */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->nspace, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); return rc; } /* unpack the number of procs */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->nprocs, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); return rc; } /* unpack any provided procs - these are the procs the caller * wants aborted */ if (0 < cd->nprocs) { PMIX_PROC_CREATE(cd->procs, cd->nprocs); if (NULL == cd->procs) { PMIX_RELEASE(cd); return PMIX_ERR_NOMEM; } cnt = cd->nprocs; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->procs, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); return rc; } } /* let the local host's server execute it */ if (NULL != pmix_host_server.abort) { pmix_strncpy(proc.nspace, peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = peer->info->pname.rank; rc = pmix_host_server.abort(&proc, peer->info->server_object, cd->status, cd->nspace, cd->procs, cd->nprocs, abcbfn, cd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); } } else { PMIX_RELEASE(cd); rc = PMIX_ERR_NOT_SUPPORTED; } return rc; } static void opcbfunc(pmix_status_t status, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; if (NULL != cd->keys) { PMIx_Argv_free(cd->keys); } if (NULL != cd->codes) { free(cd->codes); } if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } if (NULL != cd->opcbfunc) { cd->opcbfunc(status, cd->cbdata); } PMIX_RELEASE(cd); } pmix_status_t pmix_server_publish(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; pmix_status_t rc; int32_t cnt; size_t ninfo; pmix_proc_t proc; uint32_t uid; pmix_output_verbose(2, pmix_server_globals.pub_output, "recvd PUBLISH"); if (NULL == pmix_host_server.publish) { return PMIX_ERR_NOT_SUPPORTED; } /* unpack the effective user id */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &uid, &cnt, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* unpack the number of info objects */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* we will be adding one for the user id */ cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->opcbfunc = cbfunc; cd->cbdata = cbdata; cd->ninfo = ninfo + 1; PMIX_INFO_CREATE(cd->info, cd->ninfo); if (NULL == cd->info) { rc = PMIX_ERR_NOMEM; goto cleanup; } /* unpack the array of info objects */ if (0 < cd->ninfo) { cnt = cd->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } pmix_strncpy(cd->info[cd->ninfo - 1].key, PMIX_USERID, PMIX_MAX_KEYLEN); cd->info[cd->ninfo - 1].value.type = PMIX_UINT32; cd->info[cd->ninfo - 1].value.data.uint32 = uid; /* call the local server */ pmix_strncpy(proc.nspace, peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = peer->info->pname.rank; rc = pmix_host_server.publish(&proc, cd->info, cd->ninfo, opcbfunc, cd); cleanup: if (PMIX_SUCCESS != rc) { if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } PMIX_RELEASE(cd); } return rc; } static void lkcbfunc(pmix_status_t status, pmix_pdata_t data[], size_t ndata, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; /* cleanup the caddy */ if (NULL != cd->keys) { PMIx_Argv_free(cd->keys); } if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } /* return the results */ if (NULL != cd->lkcbfunc) { cd->lkcbfunc(status, data, ndata, cd->cbdata); } PMIX_RELEASE(cd); } pmix_status_t pmix_server_lookup(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_lookup_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; int32_t cnt; pmix_status_t rc; size_t nkeys, i; char *sptr; size_t ninfo; pmix_proc_t proc; uint32_t uid; pmix_output_verbose(2, pmix_server_globals.pub_output, "recvd LOOKUP"); if (NULL == pmix_host_server.lookup) { return PMIX_ERR_NOT_SUPPORTED; } /* unpack the effective user id */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &uid, &cnt, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* unpack the number of keys */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &nkeys, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* setup the caddy */ cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->lkcbfunc = cbfunc; cd->cbdata = cbdata; /* unpack the array of keys */ for (i = 0; i < nkeys; i++) { cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &sptr, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } PMIx_Argv_append_nosize(&cd->keys, sptr); free(sptr); } /* unpack the number of info objects */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* we will be adding one for the user id */ cd->ninfo = ninfo + 1; PMIX_INFO_CREATE(cd->info, cd->ninfo); if (NULL == cd->info) { rc = PMIX_ERR_NOMEM; goto cleanup; } /* unpack the array of info objects */ if (0 < ninfo) { cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } pmix_strncpy(cd->info[cd->ninfo - 1].key, PMIX_USERID, PMIX_MAX_KEYLEN); cd->info[cd->ninfo - 1].value.type = PMIX_UINT32; cd->info[cd->ninfo - 1].value.data.uint32 = uid; /* call the local server */ pmix_strncpy(proc.nspace, peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = peer->info->pname.rank; rc = pmix_host_server.lookup(&proc, cd->keys, cd->info, cd->ninfo, lkcbfunc, cd); cleanup: if (PMIX_SUCCESS != rc) { if (NULL != cd->keys) { PMIx_Argv_free(cd->keys); } if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } PMIX_RELEASE(cd); } return rc; } pmix_status_t pmix_server_unpublish(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; int32_t cnt; pmix_status_t rc; size_t i, nkeys, ninfo; char *sptr; pmix_proc_t proc; uint32_t uid; pmix_output_verbose(2, pmix_server_globals.pub_output, "recvd UNPUBLISH"); if (NULL == pmix_host_server.unpublish) { return PMIX_ERR_NOT_SUPPORTED; } /* unpack the effective user id */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &uid, &cnt, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* unpack the number of keys */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &nkeys, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* setup the caddy */ cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* unpack the array of keys */ for (i = 0; i < nkeys; i++) { cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &sptr, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } PMIx_Argv_append_nosize(&cd->keys, sptr); free(sptr); } /* unpack the number of info objects */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* we will be adding one for the user id */ cd->ninfo = ninfo + 1; PMIX_INFO_CREATE(cd->info, cd->ninfo); if (NULL == cd->info) { rc = PMIX_ERR_NOMEM; goto cleanup; } /* unpack the array of info objects */ if (0 < ninfo) { cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } pmix_strncpy(cd->info[cd->ninfo - 1].key, PMIX_USERID, PMIX_MAX_KEYLEN); cd->info[cd->ninfo - 1].value.type = PMIX_UINT32; cd->info[cd->ninfo - 1].value.data.uint32 = uid; /* call the local server */ pmix_strncpy(proc.nspace, peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = peer->info->pname.rank; rc = pmix_host_server.unpublish(&proc, cd->keys, cd->info, cd->ninfo, opcbfunc, cd); cleanup: if (PMIX_SUCCESS != rc) { if (NULL != cd->keys) { PMIx_Argv_free(cd->keys); } if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } PMIX_RELEASE(cd); } return rc; } pmix_status_t pmix_server_process_iof(pmix_setup_caddy_t *cd, char nspace[]) { pmix_iof_req_t *req; pmix_status_t rc; pmix_iof_cache_t *iof, *ionext; // if no channels to forward, just return success if (PMIX_FWD_NO_CHANNELS == cd->channels) { return PMIX_SUCCESS; } /* record the request */ req = PMIX_NEW(pmix_iof_req_t); if (NULL == req) { return PMIX_ERR_NOMEM; } PMIX_RETAIN(cd->peer); req->requestor = cd->peer; req->nprocs = 1; PMIX_PROC_CREATE(req->procs, req->nprocs); PMIX_LOAD_PROCID(&req->procs[0], nspace, PMIX_RANK_WILDCARD); req->channels = cd->channels; req->flags = cd->flags; req->local_id = pmix_pointer_array_add(&pmix_globals.iof_requests, req); /* process any cached IO */ PMIX_LIST_FOREACH_SAFE (iof, ionext, &pmix_server_globals.iof, pmix_iof_cache_t) { rc = pmix_iof_process_iof(iof->channel, &iof->source, iof->bo, iof->info, iof->ninfo, req); if (PMIX_OPERATION_SUCCEEDED == rc) { /* remove it from the list since it has now been forwarded */ pmix_list_remove_item(&pmix_server_globals.iof, &iof->super); PMIX_RELEASE(iof); } } return PMIX_SUCCESS; } static void _spcbfunc(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); // pass along default status rc = cd->status; /* if it was successful, and there are IOF requests, then * register them now */ if (PMIX_SUCCESS == cd->status) { rc = pmix_server_process_iof(cd, cd->nspace); } if (NULL != cd->spcbfunc) { cd->spcbfunc(rc, cd->nspace, cd->cbdata); } if (NULL != cd->nspace) { free(cd->nspace); } PMIX_RELEASE(cd); } void pmix_server_spcbfunc(pmix_status_t status, char nspace[], void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } cd->status = status; if (NULL != nspace) { cd->nspace = strdup(nspace); } PMIX_THREADSHIFT(cd, _spcbfunc); } void pmix_server_spawn_parser(pmix_peer_t *peer, pmix_iof_channel_t *channels, pmix_iof_flags_t *flags, pmix_info_t *info, size_t ninfo) { size_t n; bool stdout_found = false, stderr_found = false, stddiag_found = false; /* run a quick check of the directives to see if any IOF * requests were included so we can set that up now - helps * to catch any early output - and a request for notification * of job termination so we can setup the event registration */ *channels = PMIX_FWD_NO_CHANNELS; for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_FWD_STDIN)) { if (PMIX_INFO_TRUE(&info[n])) { *channels |= PMIX_FWD_STDIN_CHANNEL; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_FWD_STDOUT)) { stdout_found = true; if (PMIX_INFO_TRUE(&info[n])) { *channels |= PMIX_FWD_STDOUT_CHANNEL; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_FWD_STDERR)) { stderr_found = true; if (PMIX_INFO_TRUE(&info[n])) { *channels |= PMIX_FWD_STDERR_CHANNEL; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_FWD_STDDIAG)) { stddiag_found = true; if (PMIX_INFO_TRUE(&info[n])) { *channels |= PMIX_FWD_STDDIAG_CHANNEL; } } else { pmix_iof_check_flags(&info[n], flags); } } /* we will construct any required iof request tracker upon completion of the spawn * as we need the nspace of the spawned application! */ if (PMIX_PEER_IS_TOOL(peer)) { /* if the requestor is a tool, we default to forwarding all * output IO channels */ if (!stdout_found) { *channels |= PMIX_FWD_STDOUT_CHANNEL; } if (!stderr_found) { *channels |= PMIX_FWD_STDERR_CHANNEL; } if (!stddiag_found) { *channels |= PMIX_FWD_STDDIAG_CHANNEL; } } } pmix_status_t pmix_server_spawn(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_spawn_cbfunc_t cbfunc, void *cbdata) { pmix_setup_caddy_t *cd; int32_t cnt; pmix_status_t rc; pmix_proc_t proc; pmix_output_verbose(2, pmix_server_globals.spawn_output, "recvd SPAWN from %s", PMIX_PNAME_PRINT(&peer->info->pname)); if (NULL == pmix_host_server.spawn) { return PMIX_ERR_NOT_SUPPORTED; } /* setup */ cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } PMIX_RETAIN(peer); cd->peer = peer; cd->spcbfunc = cbfunc; cd->cbdata = cbdata; /* unpack the number of job-level directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd); return rc; } if (0 < cd->ninfo) { PMIX_INFO_CREATE(cd->info, cd->ninfo); if (NULL == cd->info) { rc = PMIX_ERR_NOMEM; goto cleanup; } cnt = cd->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* run a quick check of the directives to see if any IOF * requests were included so we can set that up now - helps * to catch any early output - and a request for notification * of job termination so we can setup the event registration */ pmix_server_spawn_parser(peer, &cd->channels, &cd->flags, cd->info, cd->ninfo); } /* unpack the number of apps */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->napps, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* unpack the array of apps */ if (0 < cd->napps) { PMIX_APP_CREATE(cd->apps, cd->napps); if (NULL == cd->apps) { rc = PMIX_ERR_NOMEM; goto cleanup; } cnt = cd->napps; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->apps, &cnt, PMIX_APP); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } /* mark that we created the data */ cd->copied = true; /* call the local server */ PMIX_LOAD_PROCID(&proc, peer->info->pname.nspace, peer->info->pname.rank); rc = pmix_host_server.spawn(&proc, cd->info, cd->ninfo, cd->apps, cd->napps, pmix_server_spcbfunc, cd); cleanup: if (PMIX_SUCCESS != rc) { if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } if (NULL != cd->apps) { PMIX_APP_FREE(cd->apps, cd->napps); } PMIX_RELEASE(cd); } return rc; } static void _check_cached_events(int sd, short args, void *cbdata) { pmix_setup_caddy_t *scd = (pmix_setup_caddy_t *) cbdata; pmix_notify_caddy_t *cd; pmix_range_trkr_t rngtrk; pmix_proc_t proc; int i; size_t k, n; bool found, matched; pmix_buffer_t *relay; pmix_status_t ret = PMIX_SUCCESS; pmix_cmd_t cmd = PMIX_NOTIFY_CMD; PMIX_HIDE_UNUSED_PARAMS(sd, args); /* check if any matching notifications have been cached */ rngtrk.procs = NULL; rngtrk.nprocs = 0; for (i = 0; i < pmix_globals.max_events; i++) { pmix_hotel_knock(&pmix_globals.notifications, i, (void **) &cd); if (NULL == cd) { continue; } found = false; if (NULL == scd->codes) { if (!cd->nondefault) { /* they registered a default event handler - always matches */ found = true; } } else { for (k = 0; k < scd->ncodes; k++) { if (scd->codes[k] == cd->status) { found = true; break; } } } if (!found) { continue; } /* check if the affected procs (if given) match those they * wanted to know about */ if (!pmix_notify_check_affected(cd->affected, cd->naffected, scd->procs, scd->nprocs)) { continue; } /* check the range */ if (NULL == cd->targets) { rngtrk.procs = &cd->source; rngtrk.nprocs = 1; } else { rngtrk.procs = cd->targets; rngtrk.nprocs = cd->ntargets; } rngtrk.range = cd->range; PMIX_LOAD_PROCID(&proc, scd->peer->info->pname.nspace, scd->peer->info->pname.rank); if (!pmix_notify_check_range(&rngtrk, &proc)) { continue; } /* if we were given specific targets, check if this is one */ found = false; if (NULL != cd->targets) { matched = false; for (n = 0; n < cd->ntargets; n++) { /* if the source of the event is the same peer just registered, then ignore it * as the event notification system will have already locally * processed it */ if (PMIX_CHECK_NAMES(&cd->source, &scd->peer->info->pname)) { continue; } if (PMIX_CHECK_NAMES(&scd->peer->info->pname, &cd->targets[n])) { matched = true; /* track the number of targets we have left to notify */ --cd->nleft; /* if this is the last one, then evict this event * from the cache */ if (0 == cd->nleft) { pmix_hotel_checkout(&pmix_globals.notifications, cd->room); found = true; // mark that we should release cd } break; } } if (!matched) { /* do not notify this one */ continue; } } /* all matches - notify */ relay = PMIX_NEW(pmix_buffer_t); if (NULL == relay) { /* nothing we can do */ PMIX_ERROR_LOG(PMIX_ERR_NOMEM); ret = PMIX_ERR_NOMEM; break; } /* pack the info data stored in the event */ PMIX_BFROPS_PACK(ret, scd->peer, relay, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); break; } PMIX_BFROPS_PACK(ret, scd->peer, relay, &cd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); break; } PMIX_BFROPS_PACK(ret, scd->peer, relay, &cd->source, 1, PMIX_PROC); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); break; } PMIX_BFROPS_PACK(ret, scd->peer, relay, &cd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); break; } if (0 < cd->ninfo) { PMIX_BFROPS_PACK(ret, scd->peer, relay, cd->info, cd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); break; } } PMIX_SERVER_QUEUE_REPLY(ret, scd->peer, 0, relay); if (PMIX_SUCCESS != ret) { PMIX_RELEASE(relay); } if (found) { PMIX_RELEASE(cd); } } /* release the caddy */ if (NULL != scd->codes) { free(scd->codes); } if (NULL != scd->info) { PMIX_INFO_FREE(scd->info, scd->ninfo); } if (NULL != scd->opcbfunc) { scd->opcbfunc(ret, scd->cbdata); } PMIX_RELEASE(scd); } /* provide a callback function for the host when it finishes * processing the registration */ static void regevopcbfunc(pmix_status_t status, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(cd); return; } /* if the registration succeeded, then check local cache */ if (PMIX_SUCCESS == status) { cd->status = status; PMIX_THREADSHIFT(cd, _check_cached_events); return; } /* it didn't succeed, so cleanup and execute the callback * so we don't hang */ if (NULL != cd->codes) { free(cd->codes); } if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } if (NULL != cd->opcbfunc) { cd->opcbfunc(status, cd->cbdata); } PMIX_RELEASE(cd); } pmix_status_t pmix_server_register_events(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_status_t *codes = NULL; pmix_info_t *info = NULL; size_t ninfo = 0, ncodes, n; pmix_regevents_info_t *reginfo, *rptr; pmix_peer_events_info_t *prev = NULL; pmix_setup_caddy_t *scd; bool enviro_events = false; bool found; pmix_proc_t *affected = NULL; size_t naffected = 0; pmix_output_verbose(2, pmix_server_globals.event_output, "recvd register events for peer %s:%d", peer->info->pname.nspace, peer->info->pname.rank); /* unpack the number of codes */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ncodes, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* unpack the array of codes */ if (0 < ncodes) { codes = (pmix_status_t *) malloc(ncodes * sizeof(pmix_status_t)); if (NULL == codes) { rc = PMIX_ERR_NOMEM; goto cleanup; } cnt = ncodes; PMIX_BFROPS_UNPACK(rc, peer, buf, codes, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } /* unpack the number of info objects */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* unpack the array of info objects */ if (0 < ninfo) { PMIX_INFO_CREATE(info, ninfo); if (NULL == info) { rc = PMIX_ERR_NOMEM; goto cleanup; } cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } /* check the directives */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_EVENT_AFFECTED_PROC)) { if (NULL != affected) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); rc = PMIX_ERR_BAD_PARAM; goto cleanup; } naffected = 1; PMIX_PROC_CREATE(affected, naffected); memcpy(affected, info[n].value.data.proc, sizeof(pmix_proc_t)); } else if (PMIX_CHECK_KEY(&info[n], PMIX_EVENT_AFFECTED_PROCS)) { if (NULL != affected) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); rc = PMIX_ERR_BAD_PARAM; goto cleanup; } naffected = info[n].value.data.darray->size; PMIX_PROC_CREATE(affected, naffected); memcpy(affected, info[n].value.data.darray->array, naffected * sizeof(pmix_proc_t)); } } /* check the codes for system events */ for (n = 0; n < ncodes; n++) { if (PMIX_SYSTEM_EVENT(codes[n])) { enviro_events = true; break; } } /* if they asked for enviro events, and our host doesn't support * register_events, then we cannot meet the request */ if (enviro_events && NULL == pmix_host_server.register_events) { enviro_events = false; rc = PMIX_ERR_NOT_SUPPORTED; goto cleanup; } /* if they didn't send us any codes, then they are registering a * default event handler. In that case, check only for default * handlers and add this request to it, if not already present */ if (0 == ncodes) { PMIX_LIST_FOREACH (reginfo, &pmix_server_globals.events, pmix_regevents_info_t) { if (PMIX_MAX_ERR_CONSTANT == reginfo->code) { /* both are default handlers */ prev = PMIX_NEW(pmix_peer_events_info_t); if (NULL == prev) { rc = PMIX_ERR_NOMEM; goto cleanup; } PMIX_RETAIN(peer); prev->peer = peer; if (NULL != affected) { PMIX_PROC_CREATE(prev->affected, naffected); prev->naffected = naffected; memcpy(prev->affected, affected, naffected * sizeof(pmix_proc_t)); } pmix_list_append(®info->peers, &prev->super); break; } } rc = PMIX_OPERATION_SUCCEEDED; goto cleanup; } /* store the event registration info so we can call the registered * client when the server notifies the event */ for (n = 0; n < ncodes; n++) { found = false; PMIX_LIST_FOREACH (reginfo, &pmix_server_globals.events, pmix_regevents_info_t) { if (PMIX_MAX_ERR_CONSTANT == reginfo->code) { continue; } else if (codes[n] == reginfo->code) { found = true; break; } } if (found) { /* found it - add this request */ prev = PMIX_NEW(pmix_peer_events_info_t); if (NULL == prev) { rc = PMIX_ERR_NOMEM; goto cleanup; } PMIX_RETAIN(peer); prev->peer = peer; if (NULL != affected) { PMIX_PROC_CREATE(prev->affected, naffected); prev->naffected = naffected; memcpy(prev->affected, affected, naffected * sizeof(pmix_proc_t)); } prev->enviro_events = enviro_events; pmix_list_append(®info->peers, &prev->super); } else { /* if we get here, then we didn't find an existing registration for this code */ rptr = PMIX_NEW(pmix_regevents_info_t); if (NULL == rptr) { rc = PMIX_ERR_NOMEM; goto cleanup; } rptr->code = codes[n]; pmix_list_append(&pmix_server_globals.events, &rptr->super); prev = PMIX_NEW(pmix_peer_events_info_t); if (NULL == prev) { rc = PMIX_ERR_NOMEM; goto cleanup; } PMIX_RETAIN(peer); prev->peer = peer; if (NULL != affected) { PMIX_PROC_CREATE(prev->affected, naffected); prev->naffected = naffected; memcpy(prev->affected, affected, naffected * sizeof(pmix_proc_t)); } prev->enviro_events = enviro_events; pmix_list_append(&rptr->peers, &prev->super); } } /* if they asked for enviro events, call the local server */ if (enviro_events) { /* if they don't support this, then we cannot do it */ if (NULL == pmix_host_server.register_events) { rc = PMIX_ERR_NOT_SUPPORTED; goto cleanup; } /* need to ensure the arrays don't go away until after the * host RM is done with them */ scd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == scd) { rc = PMIX_ERR_NOMEM; goto cleanup; } PMIX_RETAIN(peer); scd->peer = peer; scd->codes = codes; scd->ncodes = ncodes; scd->info = info; scd->ninfo = ninfo; scd->opcbfunc = cbfunc; scd->cbdata = cbdata; if (PMIX_SUCCESS == (rc = pmix_host_server.register_events(scd->codes, scd->ncodes, scd->info, scd->ninfo, regevopcbfunc, scd))) { /* the host will call us back when completed */ pmix_output_verbose( 2, pmix_server_globals.event_output, "server register events: host server processing event registration"); if (NULL != affected) { free(affected); } return rc; } else if (PMIX_OPERATION_SUCCEEDED == rc) { /* we need to check cached notifications, but we want to ensure * that occurs _after_ the client returns from registering the * event handler in case the event is flagged for do_not_cache. * Setup an event to fire after we return as that means it will * occur after we send the registration response back to the client, * thus guaranteeing that the client will get their registration * callback prior to delivery of an event notification */ if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { PMIX_RELEASE(scd); return PMIX_ERR_NOT_AVAILABLE; } PMIX_RETAIN(peer); scd->peer = peer; scd->procs = affected; scd->nprocs = naffected; scd->opcbfunc = NULL; scd->cbdata = NULL; PMIX_THREADSHIFT(scd, _check_cached_events); return rc; } else { /* host returned a genuine error and won't be calling the callback function */ pmix_output_verbose(2, pmix_server_globals.event_output, "server register events: host server reg events returned rc =%d", rc); PMIX_RELEASE(scd); goto cleanup; } } else { rc = PMIX_OPERATION_SUCCEEDED; /* we need to check cached notifications, but we want to ensure * that occurs _after_ the client returns from registering the * event handler in case the event is flagged for do_not_cache. * Setup an event to fire after we return as that means it will * occur after we send the registration response back to the client, * thus guaranteeing that the client will get their registration * callback prior to delivery of an event notification */ if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } scd = PMIX_NEW(pmix_setup_caddy_t); PMIX_RETAIN(peer); scd->peer = peer; scd->codes = codes; scd->ncodes = ncodes; scd->procs = affected; scd->nprocs = naffected; scd->opcbfunc = NULL; scd->cbdata = NULL; PMIX_THREADSHIFT(scd, _check_cached_events); if (NULL != info) { PMIX_INFO_FREE(info, ninfo); } return rc; } cleanup: pmix_output_verbose(2, pmix_server_globals.event_output, "server register events: ninfo =%lu rc =%d", ninfo, rc); if (NULL != info) { PMIX_INFO_FREE(info, ninfo); } if (NULL != codes) { free(codes); } if (NULL != affected) { PMIX_PROC_FREE(affected, naffected); } return rc; } void pmix_server_deregister_events(pmix_peer_t *peer, pmix_buffer_t *buf) { int32_t cnt; pmix_status_t rc, code; pmix_regevents_info_t *reginfo = NULL; pmix_regevents_info_t *reginfo_next; pmix_peer_events_info_t *prev; pmix_output_verbose(2, pmix_server_globals.event_output, "%s recvd deregister events from %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_PEER_PRINT(peer)); /* unpack codes and process until done */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &code, &cnt, PMIX_STATUS); while (PMIX_SUCCESS == rc) { PMIX_LIST_FOREACH_SAFE (reginfo, reginfo_next, &pmix_server_globals.events, pmix_regevents_info_t) { if (code == reginfo->code) { /* found it - remove this peer from the list */ PMIX_LIST_FOREACH (prev, ®info->peers, pmix_peer_events_info_t) { if (prev->peer == peer) { /* found it */ pmix_list_remove_item(®info->peers, &prev->super); PMIX_RELEASE(prev); break; } } /* if all of the peers for this code are now gone, then remove it */ if (0 == pmix_list_get_size(®info->peers)) { pmix_list_remove_item(&pmix_server_globals.events, ®info->super); /* if this was registered with the host, then deregister it */ PMIX_RELEASE(reginfo); } } } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &code, &cnt, PMIX_STATUS); } if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); } } static void local_cbfunc(pmix_status_t status, void *cbdata) { pmix_notify_caddy_t *cd = (pmix_notify_caddy_t *) cbdata; if (NULL != cd->cbfunc) { cd->cbfunc(status, cd->cbdata); } PMIX_RELEASE(cd); } static void intermed_step(pmix_status_t status, void *cbdata) { pmix_notify_caddy_t *cd = (pmix_notify_caddy_t *) cbdata; pmix_status_t rc; if (PMIX_SUCCESS != status) { rc = status; goto complete; } /* check the range directive - if it is LOCAL, then we are * done. Otherwise, it needs to go up to our * host for dissemination */ if (PMIX_RANGE_LOCAL == cd->range) { rc = PMIX_SUCCESS; goto complete; } /* pass it to our host RM for distribution */ if (NULL != pmix_host_server.notify_event) { rc = pmix_host_server.notify_event(cd->status, &cd->source, cd->range, cd->info, cd->ninfo, local_cbfunc, cd); if (PMIX_SUCCESS == rc) { /* let the callback function respond for us */ return; } if (PMIX_OPERATION_SUCCEEDED == rc || PMIX_ERR_NOT_SUPPORTED == rc) { rc = PMIX_SUCCESS; // local_cbfunc will not be called } } else { rc = PMIX_SUCCESS; // local_cbfunc will not be called } complete: if (NULL != cd->cbfunc) { cd->cbfunc(rc, cd->cbdata); } PMIX_RELEASE(cd); } /* Receive an event sent by the client library. Since it was sent * to us by one client, we have to both process it locally to ensure * we notify all relevant local clients AND (assuming a range other * than LOCAL) deliver to our host, requesting that they send it * to all peer servers in the current session */ pmix_status_t pmix_server_event_recvd_from_client(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_notify_caddy_t *cd; size_t ninfo, n; pmix_output_verbose(2, pmix_server_globals.event_output, "%s:%d recvd event notification from client %s:%d", pmix_globals.myid.nspace, pmix_globals.myid.rank, peer->info->pname.nspace, peer->info->pname.rank); cd = PMIX_NEW(pmix_notify_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->cbfunc = cbfunc; cd->cbdata = cbdata; /* set the source */ PMIX_LOAD_PROCID(&cd->source, peer->info->pname.nspace, peer->info->pname.rank); /* unpack status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the range */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->range, &cnt, PMIX_DATA_RANGE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the info keys */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } cd->ninfo = ninfo + 1; PMIX_INFO_CREATE(cd->info, cd->ninfo); if (NULL == cd->info) { rc = PMIX_ERR_NOMEM; goto exit; } if (0 < ninfo) { cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* check to see if we already processed this event - it is possible * that a local client "echoed" it back to us and we want to avoid * a potential infinite loop */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&cd->info[n], PMIX_SERVER_INTERNAL_NOTIFY)) { /* yep, we did - so don't do it again! */ rc = PMIX_OPERATION_SUCCEEDED; goto exit; } } /* add an info object to mark that we recvd this internally */ PMIX_INFO_LOAD(&cd->info[cd->ninfo - 1], PMIX_SERVER_INTERNAL_NOTIFY, NULL, PMIX_BOOL); /* process it */ rc = pmix_server_notify_client_of_event(cd->status, &cd->source, cd->range, cd->info, cd->ninfo, intermed_step, cd); if (PMIX_SUCCESS != rc) { goto exit; } return rc; exit: PMIX_RELEASE(cd); return rc; } pmix_status_t pmix_server_query(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_query_caddy_t *cd; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_server_globals.base_output, "recvd query from client"); cd = PMIX_NEW(pmix_query_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->cbfunc = cbfunc; cd->cbdata = cbdata; // this is the pmix_server_caddy_t we were given /* unpack the number of queries */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->nqueries, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd); return rc; } /* unpack the queries */ if (0 < cd->nqueries) { PMIX_QUERY_CREATE(cd->queries, cd->nqueries); if (NULL == cd->queries) { rc = PMIX_ERR_NOMEM; PMIX_RELEASE(cd); return rc; } cnt = cd->nqueries; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->queries, &cnt, PMIX_QUERY); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd); return rc; } } PMIX_THREADSHIFT(cd, pmix_parse_localquery); return PMIX_SUCCESS; } static void localcbfn(pmix_status_t status, void *cbdata) { pmix_shift_caddy_t *cb = (pmix_shift_caddy_t *) cbdata; if (NULL != cb->cbfunc.opcbfn) { cb->cbfunc.opcbfn(status, cb->cbdata); } PMIX_RELEASE(cb); } pmix_status_t pmix_server_log(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_shift_caddy_t *cd; pmix_proc_t proc; time_t timestamp; PMIX_HIDE_UNUSED_PARAMS(cbfunc, cbdata); pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:server recvd log from client"); /* setup the requesting peer name */ pmix_strncpy(proc.nspace, peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = peer->info->pname.rank; cd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } if (PMIX_PEER_IS_EARLIER(peer, 3, 0, 0)) { timestamp = -1; } else { /* unpack the timestamp */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, ×tamp, &cnt, PMIX_TIME); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* unpack the number of data */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } cnt = cd->ninfo; PMIX_INFO_CREATE(cd->info, cd->ninfo); /* unpack the data */ if (0 < cnt) { PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* unpack the number of directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->ndirs, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } cnt = cd->ndirs; /* always add the source to the directives so we * can tell downstream if this gets "upcalled" to * our host for relay */ cd->ndirs = cnt + 1; /* if a timestamp was sent, then we add it to the directives */ if (0 < timestamp) { cd->ndirs++; PMIX_INFO_CREATE(cd->directives, cd->ndirs); PMIX_INFO_LOAD(&cd->directives[cnt], PMIX_LOG_SOURCE, &proc, PMIX_PROC); PMIX_INFO_LOAD(&cd->directives[cnt + 1], PMIX_LOG_TIMESTAMP, ×tamp, PMIX_TIME); } else { PMIX_INFO_CREATE(cd->directives, cd->ndirs); PMIX_INFO_LOAD(&cd->directives[cnt], PMIX_LOG_SOURCE, &proc, PMIX_PROC); } /* unpack the directives */ if (0 < cnt) { PMIX_BFROPS_UNPACK(rc, peer, buf, cd->directives, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* if we are not the gateway, then pass this up to the host * for transfer to the gateway, if available */ if (!PMIX_PEER_IS_GATEWAY(pmix_globals.mypeer)) { pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:server not gateway"); cd->cbfunc.opcbfn = cbfunc; cd->cbdata = cbdata; if (NULL != pmix_host_server.log2) { pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:server using log2 upcall"); rc = pmix_host_server.log2(&proc, cd->info, cd->ninfo, cd->directives, cd->ndirs, localcbfn, (void *) cd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); return rc; } } else if (NULL != pmix_host_server.log) { pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:server using log upcall"); pmix_host_server.log(&proc, cd->info, cd->ninfo, cd->directives, cd->ndirs, localcbfn, (void *) cd); } else { // no choice but to process locally goto local; } return PMIX_SUCCESS; } local: /* pass it down */ pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:server processing locally"); rc = pmix_plog.log(&proc, cd->info, cd->ninfo, cd->directives, cd->ndirs); if (PMIX_SUCCESS == rc) { // mark that it was done atomically rc = PMIX_OPERATION_SUCCEEDED; } exit: PMIX_RELEASE(cd); return rc; } pmix_status_t pmix_server_alloc(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_query_caddy_t *cd; pmix_proc_t proc; pmix_alloc_directive_t directive; pmix_output_verbose(2, pmix_server_globals.base_output, "%s recvd allocate request from client %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_PEER_PRINT(peer)); if (NULL == pmix_host_server.allocate) { return PMIX_ERR_NOT_SUPPORTED; } cd = PMIX_NEW(pmix_query_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->cbdata = cbdata; /* unpack the directive */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &directive, &cnt, PMIX_ALLOC_DIRECTIVE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the number of info objects */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the info */ if (0 < cd->ninfo) { PMIX_INFO_CREATE(cd->info, cd->ninfo); cnt = cd->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* setup the requesting peer name */ pmix_strncpy(proc.nspace, peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = peer->info->pname.rank; /* ask the host to execute the request */ rc = pmix_host_server.allocate(&proc, directive, cd->info, cd->ninfo, cbfunc, cd); if (PMIX_SUCCESS != rc) { goto exit; } return PMIX_SUCCESS; exit: PMIX_RELEASE(cd); return rc; } typedef struct { pmix_list_item_t super; pmix_epilog_t *epi; } pmix_srvr_epi_caddy_t; static PMIX_CLASS_INSTANCE(pmix_srvr_epi_caddy_t, pmix_list_item_t, NULL, NULL); pmix_status_t pmix_server_job_ctrl(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc, void *cbdata) { int32_t cnt, m; pmix_status_t rc; pmix_query_caddy_t *cd; pmix_namespace_t *nptr, *tmp; pmix_peer_t *pr; pmix_proc_t proc; size_t n; bool recurse = false, leave_topdir = false, duplicate; pmix_list_t cachedirs, cachefiles, ignorefiles, epicache; pmix_srvr_epi_caddy_t *epicd = NULL; pmix_cleanup_file_t *cf, *cf2, *cfptr; pmix_cleanup_dir_t *cdir, *cdir2, *cdirptr; pmix_output_verbose(2, pmix_server_globals.base_output, "recvd job control request from client"); if (NULL == pmix_host_server.job_control) { return PMIX_ERR_NOT_SUPPORTED; } cd = PMIX_NEW(pmix_query_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->cbdata = cbdata; PMIX_CONSTRUCT(&epicache, pmix_list_t); /* unpack the number of targets */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->ntargets, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } if (0 < cd->ntargets) { PMIX_PROC_CREATE(cd->targets, cd->ntargets); cnt = cd->ntargets; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->targets, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* check targets to find proper place to put any epilog requests */ if (NULL == cd->targets) { epicd = PMIX_NEW(pmix_srvr_epi_caddy_t); epicd->epi = &peer->nptr->epilog; pmix_list_append(&epicache, &epicd->super); } else { for (n = 0; n < cd->ntargets; n++) { /* find the nspace of this proc */ nptr = NULL; PMIX_LIST_FOREACH (tmp, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(tmp->nspace, cd->targets[n].nspace)) { nptr = tmp; break; } } if (NULL == nptr) { nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { rc = PMIX_ERR_NOMEM; goto exit; } nptr->nspace = strdup(cd->targets[n].nspace); pmix_list_append(&pmix_globals.nspaces, &nptr->super); } /* if the rank is wildcard, then we use the epilog for the nspace */ if (PMIX_RANK_WILDCARD == cd->targets[n].rank) { epicd = PMIX_NEW(pmix_srvr_epi_caddy_t); epicd->epi = &nptr->epilog; pmix_list_append(&epicache, &epicd->super); } else { /* we need to find the precise peer - we can only * do cleanup for a local client */ for (m = 0; m < pmix_server_globals.clients.size; m++) { pr = (pmix_peer_t *)pmix_pointer_array_get_item(&pmix_server_globals.clients, m); if (NULL == pr) { continue; } if (!PMIX_CHECK_NSPACE(pr->info->pname.nspace, cd->targets[n].nspace)) { continue; } if (pr->info->pname.rank == cd->targets[n].rank) { epicd = PMIX_NEW(pmix_srvr_epi_caddy_t); epicd->epi = &pr->epilog; pmix_list_append(&epicache, &epicd->super); break; } } } } } /* unpack the number of info objects */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the info */ if (0 < cd->ninfo) { PMIX_INFO_CREATE(cd->info, cd->ninfo); cnt = cd->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* if this includes a request for post-termination cleanup, we handle * that request ourselves */ PMIX_CONSTRUCT(&cachedirs, pmix_list_t); PMIX_CONSTRUCT(&cachefiles, pmix_list_t); PMIX_CONSTRUCT(&ignorefiles, pmix_list_t); cnt = 0; // track how many infos are cleanup related for (n = 0; n < cd->ninfo; n++) { if (PMIX_CHECK_KEY(&cd->info[n], PMIX_REGISTER_CLEANUP)) { ++cnt; if (PMIX_STRING != cd->info[n].value.type || NULL == cd->info[n].value.data.string) { /* return an error */ rc = PMIX_ERR_BAD_PARAM; goto exit; } cf = PMIX_NEW(pmix_cleanup_file_t); if (NULL == cf) { /* return an error */ rc = PMIX_ERR_NOMEM; goto exit; } cf->path = strdup(cd->info[n].value.data.string); pmix_list_append(&cachefiles, &cf->super); } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_REGISTER_CLEANUP_DIR)) { ++cnt; if (PMIX_STRING != cd->info[n].value.type || NULL == cd->info[n].value.data.string) { /* return an error */ rc = PMIX_ERR_BAD_PARAM; goto exit; } cdir = PMIX_NEW(pmix_cleanup_dir_t); if (NULL == cdir) { /* return an error */ rc = PMIX_ERR_NOMEM; goto exit; } cdir->path = strdup(cd->info[n].value.data.string); pmix_list_append(&cachedirs, &cdir->super); } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_CLEANUP_RECURSIVE)) { recurse = PMIX_INFO_TRUE(&cd->info[n]); ++cnt; } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_CLEANUP_IGNORE)) { if (PMIX_STRING != cd->info[n].value.type || NULL == cd->info[n].value.data.string) { /* return an error */ rc = PMIX_ERR_BAD_PARAM; goto exit; } cf = PMIX_NEW(pmix_cleanup_file_t); if (NULL == cf) { /* return an error */ rc = PMIX_ERR_NOMEM; goto exit; } cf->path = strdup(cd->info[n].value.data.string); pmix_list_append(&ignorefiles, &cf->super); ++cnt; } else if (PMIX_CHECK_KEY(&cd->info[n], PMIX_CLEANUP_LEAVE_TOPDIR)) { leave_topdir = PMIX_INFO_TRUE(&cd->info[n]); ++cnt; } } if (0 < cnt) { /* handle any ignore directives first */ PMIX_LIST_FOREACH (cf, &ignorefiles, pmix_cleanup_file_t) { PMIX_LIST_FOREACH (epicd, &epicache, pmix_srvr_epi_caddy_t) { /* scan the existing list of files for any duplicate */ duplicate = false; PMIX_LIST_FOREACH (cf2, &epicd->epi->cleanup_files, pmix_cleanup_file_t) { if (0 == strcmp(cf2->path, cf->path)) { duplicate = true; break; } } if (!duplicate) { /* append it to the end of the list */ cfptr = PMIX_NEW(pmix_cleanup_file_t); cfptr->path = strdup(cf->path); pmix_list_append(&epicd->epi->ignores, &cf->super); } } } PMIX_LIST_DESTRUCT(&ignorefiles); /* now look at the directories */ PMIX_LIST_FOREACH (cdir, &cachedirs, pmix_cleanup_dir_t) { PMIX_LIST_FOREACH (epicd, &epicache, pmix_srvr_epi_caddy_t) { /* scan the existing list of directories for any duplicate */ duplicate = false; PMIX_LIST_FOREACH (cdir2, &epicd->epi->cleanup_dirs, pmix_cleanup_dir_t) { if (0 == strcmp(cdir2->path, cdir->path)) { /* duplicate - check for difference in flags per RFC * precedence rules */ if (!cdir->recurse && recurse) { cdir->recurse = recurse; } if (!cdir->leave_topdir && leave_topdir) { cdir->leave_topdir = leave_topdir; } duplicate = true; break; } } if (!duplicate) { /* check for conflict with ignore */ PMIX_LIST_FOREACH (cf, &epicd->epi->ignores, pmix_cleanup_file_t) { if (0 == strcmp(cf->path, cdir->path)) { /* return an error */ rc = PMIX_ERR_CONFLICTING_CLEANUP_DIRECTIVES; PMIX_LIST_DESTRUCT(&cachedirs); PMIX_LIST_DESTRUCT(&cachefiles); goto exit; } } /* append it to the end of the list */ cdirptr = PMIX_NEW(pmix_cleanup_dir_t); cdirptr->path = strdup(cdir->path); cdirptr->recurse = recurse; cdirptr->leave_topdir = leave_topdir; pmix_list_append(&epicd->epi->cleanup_dirs, &cdirptr->super); } } } PMIX_LIST_DESTRUCT(&cachedirs); PMIX_LIST_FOREACH (cf, &cachefiles, pmix_cleanup_file_t) { PMIX_LIST_FOREACH (epicd, &epicache, pmix_srvr_epi_caddy_t) { /* scan the existing list of files for any duplicate */ duplicate = false; PMIX_LIST_FOREACH (cf2, &epicd->epi->cleanup_files, pmix_cleanup_file_t) { if (0 == strcmp(cf2->path, cf->path)) { duplicate = true; break; } } if (!duplicate) { /* check for conflict with ignore */ PMIX_LIST_FOREACH (cf2, &epicd->epi->ignores, pmix_cleanup_file_t) { if (0 == strcmp(cf->path, cf2->path)) { /* return an error */ rc = PMIX_ERR_CONFLICTING_CLEANUP_DIRECTIVES; PMIX_LIST_DESTRUCT(&cachedirs); PMIX_LIST_DESTRUCT(&cachefiles); goto exit; } } /* append it to the end of the list */ cfptr = PMIX_NEW(pmix_cleanup_file_t); cfptr->path = strdup(cf->path); pmix_list_append(&epicd->epi->cleanup_files, &cfptr->super); } } } PMIX_LIST_DESTRUCT(&cachefiles); if (cnt == (int) cd->ninfo) { /* nothing more to do */ rc = PMIX_OPERATION_SUCCEEDED; goto exit; } } /* setup the requesting peer name */ pmix_strncpy(proc.nspace, peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = peer->info->pname.rank; /* ask the host to execute the request */ if (PMIX_SUCCESS != (rc = pmix_host_server.job_control(&proc, cd->targets, cd->ntargets, cd->info, cd->ninfo, cbfunc, cd))) { goto exit; } PMIX_LIST_DESTRUCT(&epicache); return PMIX_SUCCESS; exit: PMIX_RELEASE(cd); PMIX_LIST_DESTRUCT(&epicache); return rc; } pmix_status_t pmix_server_monitor(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_cb_t *cb; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_server_globals.base_output, "recvd monitor request from client %s", PMIX_PEER_PRINT(peer)); cb = PMIX_NEW(pmix_cb_t); if (NULL == cb) { return PMIX_ERR_NOMEM; } PMIX_PROC_CREATE(cb->proc, 1); PMIX_LOAD_PROCID(&cb->proc[0], peer->info->pname.nspace, peer->info->pname.rank); cb->nprocs = 1; cb->cbdata = cbdata; cb->cbfunc.infofn = cbfunc; /* unpack what is to be monitored */ cb->info = PMIx_Info_create(1); cb->infocopy = true; cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, cb->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the error code */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cb->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the number of directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cb->ndirs, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the directives */ if (0 < cb->ndirs) { PMIX_INFO_CREATE(cb->directives, cb->ndirs); cnt = cb->ndirs; PMIX_BFROPS_UNPACK(rc, peer, buf, cb->directives, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } // pass this over to be processed PMIX_THREADSHIFT(cb, pmix_monitor_processing); return PMIX_SUCCESS; exit: PMIX_RELEASE(cb); return rc; } pmix_status_t pmix_server_get_credential(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_credential_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_query_caddy_t *cd; pmix_proc_t proc; pmix_output_verbose(2, pmix_globals.debug_output, "recvd get credential request from client"); if (NULL == pmix_host_server.get_credential) { return PMIX_ERR_NOT_SUPPORTED; } cd = PMIX_NEW(pmix_query_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->cbdata = cbdata; /* unpack the number of directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the directives */ if (0 < cd->ninfo) { PMIX_INFO_CREATE(cd->info, cd->ninfo); cnt = cd->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* setup the requesting peer name */ pmix_strncpy(proc.nspace, peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = peer->info->pname.rank; /* ask the host to execute the request */ if (PMIX_SUCCESS != (rc = pmix_host_server.get_credential(&proc, cd->info, cd->ninfo, cbfunc, cd))) { goto exit; } return PMIX_SUCCESS; exit: PMIX_RELEASE(cd); return rc; } pmix_status_t pmix_server_validate_credential(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_validation_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_query_caddy_t *cd; pmix_proc_t proc; pmix_output_verbose(2, pmix_globals.debug_output, "recvd validate credential request from client"); if (NULL == pmix_host_server.validate_credential) { return PMIX_ERR_NOT_SUPPORTED; } cd = PMIX_NEW(pmix_query_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->cbdata = cbdata; /* unpack the credential */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->bo, &cnt, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the number of directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the directives */ if (0 < cd->ninfo) { PMIX_INFO_CREATE(cd->info, cd->ninfo); cnt = cd->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* setup the requesting peer name */ pmix_strncpy(proc.nspace, peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = peer->info->pname.rank; /* ask the host to execute the request */ if (PMIX_SUCCESS != (rc = pmix_host_server.validate_credential(&proc, &cd->bo, cd->info, cd->ninfo, cbfunc, cd))) { goto exit; } return PMIX_SUCCESS; exit: PMIX_RELEASE(cd); return rc; } pmix_status_t pmix_server_iofreg(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_setup_caddy_t *cd; pmix_iof_req_t *req; size_t refid; pmix_output_verbose(2, pmix_server_globals.iof_output, "recvd IOF PULL request from client"); if (NULL == pmix_host_server.iof_pull) { return PMIX_ERR_NOT_SUPPORTED; } cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->cbdata = cbdata; // this is the pmix_server_caddy_t /* unpack the number of procs */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->nprocs, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the procs */ if (0 < cd->nprocs) { PMIX_PROC_CREATE(cd->procs, cd->nprocs); cnt = cd->nprocs; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->procs, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* unpack the number of directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the directives */ if (0 < cd->ninfo) { PMIX_INFO_CREATE(cd->info, cd->ninfo); cnt = cd->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* unpack the channels */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->channels, &cnt, PMIX_IOF_CHANNEL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack their local reference id */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &refid, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* add this peer/source/channel combination */ req = PMIX_NEW(pmix_iof_req_t); if (NULL == req) { rc = PMIX_ERR_NOMEM; goto exit; } PMIX_RETAIN(peer); req->requestor = peer; req->nprocs = cd->nprocs; if (0 < req->nprocs) { PMIX_PROC_CREATE(req->procs, cd->nprocs); memcpy(req->procs, cd->procs, req->nprocs * sizeof(pmix_proc_t)); } req->channels = cd->channels; req->remote_id = refid; req->local_id = pmix_pointer_array_add(&pmix_globals.iof_requests, req); cd->ncodes = req->local_id; /* ask the host to execute the request */ rc = pmix_host_server.iof_pull(cd->procs, cd->nprocs, cd->info, cd->ninfo, cd->channels, cbfunc, cd); if (PMIX_OPERATION_SUCCEEDED == rc) { /* the host did it atomically - send the response. In * this particular case, we can just use the cbfunc * ourselves as it will threadshift and guarantee * proper handling (i.e. that the refid will be * returned in the response to the client) */ cbfunc(PMIX_SUCCESS, cd); /* returning other than SUCCESS will cause the * switchyard to release the cd object */ return PMIX_SUCCESS; } exit: PMIX_RELEASE(cd); return rc; } pmix_status_t pmix_server_iofdereg(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_setup_caddy_t *cd; pmix_iof_req_t *req; size_t ninfo, refid; pmix_output_verbose(2, pmix_server_globals.iof_output, "recvd IOF DEREGISTER from client"); if (NULL == pmix_host_server.iof_pull) { return PMIX_ERR_NOT_SUPPORTED; } cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->cbdata = cbdata; // this is the pmix_server_caddy_t /* unpack the number of directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the directives - note that we have to add one * to tell the server to stop forwarding to this channel */ cd->ninfo = ninfo + 1; PMIX_INFO_CREATE(cd->info, cd->ninfo); if (0 < ninfo) { cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* add the directive to stop forwarding */ PMIX_INFO_LOAD(&cd->info[ninfo], PMIX_IOF_STOP, NULL, PMIX_BOOL); /* unpack the handler ID */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &refid, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* get the referenced handler */ req = (pmix_iof_req_t *) pmix_pointer_array_get_item(&pmix_globals.iof_requests, refid); if (NULL == req) { /* already gone? */ rc = PMIX_ERR_NOT_FOUND; goto exit; } pmix_pointer_array_set_item(&pmix_globals.iof_requests, refid, NULL); PMIX_RELEASE(req); /* tell the server to stop */ rc = pmix_host_server.iof_pull(cd->procs, cd->nprocs, cd->info, cd->ninfo, cd->channels, cbfunc, cd); if (PMIX_OPERATION_SUCCEEDED == rc) { /* the host did it atomically - send the response. In * this particular case, we can just use the cbfunc * ourselves as it will threadshift and guarantee * proper handling */ cbfunc(PMIX_SUCCESS, cd); /* returning other than SUCCESS will cause the * switchyard to release the cd object */ return PMIX_SUCCESS; } exit: return rc; } static void stdcbfunc(pmix_status_t status, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; if (NULL != cd->opcbfunc) { cd->opcbfunc(status, cd->cbdata); } if (NULL != cd->procs) { PMIX_PROC_FREE(cd->procs, cd->nprocs); } if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } if (NULL != cd->bo) { PMIX_BYTE_OBJECT_FREE(cd->bo, 1); } PMIX_RELEASE(cd); } pmix_status_t pmix_server_iofstdin(pmix_peer_t *peer, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc, void *cbdata) { int32_t cnt; pmix_status_t rc; pmix_proc_t source; pmix_setup_caddy_t *cd; pmix_output_verbose(2, pmix_server_globals.iof_output, "recvd stdin IOF data from tool %s", PMIX_PEER_PRINT(peer)); if (NULL == pmix_host_server.push_stdin) { return PMIX_ERR_NOT_SUPPORTED; } cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } cd->opcbfunc = cbfunc; cd->cbdata = cbdata; /* unpack the number of targets */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->nprocs, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } if (0 < cd->nprocs) { PMIX_PROC_CREATE(cd->procs, cd->nprocs); if (NULL == cd->procs) { rc = PMIX_ERR_NOMEM; goto error; } cnt = cd->nprocs; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->procs, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } } /* unpack the number of directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } if (0 < cd->ninfo) { PMIX_INFO_CREATE(cd->info, cd->ninfo); if (NULL == cd->info) { rc = PMIX_ERR_NOMEM; goto error; } cnt = cd->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } } /* unpack the data */ PMIX_BYTE_OBJECT_CREATE(cd->bo, 1); if (NULL == cd->bo) { rc = PMIX_ERR_NOMEM; goto error; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, cd->bo, &cnt, PMIX_BYTE_OBJECT); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { /* it is okay for them to not send data */ PMIX_BYTE_OBJECT_FREE(cd->bo, 1); } else if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } /* pass the data to the host */ pmix_strncpy(source.nspace, peer->nptr->nspace, PMIX_MAX_NSLEN); source.rank = peer->info->pname.rank; if (PMIX_SUCCESS != (rc = pmix_host_server.push_stdin(&source, cd->procs, cd->nprocs, cd->info, cd->ninfo, cd->bo, stdcbfunc, cd))) { if (PMIX_OPERATION_SUCCEEDED != rc) { goto error; } } return rc; error: PMIX_RELEASE(cd); return rc; } static void _fabric_response(int sd, short args, void *cbdata) { pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); qcd->cbfunc(PMIX_SUCCESS, qcd->info, qcd->ninfo, qcd->cbdata, NULL, NULL); PMIX_RELEASE(qcd); } static void frcbfunc(pmix_status_t status, void *cbdata) { pmix_query_caddy_t *qcd = (pmix_query_caddy_t *) cbdata; PMIX_ACQUIRE_OBJECT(qcd); qcd->status = status; PMIX_POST_OBJECT(qcd); PMIX_WAKEUP_THREAD(&qcd->lock); } /* we are being called from the PMIx server's switchyard function, * which means we are in an event and can access global data */ pmix_status_t pmix_server_fabric_register(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc) { int32_t cnt; pmix_status_t rc; pmix_query_caddy_t *qcd = NULL; pmix_proc_t proc; pmix_fabric_t fabric; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_server_globals.base_output, "recvd register_fabric request from client"); qcd = PMIX_NEW(pmix_query_caddy_t); if (NULL == qcd) { return PMIX_ERR_NOMEM; } PMIX_RETAIN(cd); qcd->cbfunc = cbfunc; qcd->cbdata = cd; /* unpack the number of directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &qcd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(qcd); goto exit; } /* unpack the directives */ if (0 < qcd->ninfo) { PMIX_INFO_CREATE(cd->info, qcd->ninfo); cnt = qcd->ninfo; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, qcd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(qcd); goto exit; } } /* see if we support this request ourselves */ PMIX_FABRIC_CONSTRUCT(&fabric); rc = pmix_pnet.register_fabric(&fabric, qcd->info, qcd->ninfo, frcbfunc, qcd); if (PMIX_OPERATION_SUCCEEDED == rc) { /* we need to respond, but we want to ensure * that occurs _after_ the client returns from its API */ if (NULL != qcd->info) { PMIX_INFO_FREE(qcd->info, qcd->ninfo); } qcd->info = fabric.info; qcd->ninfo = fabric.ninfo; PMIX_THREADSHIFT(qcd, _fabric_response); return PMIX_SUCCESS; } else if (PMIX_SUCCESS == rc) { PMIX_WAIT_THREAD(&qcd->lock); /* we need to respond, but we want to ensure * that occurs _after_ the client returns from its API */ if (NULL != qcd->info) { PMIX_INFO_FREE(qcd->info, qcd->ninfo); } qcd->info = fabric.info; qcd->ninfo = fabric.ninfo; PMIX_THREADSHIFT(qcd, _fabric_response); return PMIX_SUCCESS; } /* if we don't internally support it, see if * our host does */ if (NULL == pmix_host_server.fabric) { rc = PMIX_ERR_NOT_SUPPORTED; goto exit; } /* setup the requesting peer name */ PMIX_LOAD_PROCID(&proc, cd->peer->info->pname.nspace, cd->peer->info->pname.rank); /* ask the host to execute the request */ if (PMIX_SUCCESS != (rc = pmix_host_server.fabric(&proc, PMIX_FABRIC_REQUEST_INFO, qcd->info, qcd->ninfo, cbfunc, qcd))) { goto exit; } return PMIX_SUCCESS; exit: if (NULL != qcd) { PMIX_RELEASE(qcd); } return rc; } pmix_status_t pmix_server_fabric_update(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc) { int32_t cnt; size_t index; pmix_status_t rc; pmix_query_caddy_t *qcd; pmix_proc_t proc; pmix_fabric_t fabric; if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_server_globals.base_output, "recvd update_fabric request from client"); qcd = PMIX_NEW(pmix_query_caddy_t); if (NULL == qcd) { return PMIX_ERR_NOMEM; } PMIX_RETAIN(cd); qcd->cbdata = cd; /* unpack the fabric index */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &index, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* see if we support this request ourselves */ PMIX_FABRIC_CONSTRUCT(&fabric); fabric.index = index; rc = pmix_pnet.update_fabric(&fabric); if (PMIX_SUCCESS == rc) { /* we need to respond, but we want to ensure * that occurs _after_ the client returns from its API */ if (NULL != qcd->info) { PMIX_INFO_FREE(qcd->info, qcd->ninfo); } qcd->info = fabric.info; qcd->ninfo = fabric.ninfo; PMIX_THREADSHIFT(qcd, _fabric_response); return rc; } /* if we don't internally support it, see if * our host does */ if (NULL == pmix_host_server.fabric) { rc = PMIX_ERR_NOT_SUPPORTED; goto exit; } /* setup the requesting peer name */ pmix_strncpy(proc.nspace, cd->peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = cd->peer->info->pname.rank; /* add the index */ qcd->ninfo = 1; PMIX_INFO_CREATE(qcd->info, qcd->ninfo); PMIX_INFO_LOAD(&qcd->info[0], PMIX_FABRIC_INDEX, &index, PMIX_SIZE); /* ask the host to execute the request */ if (PMIX_SUCCESS != (rc = pmix_host_server.fabric(&proc, PMIX_FABRIC_UPDATE_INFO, qcd->info, qcd->ninfo, cbfunc, qcd))) { goto exit; } return PMIX_SUCCESS; exit: return rc; } pmix_status_t pmix_server_device_dists(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_device_dist_cbfunc_t cbfunc) { pmix_topology_t topo = {NULL, NULL}; pmix_cpuset_t cpuset = {NULL, NULL}; pmix_status_t rc; pmix_device_distance_t *distances; size_t ndist; int cnt; pmix_cb_t cb; pmix_kval_t *kv; pmix_proc_t proc; /* unpack the topology they want us to use */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &topo, &cnt, PMIX_TOPO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* unpack the cpuset */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &cpuset, &cnt, PMIX_PROC_CPUSET); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* unpack any directives */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &cd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } if (0 < cd->ninfo) { PMIX_INFO_CREATE(cd->info, cd->ninfo); cnt = cd->ninfo; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, cd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } /* if the provided topo is NULL, use my own */ if (NULL == topo.topology) { if (NULL == pmix_globals.topology.topology) { /* try to get it */ rc = pmix_hwloc_load_topology(&pmix_globals.topology); if (PMIX_SUCCESS != rc) { /* nothing we can do */ goto cleanup; } } topo.topology = pmix_globals.topology.topology; } /* if the cpuset is NULL, see if we know the binding of the requesting process */ if (NULL == cpuset.bitmap) { PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.key = strdup(PMIX_CPUSET); PMIX_LOAD_PROCID(&proc, cd->peer->info->pname.nspace, cd->peer->info->pname.rank); cb.proc = &proc; cb.scope = PMIX_LOCAL; cb.copy = true; PMIX_GDS_FETCH_KV(rc, cd->peer, &cb); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&cb); goto cleanup; } kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs); rc = pmix_hwloc_parse_cpuset_string(kv->value->data.string, &cpuset); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&cb); goto cleanup; } PMIX_DESTRUCT(&cb); } /* compute the distances */ rc = pmix_hwloc_compute_distances(&topo, &cpuset, cd->info, cd->ninfo, &distances, &ndist); if (PMIX_SUCCESS == rc) { /* send the reply */ cbfunc(rc, distances, ndist, cd, NULL, NULL); PMIX_DEVICE_DIST_FREE(distances, ndist); } cleanup: if (NULL != topo.topology && topo.topology != pmix_globals.topology.topology) { pmix_hwloc_destruct_topology(&topo); } if (NULL != cpuset.bitmap) { pmix_hwloc_destruct_cpuset(&cpuset); } if (NULL != cpuset.source) { free(cpuset.source); } return rc; } pmix_status_t pmix_server_refresh_cache(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc) { pmix_proc_t p; char *nspace; int cnt; pmix_status_t rc; pmix_cb_t cb; pmix_buffer_t *pbkt; pmix_kval_t *kv; PMIX_HIDE_UNUSED_PARAMS(cbfunc); // unpack the ID of the proc being requested cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &nspace, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_LOAD_NSPACE(p.nspace, nspace); free(nspace); cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &p.rank, &cnt, PMIX_PROC_RANK); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* retrieve the data for the specific rank they are asking about */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &p; cb.scope = PMIX_REMOTE; cb.copy = false; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); // pack it up pbkt = PMIX_NEW(pmix_buffer_t); // start with the status PMIX_BFROPS_PACK(rc, cd->peer, pbkt, &cb.status, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(pbkt); return rc; } PMIX_LIST_FOREACH(kv, &cb.kvs, pmix_kval_t) { PMIX_BFROPS_PACK(rc, cd->peer, pbkt, kv, 1, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(pbkt); return rc; } } PMIX_DESTRUCT(&cb); // send it back to the requestor PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, pbkt); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(pbkt); } return PMIX_SUCCESS; } pmix_status_t pmix_server_resblk(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_op_cbfunc_t cbfunc) { int32_t cnt; pmix_status_t rc; pmix_setup_caddy_t *scd; pmix_proc_t proc; pmix_resource_block_directive_t directive; pmix_output_verbose(2, pmix_server_globals.base_output, "%s recvd resource block request from client %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_PEER_PRINT(cd->peer)); if (NULL == pmix_host_server.resource_block) { return PMIX_ERR_NOT_SUPPORTED; } scd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } scd->cbdata = cd; /* unpack the directive */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &directive, &cnt, PMIX_RESBLOCK_DIRECTIVE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } // unpack the block name cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &scd->nspace, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the number of units */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &scd->nunits, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the resource units */ if (0 < scd->nunits) { PMIX_RESOURCE_UNIT_CREATE(scd->units, scd->nunits); cnt = scd->nunits; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, scd->units, &cnt, PMIX_RESOURCE_UNIT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* unpack the number of info */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &scd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the info */ if (0 < scd->ninfo) { PMIX_INFO_CREATE(scd->info, scd->ninfo); cnt = scd->ninfo; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, scd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* setup the requesting peer name */ pmix_strncpy(proc.nspace, cd->peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = cd->peer->info->pname.rank; /* ask the host to execute the request */ rc = pmix_host_server.resource_block(&proc, directive, scd->nspace, scd->units, scd->nunits, scd->info, scd->ninfo, cbfunc, scd); if (PMIX_SUCCESS != rc) { goto exit; } return PMIX_SUCCESS; exit: PMIX_RELEASE(scd); return rc; } pmix_status_t pmix_server_session_ctrl(pmix_server_caddy_t *cd, pmix_buffer_t *buf, pmix_info_cbfunc_t cbfunc) { int32_t cnt; pmix_status_t rc; pmix_shift_caddy_t *scd; pmix_proc_t proc; pmix_output_verbose(2, pmix_server_globals.base_output, "%s recvd session ctrl request from client %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_PEER_PRINT(cd->peer)); if (NULL == pmix_host_server.session_control) { return PMIX_ERR_NOT_SUPPORTED; } scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == cd) { return PMIX_ERR_NOMEM; } scd->cbdata = cd; scd->cbfunc.infocbfunc = cbfunc; /* unpack the sessionID */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &scd->sessionid, &cnt, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the number of info objects */ cnt = 1; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &scd->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } /* unpack the info */ if (0 < scd->ninfo) { PMIX_INFO_CREATE(scd->info, scd->ninfo); cnt = scd->ninfo; PMIX_BFROPS_UNPACK(rc, cd->peer, buf, scd->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } } /* setup the requesting peer name */ pmix_strncpy(proc.nspace, cd->peer->info->pname.nspace, PMIX_MAX_NSLEN); proc.rank = cd->peer->info->pname.rank; /* ask the host to execute the request */ rc = pmix_host_server.session_control(&proc, scd->sessionid, scd->info, scd->ninfo, cbfunc, scd); if (PMIX_SUCCESS != rc) { goto exit; } return PMIX_SUCCESS; exit: PMIX_RELEASE(scd); return rc; } /***** INSTANCE SERVER LIBRARY CLASSES *****/ static void gcon(pmix_grpinfo_t *p) { PMIX_LOAD_PROCID(&p->proc, NULL, PMIX_RANK_UNDEF); PMIX_BYTE_OBJECT_CONSTRUCT(&p->blob); } static void gdes(pmix_grpinfo_t *p) { PMIX_BYTE_OBJECT_DESTRUCT(&p->blob); } PMIX_CLASS_INSTANCE(pmix_grpinfo_t, pmix_list_item_t, gcon, gdes); static void tcon(pmix_server_trkr_t *t) { t->event_active = false; t->host_called = false; t->local = true; t->id = NULL; memset(t->pname.nspace, 0, PMIX_MAX_NSLEN + 1); t->pname.rank = PMIX_RANK_UNDEF; t->pcs = NULL; t->npcs = 0; PMIX_CONSTRUCT(&t->nslist, pmix_list_t); PMIX_CONSTRUCT_LOCK(&t->lock); t->def_complete = false; PMIX_CONSTRUCT(&t->local_cbs, pmix_list_t); t->nlocal = 0; t->local_cnt = 0; t->info = NULL; t->ninfo = 0; PMIX_CONSTRUCT(&t->grpinfo, pmix_list_t); t->grpop = PMIX_GROUP_NONE; /* this needs to be set explicitly */ t->collect_type = PMIX_COLLECT_INVALID; t->modexcbfunc = NULL; t->op_cbfunc = NULL; t->info_cbfunc = NULL; t->hybrid = false; t->cbdata = NULL; } static void tdes(pmix_server_trkr_t *t) { if (NULL != t->id) { free(t->id); } PMIX_DESTRUCT_LOCK(&t->lock); if (NULL != t->pcs) { free(t->pcs); } PMIX_LIST_DESTRUCT(&t->local_cbs); if (NULL != t->info) { PMIX_INFO_FREE(t->info, t->ninfo); } PMIX_LIST_DESTRUCT(&t->grpinfo); PMIX_LIST_DESTRUCT(&t->nslist); } PMIX_CLASS_INSTANCE(pmix_server_trkr_t, pmix_list_item_t, tcon, tdes); static void cdcon(pmix_server_caddy_t *cd) { memset(&cd->ev, 0, sizeof(pmix_event_t)); cd->event_active = false; cd->trk = NULL; cd->peer = NULL; cd->info = NULL; cd->ninfo = 0; cd->query = NULL; } static void cddes(pmix_server_caddy_t *cd) { if (cd->event_active) { pmix_event_del(&cd->ev); } if (NULL != cd->trk) { PMIX_RELEASE(cd->trk); } if (NULL != cd->peer) { PMIX_RELEASE(cd->peer); } if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } if (NULL != cd->query) { PMIX_QUERY_FREE(cd->query, 1); } } PMIX_CLASS_INSTANCE(pmix_server_caddy_t, pmix_list_item_t, cdcon, cddes); static void scadcon(pmix_setup_caddy_t *p) { p->peer = NULL; memset(&p->proc, 0, sizeof(pmix_proc_t)); PMIX_CONSTRUCT_LOCK(&p->lock); p->nspace = NULL; p->codes = NULL; p->ncodes = 0; p->procs = NULL; p->nprocs = 0; p->apps = NULL; p->napps = 0; p->server_object = NULL; p->nlocalprocs = 0; p->info = NULL; p->ninfo = 0; p->units = NULL; p->nunits = 0; p->copied = false; p->keys = NULL; p->channels = PMIX_FWD_NO_CHANNELS; memset(&p->flags, 0, sizeof(pmix_iof_flags_t)); p->bo = NULL; p->nbo = 0; p->cbfunc = NULL; p->opcbfunc = NULL; p->setupcbfunc = NULL; p->lkcbfunc = NULL; p->spcbfunc = NULL; p->cbdata = NULL; } static void scaddes(pmix_setup_caddy_t *p) { if (NULL != p->peer) { PMIX_RELEASE(p->peer); } PMIX_PROC_FREE(p->procs, p->nprocs); if (p->copied) { if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->ninfo); } if (NULL != p->apps) { PMIX_APP_FREE(p->apps, p->napps); } } PMIX_RESOURCE_UNIT_FREE(p->units, p->nunits); if (NULL != p->bo) { PMIX_BYTE_OBJECT_FREE(p->bo, p->nbo); } PMIX_DESTRUCT_LOCK(&p->lock); if (NULL != p->flags.file) { free(p->flags.file); } if (NULL != p->flags.directory) { free(p->flags.directory); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_setup_caddy_t, pmix_object_t, scadcon, scaddes); PMIX_CLASS_INSTANCE(pmix_trkr_caddy_t, pmix_object_t, NULL, NULL); static void dmcon(pmix_dmdx_remote_t *p) { p->cd = NULL; } static void dmdes(pmix_dmdx_remote_t *p) { if (NULL != p->cd) { PMIX_RELEASE(p->cd); } } PMIX_CLASS_INSTANCE(pmix_dmdx_remote_t, pmix_list_item_t, dmcon, dmdes); static void dmrqcon(pmix_dmdx_request_t *p) { memset(&p->ev, 0, sizeof(pmix_event_t)); p->event_active = false; p->lcd = NULL; p->key = NULL; } static void dmrqdes(pmix_dmdx_request_t *p) { if (p->event_active) { pmix_event_del(&p->ev); } if (NULL != p->lcd) { PMIX_RELEASE(p->lcd); } if (NULL != p->key) { free(p->key); } } PMIX_CLASS_INSTANCE(pmix_dmdx_request_t, pmix_list_item_t, dmrqcon, dmrqdes); static void lmcon(pmix_dmdx_local_t *p) { memset(&p->proc, 0, sizeof(pmix_proc_t)); PMIX_CONSTRUCT(&p->loc_reqs, pmix_list_t); p->info = NULL; p->ninfo = 0; } static void lmdes(pmix_dmdx_local_t *p) { if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->ninfo); } PMIX_LIST_DESTRUCT(&p->loc_reqs); } PMIX_CLASS_INSTANCE(pmix_dmdx_local_t, pmix_list_item_t, lmcon, lmdes); static void prevcon(pmix_peer_events_info_t *p) { p->peer = NULL; p->affected = NULL; p->naffected = 0; } static void prevdes(pmix_peer_events_info_t *p) { if (NULL != p->peer) { PMIX_RELEASE(p->peer); } if (NULL != p->affected) { PMIX_PROC_FREE(p->affected, p->naffected); } } PMIX_CLASS_INSTANCE(pmix_peer_events_info_t, pmix_list_item_t, prevcon, prevdes); static void regcon(pmix_regevents_info_t *p) { PMIX_CONSTRUCT(&p->peers, pmix_list_t); } static void regdes(pmix_regevents_info_t *p) { PMIX_LIST_DESTRUCT(&p->peers); } PMIX_CLASS_INSTANCE(pmix_regevents_info_t, pmix_list_item_t, regcon, regdes); static void ilcon(pmix_inventory_rollup_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); p->status = PMIX_SUCCESS; p->requests = 0; p->replies = 0; PMIX_CONSTRUCT(&p->payload, pmix_list_t); p->info = NULL; p->ninfo = 0; p->cbfunc = NULL; p->infocbfunc = NULL; p->opcbfunc = NULL; p->cbdata = NULL; } static void ildes(pmix_inventory_rollup_t *p) { PMIX_DESTRUCT_LOCK(&p->lock); PMIX_LIST_DESTRUCT(&p->payload); } PMIX_CLASS_INSTANCE(pmix_inventory_rollup_t, pmix_object_t, ilcon, ildes); PMIX_CLASS_INSTANCE(pmix_group_caddy_t, pmix_list_item_t, NULL, NULL); static void iocon(pmix_iof_cache_t *p) { p->bo = NULL; p->info = NULL; p->ninfo = 0; } static void iodes(pmix_iof_cache_t *p) { PMIX_BYTE_OBJECT_FREE(p->bo, 1); // macro protects against NULL if (0 < p->ninfo) { PMIX_INFO_FREE(p->info, p->ninfo); } } PMIX_CLASS_INSTANCE(pmix_iof_cache_t, pmix_list_item_t, iocon, iodes); static void pscon(pmix_pset_t *p) { p->name = NULL; p->members = NULL; p->nmembers = 0; } static void psdes(pmix_pset_t *p) { if (NULL != p->name) { free(p->name); } if (NULL != p->members) { free(p->members); } } PMIX_CLASS_INSTANCE(pmix_pset_t, pmix_list_item_t, pscon, psdes); pmix-6.1.1~rc2/src/mca/0000775000175000017500000000000015203536752015024 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pdl/0000775000175000017500000000000015203536752015603 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pdl/pdl.h0000664000175000017500000001434115203536752016536 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Dynamic library framework * * General Description: * * This framework provides portable access to dlopen- and dlsym-like * functionality, very similar to Libtool's libltdl. Indeed, one of * the components in this framework will use libltdl, if it is * present/available. However, on some common types systems where * libltdl headers and libraries are *not* available, we can support * plugins via this simple framework. * * This is a compile-time framework: a single component will be * selected by the priority that its configure.m4 provides. All other * components will be ignored (i.e., not built/not part of the * installation). Meaning: the static_components of the pdl framework * will always contain 0 or 1 components. * * SIDENOTE: PMIX used to embed libltdl. However, as of early * 2015, this became problematic, for a variety of complex and * uninteresting reasons (see the following if you care about the * details: https://github.com/open-mpi/ompi/issues/311, * http://debbugs.gnu.org/cgi/bugreport.cgi?bug=19370, * https://github.com/open-mpi/ompi/pull/366, * https://github.com/open-mpi/ompi/pull/390). That being said, we, * as a developer community, still wanted to be able to natively use * DSOs by default. A small/simple framework for PDL functionality, * along with a simple component that supports dlopen/dlsym on POSIX * platforms and another component that natively uses libltdl seemed * like a good solution. */ #ifndef PMIX_MCA_PDL_PDL_H #define PMIX_MCA_PDL_PDL_H #include "src/include/pmix_config.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" BEGIN_C_DECLS /** * Handle for an opened file */ struct pmix_pdl_handle_t; typedef struct pmix_pdl_handle_t pmix_pdl_handle_t; /** * Dynamically open the file specified. * * Arguments: * fname = Base filename to open. If NULL, open this process. * use_ext = If true, try various filename suffixes that are * relevant on this platform (e.g., .so, .dll, .dylib). If * false, just use exactly whatever was passed as fname. * private = If true, open the file in a private namespace. * Otherwise, open the file in a global namespace. * handle = Upon successful open, a handle to the opened file will * be returned. * err_msg= if non-NULL and !=PMIX_SUCCESS is returned, will point to a * string error message * * Returns: * PMIX_SUCCESS on success, or PMIX_ERROR * * Space for the handle must be allocated by the module (it can be * freed during the call to pmix_pdl_base_module_dlclose_fn_t). * * The err_msg points to an internal string and should not be altered * or freed by the caller. The contents of the err_msg string may * change after successive calls to pmix_pdl API calls. */ typedef int (*pmix_pdl_base_module_open_fn_t)(const char *fname, bool use_ext, bool private_namespace, pmix_pdl_handle_t **handle, char **err_msg); /** * Lookup a symbol in an opened file. * * Arguments: * handle = handle of a previously dynamically opened file * symbol = name of the symbol to lookup * ptr = if found, a pointer to the symbol. Otherwise, NULL. * err_msg= if non-NULL and !=PMIX_SUCCESS is returned, will point to a * string error message * Returns: * PMIX_SUCCESS on success, or PMIX_ERROR * * * The err_msg points to an internal string and should not be altered * or freed by the caller. The contents of the err_msg string may * change after successive calls to pmix_pdl API calls. */ typedef int (*pmix_pdl_base_module_lookup_fn_t)(pmix_pdl_handle_t *handle, const char *symbol, void **ptr, char **err_msg); /** * Dynamically close a previously dynamically-opened file. * * Arguments: * handle = handle of a previously dynamically opened file. * Returns: * PMIX_SUCCESS on success, or PMIX_ERROR * * This function should close the file and free and resources * associated with it (e.g., whatever is cached on the handle). */ typedef int (*pmix_pdl_base_module_close_fn_t)(pmix_pdl_handle_t *handle); /** * Search through a path of directories, invoking a callback on each * unique regular (non-Libtool) file basename found (e.g., will only * be invoked once for the files "foo.la" and "foo.so", with the * parameter "foo"). * * Arguments: * path = PMIX_ENV_SEP-delimited list of directories * cb_func= function to invoke on each filename found * data = context for callback function * Returns: * PMIX_SUCESS on success, PMIX_ERR* otherwise */ typedef int (*pmix_pdl_base_module_foreachfile_fn_t)( const char *search_path, int (*cb_func)(const char *filename, void *context), void *context); /** * Structure for PDL components. */ struct pmix_pdl_base_component_1_0_0_t { /** MCA base component */ pmix_mca_base_component_t base_version; /** Default priority */ int priority; }; typedef struct pmix_pdl_base_component_1_0_0_t pmix_pdl_base_component_1_0_0_t; typedef struct pmix_pdl_base_component_1_0_0_t pmix_pdl_base_component_t; /** * Structure for PDL modules */ struct pmix_pdl_base_module_1_0_0_t { pmix_mca_base_module_2_0_0_t super; /** Open / close */ pmix_pdl_base_module_open_fn_t open; pmix_pdl_base_module_close_fn_t close; /** Lookup a symbol */ pmix_pdl_base_module_lookup_fn_t lookup; /** Iterate looking for files */ pmix_pdl_base_module_foreachfile_fn_t foreachfile; }; typedef struct pmix_pdl_base_module_1_0_0_t pmix_pdl_base_module_1_0_0_t; typedef struct pmix_pdl_base_module_1_0_0_t pmix_pdl_base_module_t; /** * Macro for use in components that are of type PDL */ #define PMIX_PDL_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("pdl", 1, 0, 0) END_C_DECLS #endif /* PMIX_MCA_PDL_PDL_H */ pmix-6.1.1~rc2/src/mca/pdl/configure.m40000664000175000017500000000663715203536752020042 0ustar alastairalastairdnl -*- shell-script -*- dnl dnl Copyright (c) 2010-2015 Cisco Systems, Inc. All rights reserved. dnl Copyright (c) 2016-2017 Intel, Inc. All rights reserved. dnl Copyright (c) 2016-2019 Research Organization for Information Science dnl and Technology (RIST). All rights reserved. dnl $COPYRIGHT$ dnl dnl Additional copyrights may follow dnl dnl $HEADER$ dnl dnl There will only be one component used in this framework, and it will dnl be selected at configure time by priority. Components must set dnl their priorities in their configure.m4 file. dnl We only want one winning component (vs. STOP_AT_FIRST_PRIORITY, dnl which will allow all components of the same priority who succeed to dnl win) m4_define(MCA_pmix_pdl_CONFIGURE_MODE, STOP_AT_FIRST) AC_DEFUN([MCA_pmix_pdl_CONFIG],[ PMIX_HAVE_PDL_SUPPORT=0 # If --disable-dlopen was used, then have all the components fail # (we still need to configure them all so that things like "make # dist" work", but we just want the MCA system to (artificially) # conclude that it can't build any of the components. AS_IF([test $PMIX_ENABLE_DLOPEN_SUPPORT -eq 0], [want_pdl=0], [want_pdl=1]) MCA_CONFIGURE_FRAMEWORK([pdl], [$want_pdl]) # If we found no suitable static pdl component and dlopen support # was not specifically disabled, this is an error. AS_IF([test "$MCA_pmix_pdl_STATIC_COMPONENTS" = "" && \ test $PMIX_ENABLE_DLOPEN_SUPPORT -eq 1], [AC_MSG_WARN([Did not find a suitable static pmix pdl component]) AC_MSG_WARN([You might need to install libltld (and its headers) or]) AC_MSG_WARN([specify --disable-dlopen to configure.]) AC_MSG_ERROR([Cannot continue])]) # If we have a winning component (which, per above, will only # happen if --disable-dlopen was *not* specified), do some more # logic. AS_IF([test "$MCA_pmix_pdl_STATIC_COMPONENTS" != ""], [ # We had a winner -- w00t! PMIX_HAVE_PDL_SUPPORT=1 # If we added any -L flags to ADD_LDFLAGS, then we (might) # need to add those directories to LD_LIBRARY_PATH. # Otherwise, if we try to AC RUN_IFELSE anything here in # configure, it might die because it can't find the libraries # we just linked against. PMIX_VAR_SCOPE_PUSH([pmix_pdl_base_found_l pmix_pdl_base_token pmix_pdl_base_tmp pmix_pdl_base_dir]) pmix_pdl_base_found_l=0 eval "pmix_pdl_base_tmp=\$pmix_pdl_${pmix_pdl_winner}_ADD_LIBS" for pmix_pdl_base_token in $pmix_pdl_base_tmp; do case $pmix_pdl_base_token in -l*) pmix_pdl_base_found_l=1 ;; esac done AS_IF([test $pmix_pdl_base_found_l -eq 1], [eval "pmix_pdl_base_tmp=\$pmix_pdl_${pmix_pdl_winner}_ADD_LDFLAGS" for pmix_pdl_base_token in $pmix_pdl_base_tmp; do case $pmix_pdl_base_token in -L*) pmix_pdl_base_dir=`echo $pmix_pdl_base_token | cut -c3-` export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$pmix_pdl_base_dir AC_MSG_WARN([Adding to LD_LIBRARY_PATH: $pmix_pdl_base_dir]) ;; esac done]) PMIX_VAR_SCOPE_POP ]) AC_DEFINE_UNQUOTED([PMIX_HAVE_PDL_SUPPORT], [$PMIX_HAVE_PDL_SUPPORT], [Whether the PMIX PDL framework is functional or not]) ]) pmix-6.1.1~rc2/src/mca/pdl/base/0000775000175000017500000000000015203536752016515 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pdl/base/pdl_base_fns.c0000664000175000017500000000342715203536752021306 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * This file is a simple set of wrappers around the selected PMIX PDL * component (it's a compile-time framework with, at most, a single * component; see pdl.h for details). */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/mca/pdl/base/base.h" #include "src/util/pmix_output.h" int pmix_pdl_open(const char *fname, bool use_ext, bool private_namespace, pmix_pdl_handle_t **handle, char **err_msg) { *handle = NULL; if (NULL != pmix_pdl && NULL != pmix_pdl->open) { return pmix_pdl->open(fname, use_ext, private_namespace, handle, err_msg); } return PMIX_ERR_NOT_SUPPORTED; } int pmix_pdl_lookup(pmix_pdl_handle_t *handle, const char *symbol, void **ptr, char **err_msg) { if (NULL != pmix_pdl && NULL != pmix_pdl->lookup) { return pmix_pdl->lookup(handle, symbol, ptr, err_msg); } return PMIX_ERR_NOT_SUPPORTED; } int pmix_pdl_close(pmix_pdl_handle_t *handle) { if (NULL != pmix_pdl && NULL != pmix_pdl->close) { return pmix_pdl->close(handle); } return PMIX_ERR_NOT_SUPPORTED; } int pmix_pdl_foreachfile(const char *search_path, int (*cb_func)(const char *filename, void *context), void *context) { if (NULL != pmix_pdl && NULL != pmix_pdl->foreachfile) { return pmix_pdl->foreachfile(search_path, cb_func, context); } return PMIX_ERR_NOT_SUPPORTED; } pmix-6.1.1~rc2/src/mca/pdl/base/pdl_base_close.c0000664000175000017500000000132215203536752021615 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/mca/pdl/base/base.h" #include "src/mca/pdl/pdl.h" int pmix_pdl_base_close(void) { /* Close all available modules that are open */ return pmix_mca_base_framework_components_close(&pmix_pdl_base_framework, NULL); } pmix-6.1.1~rc2/src/mca/pdl/base/pdl_base_select.c0000664000175000017500000000320615203536752021772 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_UNISTD_H # include "unistd.h" #endif #include "pmix_common.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/mca/pdl/base/base.h" #include "src/mca/pdl/pdl.h" #include "src/util/pmix_output.h" int pmix_pdl_base_select(void) { int exit_status = PMIX_SUCCESS; pmix_pdl_base_component_t *best_component = NULL; pmix_pdl_base_module_t *best_module = NULL; /* * Select the best component */ if (PMIX_SUCCESS != pmix_mca_base_select("pdl", pmix_pdl_base_framework.framework_output, &pmix_pdl_base_framework.framework_components, (pmix_mca_base_module_t **) &best_module, (pmix_mca_base_component_t **) &best_component, NULL)) { /* This will only happen if no component was selected */ exit_status = PMIX_ERROR; goto cleanup; } /* Save the winner */ pmix_pdl_base_selected_component = best_component; pmix_pdl = best_module; cleanup: return exit_status; } pmix-6.1.1~rc2/src/mca/pdl/base/base.h0000664000175000017500000000476015203536752017607 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PDL_BASE_H #define PMIX_PDL_BASE_H #include "src/include/pmix_config.h" #include "src/mca/pdl/pdl.h" #include "src/util/pmix_environ.h" #include "src/mca/base/pmix_base.h" BEGIN_C_DECLS /** * Globals */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_pdl_base_framework; extern pmix_pdl_base_component_t *pmix_pdl_base_selected_component; extern pmix_pdl_base_module_t *pmix_pdl; /** * Initialize the PDL MCA framework * * @retval PMIX_SUCCESS Upon success * @retval PMIX_ERROR Upon failures * * This function is invoked during pmix_init(); */ int pmix_pdl_base_open(pmix_mca_base_open_flag_t flags); /** * Select an available component. * * @retval PMIX_SUCCESS Upon Success * @retval PMIX_NOT_FOUND If no component can be selected * @retval PMIX_ERROR Upon other failure * */ int pmix_pdl_base_select(void); /** * Finalize the PDL MCA framework * * @retval PMIX_SUCCESS Upon success * @retval PMIX_ERROR Upon failures * * This function is invoked during pmix_finalize(); */ int pmix_pdl_base_close(void); /** * Open a DSO * * (see pmix_pdl_base_module_open_ft_t in pmix/mca/pdl/pdl.h for * documentation of this function) */ int pmix_pdl_open(const char *fname, bool use_ext, bool private_namespace, pmix_pdl_handle_t **handle, char **err_msg); /** * Lookup a symbol in a DSO * * (see pmix_pdl_base_module_lookup_ft_t in pmix/mca/pdl/pdl.h for * documentation of this function) */ int pmix_pdl_lookup(pmix_pdl_handle_t *handle, const char *symbol, void **ptr, char **err_msg); /** * Close a DSO * * (see pmix_pdl_base_module_close_ft_t in pmix/mca/pdl/pdl.h for * documentation of this function) */ int pmix_pdl_close(pmix_pdl_handle_t *handle); /** * Iterate over files in a path * * (see pmix_pdl_base_module_foreachfile_ft_t in pmix/mca/pdl/pdl.h for * documentation of this function) */ int pmix_pdl_foreachfile(const char *search_path, int (*cb_func)(const char *filename, void *context), void *context); END_C_DECLS #endif /* PMIX_PDL_BASE_H */ pmix-6.1.1~rc2/src/mca/pdl/base/pdl_base_open.c0000664000175000017500000000371515203536752021461 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/mca/pdl/base/base.h" #include "src/mca/pdl/base/static-components.h" /* * Globals */ pmix_pdl_base_module_t *pmix_pdl = NULL; pmix_pdl_base_component_t *pmix_pdl_base_selected_component = NULL; /* * Function for finding and opening either all MCA components, * or the one that was specifically requested via a MCA parameter. * * Note that we really don't need this function -- we could specify a * NULL pointer in the framework declare and the base would do this * exact same thing. However, we need to have at least some * executable code in this file, or some linkers (cough cough OS X * cough cough) may not actually link in this .o file. */ int pmix_pdl_base_open(pmix_mca_base_open_flag_t flags) { /* Open up all available components */ return pmix_mca_base_framework_components_open(&pmix_pdl_base_framework, flags); } /* VERY IMPORTANT: This framework is static, and is opened before any other dynamic frameworks are opened (which makes sense, of course). But we must mark this framework is NO_DSO so that the MCA framework base doesn't try to open any dynamic components in this framework. */ PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, pdl, "Dynamic loader framework", NULL /* register */, pmix_pdl_base_open /* open */, NULL /* close */, pmix_mca_pdl_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_NO_DSO); pmix-6.1.1~rc2/src/mca/pdl/base/Makefile.am0000664000175000017500000000047515203536752020557 0ustar alastairalastair# # Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers += \ base/base.h libmca_pdl_la_SOURCES += \ base/pdl_base_open.c \ base/pdl_base_close.c \ base/pdl_base_select.c \ base/pdl_base_fns.c pmix-6.1.1~rc2/src/mca/pdl/pdlopen/0000775000175000017500000000000015203536752017244 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pdl/pdlopen/pdl_pdlopen_component.c0000664000175000017500000000676315203536752024006 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/mca/pdl/pdl.h" #include "src/util/pmix_argv.h" #include "pdl_pdlopen.h" /* * Public string showing the sysinfo ompi_linux component version number */ const char *pmix_pdl_pdlopen_component_version_string = "PMIX pdl pdlopen MCA component version " PMIX_VERSION; /* * Local functions */ static int pdlopen_component_register(void); static int pdlopen_component_open(void); static int pdlopen_component_close(void); static int pdlopen_component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_pdl_pdlopen_component_t pmix_mca_pdl_pdlopen_component = { /* Fill in the mca_pdl_base_component_t */ .base = { /* First, the mca_component_t struct containing meta information about the component itself */ .base_version = { PMIX_PDL_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "pdlopen", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component functions */ .pmix_mca_register_component_params = pdlopen_component_register, .pmix_mca_open_component = pdlopen_component_open, .pmix_mca_close_component = pdlopen_component_close, .pmix_mca_query_component = pdlopen_component_query, }, /* The pdl framework members */ .priority = 80 }, }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pdl, pdlopen) static int pdlopen_component_register(void) { int ret; pmix_mca_pdl_pdlopen_component.filename_suffixes_mca_storage = ".so,.dylib,.dll,.sl"; ret = pmix_mca_base_component_var_register( &pmix_mca_pdl_pdlopen_component.base.base_version, "filename_suffixes", "Comma-delimited list of filename suffixes that the pdlopen component will try", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pdl_pdlopen_component.filename_suffixes_mca_storage); if (ret < 0) { return ret; } pmix_mca_pdl_pdlopen_component.filename_suffixes = PMIx_Argv_split(pmix_mca_pdl_pdlopen_component.filename_suffixes_mca_storage, ','); return PMIX_SUCCESS; } static int pdlopen_component_open(void) { return PMIX_SUCCESS; } static int pdlopen_component_close(void) { if (NULL != pmix_mca_pdl_pdlopen_component.filename_suffixes) { PMIx_Argv_free(pmix_mca_pdl_pdlopen_component.filename_suffixes); pmix_mca_pdl_pdlopen_component.filename_suffixes = NULL; } return PMIX_SUCCESS; } static int pdlopen_component_query(pmix_mca_base_module_t **module, int *priority) { /* The priority value is somewhat meaningless here; by pmix/mca/pdl/configure.m4, there's at most one component available. */ *priority = pmix_mca_pdl_pdlopen_component.base.priority; *module = &pmix_pdl_pdlopen_module.super; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pdl/pdlopen/configure.m40000664000175000017500000000445615203536752021500 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2016 Research Organization for Information Science # and Technology (RIST). All rights reserved. # # Copyright (c) 2017 Intel, Inc. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # Copyright (c) 2023 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AC_DEFUN([MCA_pmix_pdl_pdlopen_PRIORITY], [80]) # # Force this component to compile in static-only mode # AC_DEFUN([MCA_pmix_pdl_pdlopen_COMPILE_MODE], [ AC_MSG_CHECKING([for MCA component $1:$2 compile mode]) $3="static" AC_MSG_RESULT([$$3]) ]) # MCA_pmix_pdl_pdlopen_POST_CONFIG() # --------------------------------- AC_DEFUN([MCA_pmix_pdl_pdlopen_POST_CONFIG],[ # If we won, then do all the rest of the setup AS_IF([test "$1" = "1"], [ # Add some stuff to CPPFLAGS so that the rest of the source # tree can be built LDFLAGS="$LDFLAGS $pmix_pdl_pdlopen_ADD_LDFLAGS" LIBS="$LIBS $pmix_pdl_pdlopen_ADD_LIBS" ]) ])dnl # MCA_pdl_pdlopen_CONFIG([action-if-can-compile], # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pdl_pdlopen_CONFIG],[ AC_CONFIG_FILES([src/mca/pdl/pdlopen/Makefile]) dnl This is effectively a back-door for PMIX developers to dnl force the use of the libltdl pdl component. AC_ARG_ENABLE([pmix-dlopen], [AS_HELP_STRING([--disable-pmix-dlopen], [Disable the PMIx "dlopen" PDL component (and probably force the use of the "libltdl" PDL component).]) ]) pmix_pdl_pdlopen_happy=no AS_IF([test "$enable_pmix_dlopen" != "no"], [OAC_CHECK_PACKAGE([dlopen], [pmix_pdl_pdlopen], [dlfcn.h], [dl], [dlopen], [pmix_pdl_pdlopen_happy=yes], [pmix_pdl_pdlopen_happy=no]) ]) AS_IF([test "$pmix_pdl_pdlopen_happy" = "yes"], [pmix_pdl_pdlopen_ADD_LIBS=$pmix_pdl_pdlopen_LIBS $1], [$2]) AC_SUBST(pmix_pdl_pdlopen_LIBS) ]) pmix-6.1.1~rc2/src/mca/pdl/pdlopen/pdl_pdlopen.h0000664000175000017500000000166615203536752021726 0ustar alastairalastair/* * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PDL_PDLOPEN #define PMIX_PDL_PDLOPEN #include "src/include/pmix_config.h" #include "src/mca/pdl/pdl.h" extern pmix_pdl_base_module_t pmix_pdl_pdlopen_module; /* * Dynamic library handles generated by this component. * * If we're debugging, keep a copy of the name of the file we've opened. */ struct pmix_pdl_handle_t { void *dlopen_handle; #if PMIX_ENABLE_DEBUG void *filename; #endif }; typedef struct { pmix_pdl_base_component_t base; char *filename_suffixes_mca_storage; char **filename_suffixes; } pmix_pdl_pdlopen_component_t; extern pmix_pdl_pdlopen_component_t pmix_mca_pdl_pdlopen_component; #endif /* PMIX_PDL_PDLOPEN */ pmix-6.1.1~rc2/src/mca/pdl/pdlopen/Makefile.am0000664000175000017500000000127715203536752021307 0ustar alastairalastair# # Copyright (c) 2004-2010 The Trustees of Indiana University. # All rights reserved. # Copyright (c) 2014-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # sources = \ pdl_pdlopen.h \ pdl_pdlopen_component.c \ pdl_pdlopen_module.c # This component will only ever be built statically -- never as a DSO. noinst_LTLIBRARIES = libpmix_mca_pdl_pdlopen.la libpmix_mca_pdl_pdlopen_la_SOURCES = $(sources) libpmix_mca_pdl_pdlopen_la_LDFLAGS = -module -avoid-version libpmix_mca_pdl_pdlopen_la_LIBADD = $(pmix_pdl_pdlopen_LIBS) pmix-6.1.1~rc2/src/mca/pdl/pdlopen/pdl_pdlopen_module.c0000664000175000017500000001642615203536752023266 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #include #include #include #include "pmix_common.h" #include "src/mca/pdl/pdl.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "pdl_pdlopen.h" /* * Trivial helper function to avoid replicating code */ static void do_pdlopen(const char *fname, int flags, void **handle, char **err_msg) { assert(handle); *handle = dlopen(fname, flags); if (NULL != err_msg) { if (NULL != *handle) { *err_msg = NULL; } else { *err_msg = dlerror(); } } } static int pdlopen_open(const char *fname, bool use_ext, bool private_namespace, pmix_pdl_handle_t **handle, char **err_msg) { int rc; assert(handle); *handle = NULL; /* Setup the dlopen flags */ int flags = RTLD_LAZY; if (private_namespace) { flags |= RTLD_LOCAL; } else { flags |= RTLD_GLOBAL; } /* If the caller wants to use filename extensions, loop through them */ void *local_handle = NULL; if (use_ext && NULL != fname) { int i; char *ext; for (i = 0, ext = pmix_mca_pdl_pdlopen_component.filename_suffixes[i]; NULL != ext; ext = pmix_mca_pdl_pdlopen_component.filename_suffixes[++i]) { char *name; rc = asprintf(&name, "%s%s", fname, ext); if (0 > rc) { return PMIX_ERR_NOMEM; } if (NULL == name) { return PMIX_ERR_IN_ERRNO; } /* Does the file exist? */ struct stat buf; /* coverity[TOCTOU] */ if (stat(name, &buf) < 0) { if (NULL != err_msg) { rc = asprintf(err_msg, "File %s not found", name); if (0 > rc) { free(name); return PMIX_ERR_NOMEM; } } free(name); continue; } /* Yes, the file exists -- try to dlopen it. If we can't dlopen it, bail. */ do_pdlopen(name, flags, &local_handle, err_msg); free(name); break; } } /* Otherwise, the caller does not want to use filename extensions, so just use the single filename that the caller provided */ else { do_pdlopen(fname, flags, &local_handle, err_msg); } if (NULL != local_handle) { *handle = calloc(1, sizeof(pmix_pdl_handle_t)); (*handle)->dlopen_handle = local_handle; #if PMIX_ENABLE_DEBUG if (NULL != fname) { (*handle)->filename = strdup(fname); } else { (*handle)->filename = strdup("(null)"); } #endif } return (NULL != local_handle) ? PMIX_SUCCESS : PMIX_ERROR; } static int pdlopen_lookup(pmix_pdl_handle_t *handle, const char *symbol, void **ptr, char **err_msg) { assert(handle); assert(handle->dlopen_handle); assert(symbol); assert(ptr); *ptr = dlsym(handle->dlopen_handle, symbol); if (NULL != *ptr) { return PMIX_SUCCESS; } if (NULL != err_msg) { *err_msg = dlerror(); } return PMIX_ERROR; } static int pdlopen_close(pmix_pdl_handle_t *handle) { assert(handle); int ret; ret = dlclose(handle->dlopen_handle); #if PMIX_ENABLE_DEBUG free(handle->filename); #endif free(handle); return ret; } /* * Scan all the files in a directory (or path) and invoke a callback * on each one. */ static int pdlopen_foreachfile(const char *search_path, int (*func)(const char *filename, void *data), void *data) { int ret; DIR *dp = NULL; char **dirs = NULL; char **good_files = NULL; dirs = PMIx_Argv_split(search_path, PMIX_ENV_SEP); for (int i = 0; NULL != dirs && NULL != dirs[i]; ++i) { dp = opendir(dirs[i]); if (NULL == dp) { ret = PMIX_ERR_IN_ERRNO; goto error; } struct dirent *de; while (NULL != (de = readdir(dp))) { /* Make the absolute path name */ char *abs_name = NULL; ret = asprintf(&abs_name, "%s/%s", dirs[i], de->d_name); if (0 > ret) { goto error; } if (NULL == abs_name) { ret = PMIX_ERR_IN_ERRNO; goto error; } /* Stat the file */ struct stat buf; /* coverity[TOCTOU] */ if (stat(abs_name, &buf) < 0) { free(abs_name); ret = PMIX_ERR_IN_ERRNO; goto error; } /* Skip if not a file */ if (!S_ISREG(buf.st_mode)) { free(abs_name); continue; } /* Find the suffix */ char *ptr = strrchr(abs_name, '.'); if (NULL != ptr) { /* Skip libtool files */ if (strcmp(ptr, ".la") == 0 || strcmp(ptr, ".lo") == 0) { free(abs_name); continue; } /* Skip .o files */ if (strcmp(ptr, ".o") == 0) { free(abs_name); continue; } *ptr = '\0'; } /* Have we already found this file? Or already found a file with the same basename (but different suffix)? */ bool found = false; for (int j = 0; NULL != good_files && NULL != good_files[j]; ++j) { if (strcmp(good_files[j], abs_name) == 0) { found = true; break; } } if (!found) { PMIx_Argv_append_nosize(&good_files, abs_name); } free(abs_name); } closedir(dp); } dp = NULL; /* Invoke the callback on all the found files */ if (NULL != good_files) { for (int i = 0; NULL != good_files[i]; ++i) { ret = func(good_files[i], data); if (PMIX_SUCCESS != ret) { goto error; } } } ret = PMIX_SUCCESS; error: if (NULL != dp) { closedir(dp); } if (NULL != dirs) { PMIx_Argv_free(dirs); } if (NULL != good_files) { PMIx_Argv_free(good_files); } return ret; } /* * Module definition */ pmix_pdl_base_module_t pmix_pdl_pdlopen_module = {.open = pdlopen_open, .lookup = pdlopen_lookup, .close = pdlopen_close, .foreachfile = pdlopen_foreachfile}; pmix-6.1.1~rc2/src/mca/pdl/Makefile.am0000664000175000017500000000175715203536752017651 0ustar alastairalastair# # Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2010-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # main library setup noinst_LTLIBRARIES = libmca_pdl.la libmca_pdl_la_SOURCES = # local files headers = pdl.h libmca_pdl_la_SOURCES += $(headers) # Ensure that the man pages are rebuilt if the pmix_config.h file # changes; a "good enough" way to know if configure was run again (and # therefore the release date or version may have changed) $(nodist_man_MANS): $(top_builddir)/pmix/include/pmix_config.h # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.am distclean-local: rm -f base/static-components.h rm -f $(nodist_man_MANS) pmix-6.1.1~rc2/src/mca/pdl/plibltdl/0000775000175000017500000000000015203536752017411 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pdl/plibltdl/pdl_libltdl_component.c0000664000175000017500000001077115203536752024132 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, Inc. All rights * reserved. * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include "pmix/mca/base/pmix_mca_base_var.h" #include "pmix/mca/pdl/pdl.h" #include "pmix/util/pmix_argv.h" #include "pdl_libltdl.h" /* * Public string showing the sysinfo ompi_linux component version number */ const char *pmix_pdl_plibltpdl_component_version_string = "PMIX pdl plibltdl MCA component version " PMIX_VERSION; /* * Local functions */ static int plibltpdl_component_register(void); static int plibltpdl_component_open(void); static int plibltpdl_component_close(void); static int plibltpdl_component_query(mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_pdl_plibltpdl_component_t mca_pdl_plibltpdl_component = { /* Fill in the mca_pdl_base_component_t */ .base = { /* First, the mca_component_t struct containing meta information about the component itself */ .base_version = { PMIX_DL_BASE_VERSION_1_0_0, /* Component name and version */ .mca_component_name = "plibltdl", MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component functions */ .mca_register_component_params = plibltpdl_component_register, .mca_open_component = plibltpdl_component_open, .mca_close_component = plibltpdl_component_close, .mca_query_component = plibltpdl_component_query, }, /* The dl framework members */ .priority = 50 } /* Now fill in the plibltdl component-specific members */ }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pdl, plibltdl) static int plibltpdl_component_register(void) { /* Register an info param indicating whether we have lt_dladvise support or not */ bool supported = PMIX_INT_TO_BOOL(PMIX_DL_LIBLTDL_HAVE_LT_DLADVISE); mca_base_component_var_register(&mca_pdl_plibltpdl_component.base.base_version, "have_lt_dladvise", "Whether the version of plibltdl that this component is built " "against supports lt_dladvise functionality or not", MCA_BASE_VAR_TYPE_BOOL, NULL, 0, MCA_BASE_VAR_FLAG_DEFAULT_ONLY, PMIX_INFO_LVL_7, MCA_BASE_VAR_SCOPE_CONSTANT, &supported); return PMIX_SUCCESS; } static int plibltpdl_component_open(void) { if (lt_dlinit()) { return PMIX_ERROR; } #if PMIX_DL_LIBLTDL_HAVE_LT_DLADVISE pmix_pdl_plibltpdl_component_t *c = &mca_pdl_plibltpdl_component; if (lt_dladvise_init(&c->advise_private_noext)) { return PMIX_ERR_OUT_OF_RESOURCE; } if (lt_dladvise_init(&c->advise_private_ext) || lt_dladvise_ext(&c->advise_private_ext)) { return PMIX_ERR_OUT_OF_RESOURCE; } if (lt_dladvise_init(&c->advise_public_noext) || lt_dladvise_global(&c->advise_public_noext)) { return PMIX_ERR_OUT_OF_RESOURCE; } if (lt_dladvise_init(&c->advise_public_ext) || lt_dladvise_global(&c->advise_public_ext) || lt_dladvise_ext(&c->advise_public_ext)) { return PMIX_ERR_OUT_OF_RESOURCE; } #endif return PMIX_SUCCESS; } static int plibltpdl_component_close(void) { #if PMIX_DL_LIBLTDL_HAVE_LT_DLADVISE pmix_pdl_plibltpdl_component_t *c = &mca_pdl_plibltpdl_component; lt_dladvise_destroy(&c->advise_private_noext); lt_dladvise_destroy(&c->advise_private_ext); lt_dladvise_destroy(&c->advise_public_noext); lt_dladvise_destroy(&c->advise_public_ext); #endif lt_dlexit(); return PMIX_SUCCESS; } static int plibltpdl_component_query(mca_base_module_t **module, int *priority) { /* The priority value is somewhat meaningless here; by pmix/mca/dl/configure.m4, there's at most one component available. */ *priority = mca_pdl_plibltpdl_component.base.priority; *module = &pmix_pdl_plibltpdl_module.super; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pdl/plibltdl/pdl_libltdl.h0000664000175000017500000000235015203536752022047 0ustar alastairalastair/* * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2017 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_DL_LIBLTDL #define PMIX_DL_LIBLTDL #include "pmix_config.h" #include "pmix/mca/dl/dl.h" #include PMIX_DECLSPEC extern pmix_pdl_base_module_t pmix_pdl_plibltpdl_module; /* * Dynamic library handles generated by this component. * * If we're debugging, keep a copy of the name of the file we've opened. */ struct pmix_pdl_handle_t { lt_dlhandle ltpdl_handle; #if PMIX_ENABLE_DEBUG char *filename; #endif }; typedef struct { pmix_pdl_base_component_t base; #if PMIX_DL_LIBLTDL_HAVE_LT_DLADVISE /* If the version of plibltdl that we are compiling against has lt_dladvise, use it to support opening DSOs in a variety of modes. */ lt_dladvise advise_private_noext; lt_dladvise advise_private_ext; lt_dladvise advise_public_noext; lt_dladvise advise_public_ext; #endif } pmix_pdl_plibltpdl_component_t; PMIX_DECLSPEC extern pmix_pdl_plibltpdl_component_t mca_pdl_plibltpdl_component; #endif /* PMIX_DL_LIBLTDL */ pmix-6.1.1~rc2/src/mca/pdl/plibltdl/configure.m40000664000175000017500000000704615203536752021643 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved. # # Copyright (c) 2017 Intel, Inc. All rights reserved. # Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AC_DEFUN([MCA_pmix_pdl_plibltdl_PRIORITY], [50]) # # Force this component to compile in static-only mode # AC_DEFUN([MCA_pmix_pdl_plibltdl_COMPILE_MODE], [ AC_MSG_CHECKING([for MCA component $1:$2 compile mode]) $3="static" AC_MSG_RESULT([$$3]) ]) # MCA_pmix_pdl_plibltdl_POST_CONFIG() # --------------------------------- AC_DEFUN([MCA_pmix_pdl_plibltdl_POST_CONFIG],[ # If we won, then do all the rest of the setup AS_IF([test "$1" = "1"], [ # Add some stuff to CPPFLAGS so that the rest of the source # tree can be built LDFLAGS="$LDFLAGS $pmix_pdl_plibltdl_ADD_LDFLAGS" LIBS="$LIBS $pmix_pdl_plibltdl_ADD_LIBS" ]) ])dnl # MCA_dl_plibltdl_CONFIG([action-if-can-compile], # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pdl_plibltdl_CONFIG],[ PMIX_VAR_SCOPE_PUSH([CPPFLAGS_save LDFLAGS_save LIBS_save]) AC_CONFIG_FILES([src/mca/pdl/plibltdl/Makefile]) # Add --with options AC_ARG_WITH([libltdl], [AS_HELP_STRING([--with-libltdl(=DIR)], [Build libltdl support, optionally adding DIR/include, DIR/lib, and DIR/lib64 to the search path for headers and libraries])]) AC_ARG_WITH([libltdl-libdir], [AS_HELP_STRING([--with-libltdl-libdir=DIR], [Search for libltdl libraries in DIR])]) pmix_pdl_plibltdl_happy=no AS_IF([test "$with_libltdl" != "no"], [OAC_CHECK_PACKAGE([libltdl], [pmix_pdl_plibltdl], [ltdl.h], [ltdl], [lt_dlopen], [pmix_pdl_plibltdl_happy=yes], [pmix_pdl_plibltdl_happy=no]) ]) # If we have plibltdl, do we have lt_dladvise? pmix_pdl_plibltdl_have_lt_dladvise=0 AS_IF([test "$pmix_pdl_plibltdl_happy" = "yes"], [CPPFLAGS_save=$CPPFLAGS LDFLAGS_save=$LDFLAGS LIBS_save=$LIBS CPPFLAGS="$pmix_pdl_plibltdl_CPPFLAGS $CPPFLAGS" LDFLAGS="$pmix_pdl_plibltdl_LDFLAGS $LDFLAGS" LIBS="$pmix_pdl_plibltdl_LIBS $LIBS" AC_CHECK_FUNC([lt_dladvise_init], [pmix_pdl_plibltdl_have_lt_dladvise=1]) CPPFLAGS=$CPPFLAGS_save LDFLAGS=$LDFLAGS_save LIBS=$LIBS_save ]) AC_DEFINE_UNQUOTED(PMIX_PDL_PLIBLTDL_HAVE_LT_DLADVISE, [$pmix_pdl_plibltdl_have_lt_dladvise], [Whether we have lt_dladvise or not]) AS_IF([test "$pmix_pdl_plibltdl_happy" = "yes"], [pmix_pdl_plibltdl_ADD_CPPFLAGS=$pmix_pdl_plibltdl_CPPFLAGS pmix_pdl_plibltdl_ADD_LDFLAGS=$pmix_pdl_plibltdl_LDFLAGS pmix_pdl_plibltdl_ADD_LIBS=$pmix_pdl_plibltdl_LIBS $1], [AS_IF([test ! -z "$with_libltdl" && \ test "$with_libltdl" != "no"], [AC_MSG_WARN([libltdl support requested (via --with-libltdl) but not found.]) AC_MSG_ERROR([Cannot continue.])]) $2]) AC_SUBST(pmix_pdl_plibltdl_CPPFLAGS) AC_SUBST(pmix_pdl_plibltdl_LDFLAGS) AC_SUBST(pmix_pdl_plibltdl_LIBS) PMIX_VAR_SCOPE_POP ]) pmix-6.1.1~rc2/src/mca/pdl/plibltdl/Makefile.am0000664000175000017500000000156615203536752021455 0ustar alastairalastair# # Copyright (c) 2004-2010 The Trustees of Indiana University. # All rights reserved. # Copyright (c) 2014-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # sources = \ pdl_libltdl.h \ pdl_libltdl_component.c \ pdl_libltdl_module.c # This component will only ever be built statically -- never as a DSO. noinst_LTLIBRARIES = libpmix_mca_pdl_plibltdl.la libpmix_mca_pdl_plibltdl_la_SOURCES = $(sources) libpmix_mca_pdl_plibltdl_la_CPPFLAGS = $(pmix_pdl_plibltdl_CPPFLAGS) libpmix_mca_pdl_plibltdl_la_LDFLAGS = \ $(pmix_pdl_plibltdl_LDFLAGS) \ -module -avoid-version libpmix_mca_pdl_plibltdl_la_LIBADD = $(pmix_pdl_plibltdl_LIBS) pmix-6.1.1~rc2/src/mca/pdl/plibltdl/pdl_libltdl_module.c0000664000175000017500000000636715203536752023423 0ustar alastairalastair/* * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix/constants.h" #include "pmix/mca/pdl/pdl.h" #include "pdl_libltdl.h" static int plibltpdl_open(const char *fname, bool use_ext, bool private_namespace, pmix_pdl_handle_t **handle, char **err_msg) { assert(handle); *handle = NULL; if (NULL != err_msg) { *err_msg = NULL; } lt_dlhandle local_handle; #if PMIX_DL_LIBLTDL_HAVE_LT_DLADVISE pmix_pdl_plibltpdl_component_t *c = &mca_pdl_plibltpdl_component; if (use_ext && private_namespace) { local_handle = lt_dlopenadvise(fname, c->advise_private_ext); } else if (use_ext && !private_namespace) { local_handle = lt_dlopenadvise(fname, c->advise_public_ext); } else if (!use_ext && private_namespace) { local_handle = lt_dlopenadvise(fname, c->advise_private_noext); } else if (!use_ext && !private_namespace) { local_handle = lt_dlopenadvise(fname, c->advise_public_noext); } #else if (use_ext) { local_handle = lt_dlopenext(fname); } else { local_handle = lt_dlopen(fname); } #endif if (NULL != local_handle) { *handle = calloc(1, sizeof(pmix_pdl_handle_t)); (*handle)->ltpdl_handle = local_handle; #if PMIX_ENABLE_DEBUG if (NULL != fname) { (*handle)->filename = strdup(fname); } else { (*handle)->filename = strdup("(null)"); } #endif return PMIX_SUCCESS; } if (NULL != err_msg) { *err_msg = strdup((char *) lt_dlerror()); } return PMIX_ERROR; } static int plibltpdl_lookup(pmix_pdl_handle_t *handle, const char *symbol, void **ptr, char **err_msg) { assert(handle); assert(handle->ltpdl_handle); assert(symbol); assert(ptr); if (NULL != err_msg) { *err_msg = NULL; } *ptr = lt_dlsym(handle->ltpdl_handle, symbol); if (NULL != *ptr) { return PMIX_SUCCESS; } if (NULL != err_msg) { *err_msg = strdup((char *) lt_dlerror()); } return PMIX_ERROR; } static int plibltpdl_close(pmix_pdl_handle_t *handle) { assert(handle); int ret; ret = lt_dlclose(handle->ltpdl_handle); #if PMIX_ENABLE_DEBUG free(handle->filename); #endif free(handle); return ret; } static int plibltpdl_foreachfile(const char *search_path, int (*func)(const char *filename, void *data), void *data) { assert(search_path); assert(func); int ret = lt_dlforeachfile(search_path, func, data); return (0 == ret) ? PMIX_SUCCESS : PMIX_ERROR; } /* * Module definition */ pmix_pdl_base_module_t pmix_pdl_plibltpdl_module = {.open = plibltpdl_open, .lookup = plibltpdl_lookup, .close = plibltpdl_close, .foreachfile = plibltpdl_foreachfile}; pmix-6.1.1~rc2/src/mca/gds/0000775000175000017500000000000015203536752015601 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/gds/shmem2/0000775000175000017500000000000015203536752016774 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/gds/shmem2/gds_shmem2_store.h0000664000175000017500000000202315203536752022406 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_GDS_SHMEM2_STORE_H #define PMIX_GDS_SHMEM2_STORE_H #include "gds_shmem2.h" BEGIN_C_DECLS PMIX_EXPORT pmix_status_t pmix_gds_shmem2_store_qualified( pmix_hash_table_t *ht, pmix_rank_t rank, pmix_value_t *value ); PMIX_EXPORT pmix_status_t pmix_gds_shmem2_store_local_job_data_in_shmem2( pmix_gds_shmem2_job_t *job, pmix_list_t *job_data ); END_C_DECLS #endif /* * vim: ft=cpp ts=4 sts=4 sw=4 expandtab */ pmix-6.1.1~rc2/src/mca/gds/shmem2/gds_shmem2.c0000664000175000017500000025214515203536752021201 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2022-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022-2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "gds_shmem2.h" #include "gds_shmem2_utils.h" #include "gds_shmem2_store.h" #include "gds_shmem2_fetch.h" #include "src/include/pmix_dictionary.h" #include "src/util/pmix_show_help.h" #include "src/util/pmix_string_copy.h" #include "src/util/pmix_vmem.h" #include "src/client/pmix_client_ops.h" #include "src/server/pmix_server_ops.h" // // Notes for developers: // We cannot use PMIX_CONSTRUCT for data that are stored in shared memory // because their address is on the stack of the process in which they are // constructed. // // Some items for future consideration: // * Address FT case at some point. We need to have a broader conversion about // how we go about doing this. Ralph has some ideas. /** * Key names used to find shared-memory segment info. */ #define SHMEM2_SEG_BLOB_KEY "PMIX_GDS_SHMEM2_SEG_BLOB" #define SHMEM2_SEG_NSID_KEY "PMIX_GDS_SHMEM2_NSPACEID" #define SHMEM2_SEG_SMID_KEY "PMIX_GDS_SHMEM2_SMSEGID" #define SHMEM2_SEG_PATH_KEY "PMIX_GDS_SHMEM2_SEG_PATH" #define SHMEM2_SEG_SIZE_KEY "PMIX_GDS_SHMEM2_SEG_SIZE" #define SHMEM2_SEG_HADR_KEY "PMIX_GDS_SHMEM2_SEG_HADR" #define SHMEM2_KIDX_KEY "PMIX_GDS_SHMEM2_KIDX" #define SHMEM2_KIDX_NSID_KEY "PMIX_GDS_SHMEM2_KIDX_NSPACEID" #define SHMEM2_KIDX_TAB_SIZE_KEY "PMIX_GDS_SHMEM2_KIDX_TAB_SIZE" #define SHMEM2_KIDX_INDEX_KEY "PMIX_GDS_SHMEM2_KIDX_INDEX" #define SHMEM2_KIDX_TYPE_KEY "PMIX_GDS_SHMEM2_KIDX_TYPE" #define SHMEM2_KIDX_NAME_KEY "PMIX_GDS_SHMEM2_KIDX_NAME" #define SHMEM2_KIDX_STRING_KEY "PMIX_GDS_SHMEM2_KIDX_STRING" #define SHMEM2_KIDX_DESCRIPTION_KEY "PMIX_GDS_SHMEM2_KIDX_DESCRIPTION" #define SHMEM2_KIDX_ELEM_DONE_KEY "PMIX_GDS_SHMEM2_KIDX_ELEM_DONE" #define EMSG_SHMEM2_IS_BROKEN "\n***\nAn unrecoverable error occurred in the " \ "gds/shmem2 component.\nResolve this issue by disabling it. Set in your " \ "environment the following:\nPMIX_MCA_gds=hash\n***\n" #define EMSG_SHMEM2_OOM "\n***\nA memory allocation backed by shared-memory " \ "failed in the gds/shmem2 component.\nResolve this issue by either:" \ "\n1.) Increasing the value of PMIX_MCA_gds_shmem2_segment_size_multiplier " \ "\nor" \ "\n2.) Disabling gds/shmem2 via PMIX_MCA_gds=hash\n***\n" /** * Stores packed job information. */ typedef struct { pmix_object_t super; /** Session ID associated with this job. */ uint32_t session_id; /** Size of packed data. */ size_t packed_size; /** Number of hash elements found. */ size_t hash_table_size; } pmix_gds_shmem2_packed_local_job_info_t; PMIX_CLASS_DECLARATION(pmix_gds_shmem2_packed_local_job_info_t); /** * Stores modex sizing information. */ typedef struct { size_t size; size_t num_ht_elements; } pmix_gds_shmem2_modex_info_t; /** * Stores modex context information. */ typedef struct { size_t buff_size; size_t nprocs; } pmix_gds_shmem2_modex_ctx_t; static void packed_job_info_construct( pmix_gds_shmem2_packed_local_job_info_t *pji ) { pji->session_id = UINT32_MAX; pji->packed_size = 0; pji->hash_table_size = 0; } PMIX_CLASS_INSTANCE( pmix_gds_shmem2_packed_local_job_info_t, pmix_object_t, packed_job_info_construct, // Destruct is the same as above because we just invalidate the data. packed_job_info_construct ); /** * Store unpacked shared-memory segment information. */ typedef struct { pmix_object_t super; char *nsid; pmix_gds_shmem2_job_shmem2_id_t smid; char *seg_path; size_t seg_size; size_t seg_hadr; } pmix_gds_shmem2_unpacked_seg_blob_t; PMIX_CLASS_DECLARATION(pmix_gds_shmem2_unpacked_seg_blob_t); static void unpacked_seg_blob_construct( pmix_gds_shmem2_unpacked_seg_blob_t *ub ) { ub->nsid = NULL; ub->smid = PMIX_GDS_SHMEM2_INVALID_ID; ub->seg_path = NULL; ub->seg_size = 0; ub->seg_hadr = 0; } static void unpacked_seg_blob_destruct( pmix_gds_shmem2_unpacked_seg_blob_t *ub ) { free(ub->nsid); free(ub->seg_path); } PMIX_CLASS_INSTANCE( pmix_gds_shmem2_unpacked_seg_blob_t, pmix_object_t, unpacked_seg_blob_construct, unpacked_seg_blob_destruct ); /** * String to size_t. */ static inline pmix_status_t strtost( const char *str, int base, size_t *maybe_val ) { *maybe_val = 0; errno = 0; char *end = NULL; const long long val = strtoll(str, &end, base); const int err = errno; if ((err == ERANGE && val == LLONG_MAX) || (err == ERANGE && val == LLONG_MIN) || *end != '\0') { return PMIX_ERROR; } *maybe_val = (size_t)val; return PMIX_SUCCESS; } /** * Stores TMA memory allocation information. */ typedef struct { /** Size of allocation. */ size_t extent; } pmix_gds_shmem2_tma_alloc_t; /** * Holds allocation context information. */ typedef struct { pmix_object_t super; /** Address to allocation information table. */ pmix_hash_table_t addr2info; /** Handle to shared-memory backing store. */ pmix_shmem_t *shmem2; /** Points to a value that maintains the next available address. */ void **data_ptr; } pmix_gds_shmem2_alloc_ctx_t; PMIX_CLASS_DECLARATION(pmix_gds_shmem2_alloc_ctx_t); static void shmem2_allocator_construct( pmix_gds_shmem2_alloc_ctx_t *a ) { PMIX_CONSTRUCT(&a->addr2info, pmix_hash_table_t); pmix_hash_table_init(&a->addr2info, 2048); a->shmem2 = NULL; a->data_ptr = NULL; } static void shmem2_allocator_destruct( pmix_gds_shmem2_alloc_ctx_t *a ) { pmix_gds_shmem2_tma_alloc_t *value; void *key; PMIX_HASH_TABLE_FOREACH_PTR(key, value, &a->addr2info, { free(value); }); PMIX_DESTRUCT(&a->addr2info); a->shmem2 = NULL; a->data_ptr = NULL; } PMIX_CLASS_INSTANCE( pmix_gds_shmem2_alloc_ctx_t, pmix_object_t, shmem2_allocator_construct, shmem2_allocator_destruct ); /** * Architecture-specific address alignment. */ static inline void * addr_align( void *base, size_t size ) { #if 0 // Helpful debug PMIX_GDS_SHMEM2_VVOUT("------------------------ADDRINN=%p,%zd", base, size); #endif void *const res = (void *)(((uintptr_t)base + size + 7) & ~(uintptr_t)0x07); #if 0 // Helpful debug // Make sure that it's 8-byte aligned. assert ((uintptr_t)res % 8 == 0); PMIX_GDS_SHMEM2_VVOUT("------------------------ADDROUT=%p,%zd", res, size); #endif return res; } static inline pmix_gds_shmem2_alloc_ctx_t * tma_get_alloc_ctx( pmix_tma_t *tma ) { return tma->data_context; } static inline void * tma_get_curraddr( pmix_tma_t *tma ) { return *(tma_get_alloc_ctx(tma)->data_ptr); } static inline void tma_set_curraddr( pmix_tma_t *tma, void *newaddr ) { *(tma_get_alloc_ctx(tma)->data_ptr) = newaddr; } static inline bool tma_alloc_request_will_overflow( pmix_tma_t *tma, size_t alloc_size ) { const pmix_gds_shmem2_alloc_ctx_t *const ctx = tma_get_alloc_ctx(tma); const pmix_shmem_t *const backing_store = ctx->shmem2; const uintptr_t hdr_baseptr = (uintptr_t)backing_store->hdr_address; const uintptr_t data_baseptr = (uintptr_t)backing_store->data_address; const uintptr_t data_ptr_pos = (uintptr_t)tma_get_curraddr(tma); // Size of 'lost capacity` because of segment header. const size_t lost_capacity = (size_t)(data_baseptr - hdr_baseptr); const size_t bytes_used = (size_t)(data_ptr_pos - data_baseptr); bool wo = (bytes_used + alloc_size) > (backing_store->size - lost_capacity); if (PMIX_UNLIKELY(wo)) { errno = ENOMEM; perror(EMSG_SHMEM2_OOM); abort(); } return wo; } static inline void tma_register_alloc( pmix_tma_t *tma, void *base, size_t extent ) { uintptr_t key = (uintptr_t)base; pmix_gds_shmem2_tma_alloc_t *value = calloc(1, sizeof(*value)); value->extent = extent; pmix_hash_table_set_value_ptr( &tma_get_alloc_ctx(tma)->addr2info, &key, sizeof(key), value ); } static inline pmix_status_t tma_get_registered_alloc( pmix_tma_t *tma, void *addr, pmix_gds_shmem2_tma_alloc_t **result ) { uintptr_t key = (uintptr_t)addr; return pmix_hash_table_get_value_ptr( &tma_get_alloc_ctx(tma)->addr2info, &key, sizeof(uintptr_t), (void **)result ); } static inline void * tma_malloc( pmix_tma_t *tma, size_t size ) { if (0 == size) { return NULL; } if (PMIX_UNLIKELY(tma_alloc_request_will_overflow(tma, size))) { return NULL; } void *const current = tma_get_curraddr(tma); tma_register_alloc(tma, current, size); #if PMIX_ENABLE_DEBUG memset(current, 0, size); #endif tma_set_curraddr(tma, addr_align(current, size)); return current; } static inline void * tma_calloc( struct pmix_tma *tma, size_t nmemb, size_t size ) { const size_t real_size = nmemb * size; if (0 == real_size) { return NULL; } if (PMIX_UNLIKELY(tma_alloc_request_will_overflow(tma, real_size))) { return NULL; } void *const current = tma_get_curraddr(tma); tma_register_alloc(tma, current, real_size); memset(current, 0, real_size); tma_set_curraddr(tma, addr_align(current, real_size)); return current; } static inline void * tma_realloc( pmix_tma_t *tma, void *ptr, size_t new_size ) { // Behave like malloc if (NULL == ptr) { return tma_malloc(tma, new_size); } // Behave like free if (0 == new_size) { pmix_tma_free(tma, ptr); return NULL; } // Find the allocation info based on the provided address. pmix_gds_shmem2_tma_alloc_t *alloc = NULL; int rc = tma_get_registered_alloc(tma, ptr, &alloc); if (PMIX_SUCCESS != rc) { errno = EFAULT; perror(EMSG_SHMEM2_IS_BROKEN); abort(); } const size_t old_size = alloc->extent; if (new_size != old_size) { void *new_base = pmix_tma_malloc(tma, new_size); if (NULL == new_base) { return ptr; } // Move min(new_size, old_size) into new space. memmove(new_base, ptr, new_size < old_size ? new_size : old_size); pmix_tma_free(tma, ptr); return new_base; } return ptr; } static inline char * tma_strdup( pmix_tma_t *tma, const char *s ) { const size_t size = strlen(s) + 1; if (PMIX_UNLIKELY(tma_alloc_request_will_overflow(tma, size))) { return NULL; } void *const current = tma_get_curraddr(tma); tma_register_alloc(tma, current, size); tma_set_curraddr(tma, addr_align(current, size)); return (char *)memmove(current, s, size); } static inline void tma_free( struct pmix_tma *tma, void *ptr ) { PMIX_HIDE_UNUSED_PARAMS(tma, ptr); // We don't do anything for free. } static void tma_init_function_pointers( pmix_tma_t *tma ) { tma->tma_malloc = tma_malloc; tma->tma_calloc = tma_calloc; tma->tma_realloc = tma_realloc; tma->tma_strdup = tma_strdup; tma->tma_free = tma_free; } static void tma_init( pmix_shmem_t *shmem2_backing_store, pmix_tma_t *tma, void *data_ptr ) { // Only available in the allocator's address space. pmix_gds_shmem2_alloc_ctx_t *ctx = PMIX_NEW(pmix_gds_shmem2_alloc_ctx_t); tma_init_function_pointers(tma); tma->data_context = (void *)ctx; ctx->shmem2 = shmem2_backing_store; ctx->data_ptr = data_ptr; } static void host_alias_construct( pmix_gds_shmem2_host_alias_t *a ) { a->name = NULL; } static void host_alias_destruct( pmix_gds_shmem2_host_alias_t *a ) { pmix_tma_t *const tma = pmix_obj_get_tma(&a->super.super); if (a->name) { pmix_tma_free(tma, a->name); } } PMIX_CLASS_INSTANCE( pmix_gds_shmem2_host_alias_t, pmix_list_item_t, host_alias_construct, host_alias_destruct ); static void nodeinfo_construct( pmix_gds_shmem2_nodeinfo_t *n ) { pmix_tma_t *const tma = pmix_obj_get_tma(&n->super.super); n->nodeid = UINT32_MAX; n->hostname = NULL; n->aliases = PMIX_NEW(pmix_list_t, tma); n->info = PMIX_NEW(pmix_list_t, tma); } static void nodeinfo_destruct( pmix_gds_shmem2_nodeinfo_t *n ) { pmix_tma_t *const tma = pmix_obj_get_tma(&n->super.super); pmix_tma_free(tma, n->hostname); if (n->aliases) { PMIX_LIST_DESTRUCT(n->aliases); } if (n->info) { PMIX_LIST_DESTRUCT(n->info); } } PMIX_CLASS_INSTANCE( pmix_gds_shmem2_nodeinfo_t, pmix_list_item_t, nodeinfo_construct, nodeinfo_destruct ); static void job_construct( pmix_gds_shmem2_job_t *job ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); // Backing store ownership job->uid = geteuid(); job->gid = getegid(); job->chown = false; job->chgrp = false; // Namespace identification job->nspace_id = NULL; job->nspace = NULL; // Session job->session = PMIX_NEW(pmix_gds_shmem2_session_t); // Job job->shmem2_status = 0; job->shmem2 = PMIX_NEW(pmix_shmem_t); job->smdata = NULL; // Modex job->modex_shmem2_status = 0; job->modex_shmem2 = PMIX_NEW(pmix_shmem_t); job->smmodex = NULL; // Connection info job->conni = NULL; // Fixup flag job->client_keyindex_fixup_done = false; } static pmix_tma_t * get_tma_by_shmem2_id( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id ) { switch (shmem2_id) { case PMIX_GDS_SHMEM2_JOB_ID: return &job->smdata->tma; case PMIX_GDS_SHMEM2_MODEX_ID: return &job->smmodex->tma; case PMIX_GDS_SHMEM2_SESSION_ID: return &job->session->smdata->tma; case PMIX_GDS_SHMEM2_INVALID_ID: default: PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); // This is an internal error. abort(); return NULL; } } static const char * get_shmem2_id_name( pmix_gds_shmem2_job_shmem2_id_t shmem2_id ) { switch (shmem2_id) { case PMIX_GDS_SHMEM2_JOB_ID: return "smdata"; case PMIX_GDS_SHMEM2_MODEX_ID: return "smmodex"; case PMIX_GDS_SHMEM2_SESSION_ID: return "smsession"; case PMIX_GDS_SHMEM2_INVALID_ID: default: PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); // This is an internal error. abort(); return NULL; } } static void emit_shmem2_usage_stats( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id ) { pmix_status_t rc = PMIX_SUCCESS; pmix_shmem_t *shmem2; rc = pmix_gds_shmem2_get_job_shmem2_by_id( job, shmem2_id, &shmem2 ); if (PMIX_UNLIKELY(rc != PMIX_SUCCESS)) { PMIX_ERROR_LOG(rc); return; } pmix_tma_t *tma = get_tma_by_shmem2_id(job, shmem2_id); const char *smname = get_shmem2_id_name(shmem2_id); const size_t shmem2_size = shmem2->size; const size_t bytes_used = (size_t)((uintptr_t)tma_get_curraddr(tma) - (uintptr_t)shmem2->data_address); const float utilization = (bytes_used / (float)shmem2_size) * 100.0; PMIX_GDS_SHMEM2_VOUT( "%s memory statistics: " "segment size=%zd, bytes used=%zd, utilization=%.2f %%", smname, shmem2_size, bytes_used, utilization ); } static void job_destruct( pmix_gds_shmem2_job_t *job ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); pmix_status_t rc = PMIX_SUCCESS; if (job->nspace_id) { free(job->nspace_id); } if (job->nspace) { PMIX_RELEASE(job->nspace); } if (job->conni) { PMIX_RELEASE(job->conni); } static const pmix_gds_shmem2_job_shmem2_id_t shmem2_ids[] = { PMIX_GDS_SHMEM2_JOB_ID, PMIX_GDS_SHMEM2_MODEX_ID, PMIX_GDS_SHMEM2_SESSION_ID, PMIX_GDS_SHMEM2_INVALID_ID }; for (int i = 0; shmem2_ids[i] != PMIX_GDS_SHMEM2_INVALID_ID; ++i) { const pmix_gds_shmem2_job_shmem2_id_t sid = shmem2_ids[i]; pmix_shmem_t *shmem2; rc = pmix_gds_shmem2_get_job_shmem2_by_id(job, sid, &shmem2); if (PMIX_UNLIKELY(rc != PMIX_SUCCESS)) { PMIX_ERROR_LOG(rc); return; } if (pmix_gds_shmem2_has_status(job, sid, PMIX_GDS_SHMEM2_MINE)) { // Emit usage status before we potentially destroy the segment. emit_shmem2_usage_stats(job, sid); // Points to a pmix_gds_shmem2_alloc_ctx_t. PMIX_RELEASE(get_tma_by_shmem2_id(job, sid)->data_context); } // Releases memory for the structures located in shared-memory. This // will also unmap in case we need to later remap something in the // address space covered by this. PMIX_RELEASE(shmem2); // Invalidate the shmem2 flags. pmix_gds_shmem2_clearall_status(job, sid); } if (job->session) { PMIX_RELEASE(job->session); } } PMIX_CLASS_INSTANCE( pmix_gds_shmem2_job_t, pmix_list_item_t, job_construct, job_destruct ); static void app_construct( pmix_gds_shmem2_app_t *a ) { pmix_tma_t *const tma = pmix_obj_get_tma(&a->super.super); a->appnum = 0; a->appinfo = PMIX_NEW(pmix_list_t, tma); a->nodeinfo = PMIX_NEW(pmix_list_t, tma); a->job = NULL; } static void app_destruct( pmix_gds_shmem2_app_t *a ) { if (a->appinfo) { PMIX_LIST_DESTRUCT(a->appinfo); } if (a->nodeinfo) { PMIX_LIST_DESTRUCT(a->nodeinfo); } } PMIX_CLASS_INSTANCE( pmix_gds_shmem2_app_t, pmix_list_item_t, app_construct, app_destruct ); static void session_construct( pmix_gds_shmem2_session_t *s ) { s->shmem2 = PMIX_NEW(pmix_shmem_t); s->shmem2_status = 0; s->smdata = NULL; } static void session_destruct( pmix_gds_shmem2_session_t *s ) { // job_destruct took care of our shmem2. s->shmem2 = NULL; // Invalidate the shmem2 flags. s->shmem2_status = 0; s->smdata = NULL; } PMIX_CLASS_INSTANCE( pmix_gds_shmem2_session_t, pmix_list_item_t, session_construct, session_destruct ); static pmix_status_t session_smdata_construct( pmix_gds_shmem2_job_t *job, uint32_t sid ) { pmix_status_t rc = PMIX_SUCCESS; // Setup the shared information structure. It will be at the base address of // the shared-memory segment. The memory is already allocated, so let the // session know about its data located at the base of the segment. const size_t smdata_size = sizeof(*job->session->smdata); void *const baseaddr = job->session->shmem2->data_address; job->session->smdata = baseaddr; memset(job->session->smdata, 0, smdata_size); // Save the starting address for TMA memory allocations. job->session->smdata->current_addr = baseaddr; // Setup the TMA. tma_init( job->session->shmem2, &job->session->smdata->tma, &job->session->smdata->current_addr ); // Now we need to update the TMA's pointer to account for our using up some // space for its header. tma_set_curraddr(&job->session->smdata->tma, addr_align(baseaddr, smdata_size)); // We can now safely get our TMA. pmix_tma_t *const tma = &job->session->smdata->tma; // Now that we know the TMA, initialize smdata structures using it. job->session->smdata->id = sid; job->session->smdata->sessioninfo = PMIX_NEW(pmix_list_t, tma); if (!job->session->smdata->sessioninfo) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } job->session->smdata->nodeinfo = PMIX_NEW(pmix_list_t, tma); if (!job->session->smdata->nodeinfo) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } pmix_gds_shmem2_vout_smsession(job->session); out: if (PMIX_SUCCESS != rc) { if (job->session->smdata->sessioninfo) { PMIX_RELEASE(job->session->smdata->sessioninfo); } if (job->session->smdata->nodeinfo) { PMIX_RELEASE(job->session->smdata->nodeinfo); } } return rc; } static pmix_status_t job_smdata_construct( pmix_gds_shmem2_job_t *job, size_t htsize ) { pmix_status_t rc = PMIX_SUCCESS; // Setup the shared information structure. It will be at the base address of // the shared-memory segment. The memory is already allocated, so let the // job know about its data located at the base of the segment. const size_t smdata_size = sizeof(*job->smdata); void *const baseaddr = job->shmem2->data_address; job->smdata = baseaddr; memset(job->smdata, 0, smdata_size); // Save the starting address for TMA memory allocations. job->smdata->current_addr = baseaddr; // Setup the TMA. tma_init(job->shmem2, &job->smdata->tma, &job->smdata->current_addr); // Now we need to update the TMA's pointer to account for our using up some // space for its header. tma_set_curraddr(&job->smdata->tma, addr_align(baseaddr, smdata_size)); // We can now safely get our TMA. pmix_tma_t *const tma = &job->smdata->tma; // Now that we know the TMA, initialize smdata structures using it. job->smdata->jobinfo = PMIX_NEW(pmix_list_t, tma); if (!job->smdata->jobinfo) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } job->smdata->nodeinfo = PMIX_NEW(pmix_list_t, tma); if (!job->smdata->nodeinfo) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } job->smdata->appinfo = PMIX_NEW(pmix_list_t, tma); if (!job->smdata->appinfo) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } // Will always have local data, so set it up. job->smdata->local_hashtab = PMIX_NEW(pmix_hash_table_t, tma); if (!job->smdata->local_hashtab) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } pmix_hash_table_init(job->smdata->local_hashtab, htsize); pmix_gds_shmem2_vout_smdata(job); out: if (PMIX_SUCCESS != rc) { if (job->smdata->jobinfo) { PMIX_RELEASE(job->smdata->jobinfo); } if (job->smdata->nodeinfo) { PMIX_RELEASE(job->smdata->nodeinfo); } if (job->smdata->appinfo) { PMIX_RELEASE(job->smdata->appinfo); } if (job->smdata->local_hashtab) { PMIX_RELEASE(job->smdata->local_hashtab); } } return rc; } static pmix_status_t modex_smdata_construct( pmix_gds_shmem2_job_t *job, size_t htsize ) { pmix_status_t rc = PMIX_SUCCESS; // Setup the shared information structure. It will be at the base address of // the shared-memory segment. The memory is already allocated, so let the // job know about its data located at the base of the segment. const size_t smmodex_size = sizeof(*job->smmodex); void *const baseaddr = job->modex_shmem2->data_address; job->smmodex = baseaddr; memset(job->smmodex, 0, smmodex_size); // Save the starting address for TMA memory allocations. job->smmodex->current_addr = baseaddr; // Setup the TMA. tma_init(job->modex_shmem2, &job->smmodex->tma, &job->smmodex->current_addr); // Now we need to update the TMA's pointer to account for our using up some // space for its header. tma_set_curraddr(&job->smmodex->tma, addr_align(baseaddr, smmodex_size)); // We can now safely get our TMA. pmix_tma_t *const tma = &job->smmodex->tma; // Now that we know the TMA, initialize smdata structures using it. job->smmodex->hashtab = PMIX_NEW(pmix_hash_table_t, tma); if (!job->smmodex->hashtab) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); return rc; } pmix_hash_table_init(job->smmodex->hashtab, htsize); pmix_gds_shmem2_vout_smmodex(job); return rc; } /** * Returns the base temp directory. */ static inline const char * fetch_base_tmpdir( pmix_gds_shmem2_job_t *job ) { pmix_status_t rc = PMIX_SUCCESS; static char fetched_path[PMIX_PATH_MAX] = {'\0'}; // Keys we may fetch, in priority order. char *fetch_keys[] = { PMIX_NSDIR, PMIX_TMPDIR, NULL }; // Did we get a usable fetched key/value? bool fetched_kv = false; for (int i = 0; NULL != fetch_keys[i]; ++i) { pmix_cb_t cb; PMIX_CONSTRUCT(&cb, pmix_cb_t); pmix_proc_t wildcard; PMIX_LOAD_PROCID( &wildcard, job->nspace->nspace, PMIX_RANK_WILDCARD ); cb.key = fetch_keys[i]; cb.proc = &wildcard; cb.copy = true; cb.scope = PMIX_LOCAL; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); if (rc != PMIX_SUCCESS) { PMIX_DESTRUCT(&cb); break; } // We should only have one item here. assert(1 == pmix_list_get_size(&cb.kvs)); // Get a pointer to the only item in the list. pmix_kval_t *kv = (pmix_kval_t *)pmix_list_get_first(&cb.kvs); // Make sure we are dealing with the right stuff. assert(PMIX_CHECK_KEY(kv, fetch_keys[i])); assert(kv->value->type == PMIX_STRING); // Copy the value over. size_t nw = snprintf( fetched_path, PMIX_PATH_MAX, "%s", kv->value->data.string ); PMIX_DESTRUCT(&cb); if (nw >= PMIX_PATH_MAX) { // Try another. continue; } else { // We got a usable fetched key. fetched_kv = true; break; } } // Didn't find a specific temp basedir, so just use a general one. if (!fetched_kv) { static const char *tmpdir = NULL; if (NULL == (tmpdir = getenv("TMPDIR"))) { tmpdir = "/tmp"; } return tmpdir; } else { return fetched_path; } } /** * Returns a valid path or NULL on error. */ static inline const char * get_shmem2_backing_path( pmix_gds_shmem2_job_t *job, const char *id ) { static char path[PMIX_PATH_MAX] = {'\0'}; const char *basedir = fetch_base_tmpdir(job); // Now that we have the base path, append unique name. size_t nw = snprintf( path, PMIX_PATH_MAX, "%s/%s-gds-%s.%s-%s.%s.%d", basedir, PACKAGE_NAME, PMIX_GDS_SHMEM2_NAME, pmix_globals.hostname, job->nspace_id, id, getpid() ); if (nw >= PMIX_PATH_MAX) { return NULL; } return path; } /** * Returns a valid shared-memory session name or NULL on error. */ static inline const char * get_shmem2_session_name( uint32_t session_id ) { static char name[64] = {'\0'}; // Now that we have the base path, append unique name. size_t nw = snprintf( name, sizeof(name), "session.%zx", (size_t)session_id ); if (nw >= sizeof(name)) { return NULL; } return name; } /** * Attaches to the given shared-memory segment. */ static pmix_status_t shmem2_attach( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, uintptr_t req_addr ) { pmix_status_t rc = PMIX_SUCCESS; pmix_shmem_t *shmem2; rc = pmix_gds_shmem2_get_job_shmem2_by_id( job, shmem2_id, &shmem2 ); if (PMIX_UNLIKELY(rc != PMIX_SUCCESS)) { PMIX_ERROR_LOG(rc); return rc; } rc = pmix_shmem_segment_attach( shmem2, req_addr, PMIX_SHMEM_MUST_MAP_AT_RADDR ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { // This type of error occurs when we // didn't map to the requested address. if (PMIX_ERR_NOT_AVAILABLE == rc) { pmix_show_help("help-gds-shmem2.txt", "shmem2-segment-attach:address-mismatch", true, (size_t)req_addr, (size_t)shmem2->hdr_address ); rc = PMIX_ERROR; } goto out; } PMIX_GDS_SHMEM2_VOUT( "%s: mmapd at address=0x%zx", __func__, (size_t)shmem2->hdr_address ); out: if (PMIX_SUCCESS != rc) { (void)pmix_shmem_segment_detach(shmem2); // remove the job from the tracker pmix_list_remove_item(&pmix_mca_gds_shmem2_component.jobs, &job->super); PMIX_RELEASE(job); } else { pmix_gds_shmem2_set_status( job, shmem2_id, PMIX_GDS_SHMEM2_ATTACHED ); } return rc; } static inline pmix_status_t init_client_side_sm_data( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id ) { switch (shmem2_id) { case PMIX_GDS_SHMEM2_JOB_ID: job->smdata = job->shmem2->data_address; pmix_gds_shmem2_vout_smdata(job); break; case PMIX_GDS_SHMEM2_SESSION_ID: job->session->smdata = job->session->shmem2->data_address; pmix_gds_shmem2_vout_smsession(job->session); break; case PMIX_GDS_SHMEM2_MODEX_ID: job->smmodex = job->modex_shmem2->data_address; pmix_gds_shmem2_vout_smmodex(job); break; case PMIX_GDS_SHMEM2_INVALID_ID: default: PMIX_ERROR_LOG(PMIX_ERROR); abort(); return PMIX_ERROR; } // Segment is ready for use by the client. pmix_gds_shmem2_set_status(job, shmem2_id, PMIX_GDS_SHMEM2_READY_FOR_USE); // Note: don't update the TMA to point to its local function pointers // because clients should only be reading from the shared-memory segment. return PMIX_SUCCESS; } static pmix_status_t shmem2_segment_attach_and_init( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_unpacked_seg_blob_t *seginfo ) { pmix_status_t rc = PMIX_SUCCESS; pmix_shmem_t *shmem2; rc = pmix_gds_shmem2_get_job_shmem2_by_id( job, seginfo->smid, &shmem2 ); if (PMIX_UNLIKELY(rc != PMIX_SUCCESS)) { PMIX_ERROR_LOG(rc); return rc; } // Initialize the segment path. const size_t buffmax = sizeof(shmem2->backing_path); pmix_string_copy(shmem2->backing_path, seginfo->seg_path, buffmax); // Initialize the segment size. shmem2->size = seginfo->seg_size; const uintptr_t req_addr = (uintptr_t)seginfo->seg_hadr; rc = shmem2_attach(job, seginfo->smid, req_addr); if (PMIX_UNLIKELY(rc != PMIX_SUCCESS)) { return rc; } // Now we can safely initialize our shared data structures. rc = init_client_side_sm_data(job, seginfo->smid); #if 0 // Protect memory: clients can only read from here. mprotect( shmem2->data_address, shmem2->size, PROT_READ ); #endif return rc; } /** * Updates backing file permissions based on PMIx directives. */ static pmix_status_t shmem2_segment_fix_perms( pmix_gds_shmem2_job_t *job, pmix_shmem_t *shmem2 ) { pmix_status_t rc = PMIX_SUCCESS; // Update segment ownership and permissions? if (job->chown || job->chgrp) { const uid_t uid = job->chown ? job->uid : (uid_t)-1; const gid_t gid = job->chgrp ? job->gid : (gid_t)-1; rc = pmix_shmem_segment_chown(shmem2, uid, gid); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } rc = pmix_shmem_segment_chmod( shmem2, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } } return rc; } /** * Create and attach to a shared-memory segment. */ static pmix_status_t shmem2_segment_create_and_attach( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, const char *segment_name, size_t segment_size ) { pmix_status_t rc = PMIX_SUCCESS; // Pad given size to fill remaining space on the last page. const size_t real_segsize = pmix_shmem_utils_pad_to_page(segment_size); // Find a hole in virtual memory that meets our size requirements. size_t base_addr = 0; rc = pmix_vmem_find_hole( VMEM_HOLE_BIGGEST, &base_addr, real_segsize ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } PMIX_GDS_SHMEM2_VOUT( "%s: %s found vmhole at address=0x%zx", __func__, segment_name, base_addr ); // Find a unique path for the shared-memory backing file. const char *segment_path = get_shmem2_backing_path(job, segment_name); if (PMIX_UNLIKELY(!segment_path)) { rc = PMIX_ERROR; PMIX_ERROR_LOG(rc); goto out; } PMIX_GDS_SHMEM2_VOUT( "%s: segment backing file path is %s (size=%zd B)", __func__, segment_path, real_segsize ); // Get a handle to the appropriate shmem2. pmix_shmem_t *shmem2; rc = pmix_gds_shmem2_get_job_shmem2_by_id(job, shmem2_id, &shmem2); if (PMIX_UNLIKELY(rc != PMIX_SUCCESS)) { PMIX_ERROR_LOG(rc); goto out; } // Create a shared-memory segment backing store at the given path. rc = pmix_shmem_segment_create( shmem2, real_segsize, segment_path ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } // Attach to the shared-memory segment. rc = shmem2_attach(job, shmem2_id, (uintptr_t)base_addr); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } // Fix-up backing file permission. rc = shmem2_segment_fix_perms(job, shmem2); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } out: if (PMIX_SUCCESS == rc) { // I created it, so note that it is mine. pmix_gds_shmem2_set_status( job, shmem2_id, PMIX_GDS_SHMEM2_MINE ); } return rc; } static pmix_status_t module_init( pmix_info_t info[], size_t ninfo ) { PMIX_HIDE_UNUSED_PARAMS(info, ninfo); PMIX_GDS_SHMEM2_VVOUT_HERE(); PMIX_CONSTRUCT(&pmix_mca_gds_shmem2_component.jobs, pmix_list_t); PMIX_CONSTRUCT(&pmix_mca_gds_shmem2_component.sessions, pmix_list_t); return PMIX_SUCCESS; } static void module_finalize(void) { PMIX_GDS_SHMEM2_VVOUT_HERE(); PMIX_LIST_DESTRUCT(&pmix_mca_gds_shmem2_component.sessions); PMIX_LIST_DESTRUCT(&pmix_mca_gds_shmem2_component.jobs); } static pmix_status_t assign_module( pmix_info_t *info, size_t ninfo, int *priority ) { static const int max_priority = 100; *priority = PMIX_GDS_SHMEM2_DEFAULT_PRIORITY; // The incoming info always overrides anything in the // environment as it is set by the application itself. bool specified = false; for (size_t n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_GDS_MODULE)) { char **options = NULL; specified = true; // They specified who they want. options = PMIx_Argv_split(info[n].value.data.string, ','); for (size_t m = 0; NULL != options[m]; m++) { if (0 == strcmp(options[m], PMIX_GDS_SHMEM2_NAME)) { // They specifically asked for us. *priority = max_priority; break; } } PMIx_Argv_free(options); break; } } // If they don't want us, then disqualify ourselves. if (specified && *priority != max_priority) { *priority = 0; } return PMIX_SUCCESS; } static pmix_status_t server_cache_job_info( struct pmix_namespace_t *ns, pmix_info_t info[], size_t ninfo ) { PMIX_HIDE_UNUSED_PARAMS(ns, info, ninfo); PMIX_GDS_SHMEM2_VVOUT_HERE(); // We don't support this operation. return PMIX_ERR_NOT_SUPPORTED; } /** * */ static pmix_status_t prepare_shmem2_stores_for_local_job_data( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_packed_local_job_info_t *pji ) { pmix_status_t rc = PMIX_SUCCESS; static const float fluff = 3.0; const size_t kvsize = (sizeof(pmix_kval_t) + sizeof(pmix_value_t)); // Initial hash table size. const size_t htsize = pji->hash_table_size; // Calculate a rough estimate on the amount of storage required to store the // values associated with the pmix_gds_shmem2_shared_job_data_t. Err on the // side of overestimation. size_t seg_size = sizeof(*job->smdata); // We need to store a hash table in the shared-memory segment, so calculate // a rough estimate on the memory required for its storage. seg_size += sizeof(pmix_hash_table_t); seg_size += htsize * pmix_hash_table_sizeof_hash_element(); // Add a little extra to compensate for the value storage requirements. Here // we add an additional storage space for each entry. seg_size += htsize * kvsize; // Finally add the data size contribution, plus a little extra. seg_size += pji->packed_size; // Include some extra fluff that empirically seems reasonable. seg_size *= fluff; // Adjust (increase or decrease) segment size by the given parameter size. seg_size *= pmix_gds_shmem2_segment_size_multiplier; // Create and attach to the shared-memory segment associated with this job. // This will be the backing store for data associated with static, read-only // data shared between the server and its clients. rc = shmem2_segment_create_and_attach( job, PMIX_GDS_SHMEM2_JOB_ID, "jobdata", seg_size ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } // Do the same for the job's session information. Note that we recycle the // segment size calculated above because we know that it will be at least as // big as we need for this session information. const char *session_name = get_shmem2_session_name(pji->session_id); if (PMIX_UNLIKELY(!session_name)) { rc = PMIX_ERROR; PMIX_ERROR_LOG(rc); return rc; } rc = shmem2_segment_create_and_attach( job, PMIX_GDS_SHMEM2_SESSION_ID, session_name, seg_size ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } // Construct shared-memory data structures for job and session. rc = job_smdata_construct(job, htsize); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } rc = session_smdata_construct(job, pji->session_id); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } return rc; } static inline pmix_status_t pack_shmem2_connection_info( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, pmix_peer_t *peer, pmix_buffer_t *buffer ) { pmix_status_t rc = PMIX_SUCCESS; PMIX_GDS_SHMEM2_VVOUT( "%s:%s for peer (ID=%d) namespace=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), peer->info->peerid, job->nspace_id ); pmix_shmem_t *shmem2; rc = pmix_gds_shmem2_get_job_shmem2_by_id( job, shmem2_id, &shmem2 ); if (PMIX_UNLIKELY(rc != PMIX_SUCCESS)) { PMIX_ERROR_LOG(rc); return rc; } pmix_kval_t kv; do { // Pack the namespace name. PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_SEG_NSID_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_STRING; kv.value->data.string = strdup(job->nspace_id); PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); // Pack the shmem2 ID as string. PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_SEG_SMID_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_STRING; int nw = asprintf(&kv.value->data.string, "%zd", (size_t)shmem2_id); if (PMIX_UNLIKELY(nw == -1)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); // Pack the backing file path. PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_SEG_PATH_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_STRING; kv.value->data.string = strdup(shmem2->backing_path); PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); // Pack attach size to shared-memory segment. PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_SEG_SIZE_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_STRING; nw = asprintf(&kv.value->data.string, "%zx", shmem2->size); if (PMIX_UNLIKELY(nw == -1)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); // Pack the addresses used to attach to the shared-memory segment. PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_SEG_HADR_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_STRING; nw = asprintf( &kv.value->data.string, "%zx", (size_t)shmem2->hdr_address ); if (PMIX_UNLIKELY(nw == -1)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } } while (false); PMIX_DESTRUCT(&kv); return rc; } static inline pmix_status_t pack_server_keyindex_description( pmix_peer_t *peer, pmix_buffer_t *buffer, char **description ) { pmix_status_t rc = PMIX_SUCCESS; // Nothing to pack. if (NULL == description) { return PMIX_SUCCESS; } pmix_kval_t kv; PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_KIDX_DESCRIPTION_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_STRING; kv.value->data.string = NULL; // Encode the char** as a new-line-delimited string. for (int i = 0; NULL != description[i]; ++i) { int nw = -1; if (0 == i) { nw = asprintf(&kv.value->data.string, "%s", description[i]); } else { char *curs = kv.value->data.string; nw = asprintf(&kv.value->data.string, "%s\n%s", curs, description[i]); free(curs); } if (PMIX_UNLIKELY(nw == -1)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } } if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } out: PMIX_DESTRUCT(&kv); return rc; } static inline pmix_status_t pack_server_keyindex_info( pmix_gds_shmem2_job_t *job, pmix_peer_t *peer, pmix_buffer_t *buffer ) { pmix_status_t rc = PMIX_SUCCESS; PMIX_GDS_SHMEM2_VVOUT( "%s:%s for peer (ID=%d) namespace=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), peer->info->peerid, job->nspace_id ); pmix_kval_t kv; do { // First, pack the namespace name. PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_KIDX_NSID_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_STRING; kv.value->data.string = strdup(job->nspace_id); PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); // Pack the size of the server's keyindex table. PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_KIDX_TAB_SIZE_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_UINT32; kv.value->data.uint32 = (uint32_t)PMIX_INDEX_BOUNDARY; PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); for (int i = 0; i < PMIX_INDEX_BOUNDARY; ++i) { const pmix_regattr_input_t *p = &pmix_dictionary[i]; PMIX_GDS_SHMEM2_VVVOUT( "%s:keyindex=(index=%zd, type=%zd, name=%s string=%s, description=%s)", __func__, (size_t)p->index, (size_t)p->type, p->name ? p->name : "NULL", p->string ? p->string : "NULL", // For debug, only print the first element, if present. (p->description && p->description[0]) ? p->description[0] : "NULL" ); // Pack index PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_KIDX_INDEX_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_UINT32; assert(sizeof(kv.value->data.uint32) == sizeof(p->index)); kv.value->data.uint32 = p->index; PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); // Pack type PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_KIDX_TYPE_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_UINT16; assert(sizeof(kv.value->data.uint16) == sizeof(p->type)); kv.value->data.uint16 = p->type; PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); // Pack name, if available. if (p->name) { PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_KIDX_NAME_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_STRING; kv.value->data.string = strdup(p->name); PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); } // Pack string, if available. if (p->string) { PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_KIDX_STRING_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_STRING; kv.value->data.string = strdup(p->string); PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); } // Pack description. rc = pack_server_keyindex_description(peer, buffer, p->description); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } // Last mark the element boundary. PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = strdup(SHMEM2_KIDX_ELEM_DONE_KEY); kv.value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); kv.value->type = PMIX_UINT8; kv.value->data.uint8 = 1; PMIX_BFROPS_PACK(rc, peer, buffer, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kv); } } while (false); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kv); } return rc; } /** * Emits the contents of an pmix_gds_shmem2_unpacked_seg_blob_t. */ static inline void vout_unpacked_seg_blob( pmix_gds_shmem2_unpacked_seg_blob_t *usb, const char *called_by ) { #if (PMIX_ENABLE_DEBUG == 0) PMIX_HIDE_UNUSED_PARAMS(usb, called_by); #endif PMIX_GDS_SHMEM2_VVOUT( "%s: " SHMEM2_SEG_NSID_KEY "=%s " SHMEM2_SEG_SMID_KEY "=%u " SHMEM2_SEG_PATH_KEY "=%s " SHMEM2_SEG_SIZE_KEY "=%zd " SHMEM2_SEG_HADR_KEY "=0x%zx", called_by, usb->nsid, (unsigned)usb->smid, usb->seg_path, usb->seg_size, usb->seg_hadr ); } /** * Sets shared-memory connection information from a pmix_kval_t by unpacking the * blob and saving the values for the caller. If successful, returns relevant * data associated with the unpacked data. */ static inline pmix_status_t unpack_shmem2_connection_info( pmix_kval_t *kvbo, pmix_gds_shmem2_unpacked_seg_blob_t *usb ) { pmix_status_t rc = PMIX_SUCCESS; // Make sure this is the expected type. if (PMIX_UNLIKELY(PMIX_BYTE_OBJECT != kvbo->value->type)) { rc = PMIX_ERR_TYPE_MISMATCH; PMIX_ERROR_LOG(rc); return rc; } pmix_buffer_t buffer; PMIX_CONSTRUCT(&buffer, pmix_buffer_t); PMIX_LOAD_BUFFER( pmix_client_globals.myserver, &buffer, kvbo->value->data.bo.bytes, kvbo->value->data.bo.size ); pmix_kval_t kv; while (true) { PMIX_CONSTRUCT(&kv, pmix_kval_t); int32_t count = 1; PMIX_BFROPS_UNPACK( rc, pmix_client_globals.myserver, &buffer, &kv, &count, PMIX_KVAL ); if (PMIX_SUCCESS != rc) { break; } const char *const val = kv.value->data.string; if (PMIX_CHECK_KEY(&kv, SHMEM2_SEG_NSID_KEY)) { int nw = asprintf(&usb->nsid, "%s", val); if (PMIX_UNLIKELY(nw == -1)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(&kv, SHMEM2_SEG_SMID_KEY)) { size_t st_shmem2_id; rc = strtost(val, 10, &st_shmem2_id); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } usb->smid = (pmix_gds_shmem2_job_shmem2_id_t)st_shmem2_id; } else if (PMIX_CHECK_KEY(&kv, SHMEM2_SEG_PATH_KEY)) { int nw = asprintf(&usb->seg_path, "%s", val); if (PMIX_UNLIKELY(nw == -1)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(&kv, SHMEM2_SEG_SIZE_KEY)) { rc = strtost(val, 16, &usb->seg_size); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(&kv, SHMEM2_SEG_HADR_KEY)) { rc = strtost(val, 16, &usb->seg_hadr); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } } else { rc = PMIX_ERR_BAD_PARAM; PMIX_ERROR_LOG(rc); break; } // Done with this one. PMIX_DESTRUCT(&kv); } // Catch last kval. PMIX_DESTRUCT(&kv); PMIX_DESTRUCT(&buffer); if (PMIX_UNLIKELY(PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc)) { PMIX_ERROR_LOG(rc); rc = PMIX_ERR_UNPACK_FAILURE; PMIX_ERROR_LOG(rc); } else { vout_unpacked_seg_blob(usb, __func__); rc = PMIX_SUCCESS; } return rc; } static inline void regattr_list_free( pmix_regattr_input_t *ra, int nra ) { if (NULL == ra) return; for (int i = 0; i < nra; ++i) { free(ra[i].name); free(ra[i].string); PMIx_Argv_free(ra[i].description); } free(ra); } // keyindex = dictionary from the server // nkeyindex = number of entries in that dictionary static pmix_status_t client_update_global_keyindex_if_necessary( char *nspace_name, pmix_regattr_input_t *keyindex, int nkeyindex ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); pmix_status_t rc; int i, m; pmix_regattr_input_t *ra, *rb; pmix_keyindex_t tmpindex; bool found; // Do we need to update? pmix_gds_shmem2_job_t *job; rc = pmix_gds_shmem2_get_job_tracker(nspace_name, true, &job); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } if (job->client_keyindex_fixup_done) { // Already done! return PMIX_SUCCESS; } // We can _never_ assume that the indices in our dictionary // match the ones in the server's dictionary. Even if the // number of entries is the same, there is no guarantee that // they are in the same order - and thus, the index of a // particular entry can be different, causing errors on our // side. Likewise, even if we have more entries than they do, // there is no guarantee that their entries are in the same // order as ours. So we have to rebuild the dictionary to // match what they have - and if we have additional entries, // then we add them back at the end of the new dictionary. // Get a fresh temp index. PMIX_CONSTRUCT(&tmpindex, pmix_keyindex_t); tmpindex.next_id = 0; // Add the server's keys. for (i = 0; i < nkeyindex; ++i) { PMIX_REGATTR_INPUT_NEW(ra, keyindex[i].index, keyindex[i].name, keyindex[i].string, keyindex[i].type, keyindex[i].description); if (PMIX_UNLIKELY(NULL == ra)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); return rc; } pmix_pointer_array_set_item(tmpindex.table, (int)tmpindex.next_id, ra); ra->index = tmpindex.next_id; tmpindex.next_id += 1; PMIX_GDS_SHMEM2_VVVOUT( "%s:keyindex=(index=%zd, type=%zd, name=%s string=%s, description=%s)", __func__, (size_t)ra->index, (size_t)ra->type, ra->name ? ra->name : "NULL", ra->string ? ra->string : "NULL", // For debug, only print the first element, if present. (ra->description && ra->description[0]) ? ra->description[0] : "NULL" ); } // now cycle thru our dictionary, adding anything missing to the // new keyindex - some definitions are added to the dictionary // but are internally defined, so they might not be in the keyindex // just yet for (i = 0; i < PMIX_INDEX_BOUNDARY; ++i) { ra = (pmix_regattr_input_t*)&pmix_dictionary[i]; // see if this entry is already present in the new keyindex found = false; for (m=0; m < tmpindex.table->size; m++) { rb = (pmix_regattr_input_t*)pmix_pointer_array_get_item(tmpindex.table, m); if (NULL == rb) { // left-justified break; } if (0 == strcmp(ra->name, rb->name)) { found = true; break; } } if (found) { // ignore this entry continue; } // not found, so we need to add it back PMIX_REGATTR_INPUT_NEW(rb, ra->index, ra->name, ra->string, ra->type, ra->description); if (PMIX_UNLIKELY(NULL == rb)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); return rc; } pmix_pointer_array_set_item(tmpindex.table, (int)tmpindex.next_id, rb); rb->index = tmpindex.next_id; tmpindex.next_id += 1; PMIX_GDS_SHMEM2_VVVOUT( "%s:keyindex=(index=%zd, type=%zd, name=%s string=%s, description=%s)", __func__, (size_t)ra->index, (size_t)ra->type, ra->name ? ra->name : "NULL", ra->string ? ra->string : "NULL", // For debug, only print the first element, if present. (ra->description && ra->description[0]) ? ra->description[0] : "NULL" ); } // now cycle thru our keyindex, adding anything missing to the // new keyindex for (i = 0; i < pmix_globals.keyindex.table->size; ++i) { ra = (pmix_regattr_input_t*)pmix_pointer_array_get_item(pmix_globals.keyindex.table, i); if (NULL == ra) { // the array is left-justified break; } // see if this entry is already present in the new keyindex found = false; for (m=0; m < tmpindex.table->size; m++) { rb = (pmix_regattr_input_t*)pmix_pointer_array_get_item(tmpindex.table, m); if (NULL == rb) { // left-justified break; } if (0 == strcmp(ra->name, rb->name)) { found = true; break; } } if (found) { // ignore this entry continue; } // not found, so we need to add it back // to save operations, we remove the entry from the global keyindex // and add it to the new index pmix_pointer_array_set_item(pmix_globals.keyindex.table, i, NULL); pmix_pointer_array_set_item(tmpindex.table, (int)tmpindex.next_id, ra); ra->index = tmpindex.next_id; tmpindex.next_id += 1; PMIX_GDS_SHMEM2_VVVOUT( "%s:keyindex=(index=%zd, type=%zd, name=%s string=%s, description=%s)", __func__, (size_t)ra->index, (size_t)ra->type, ra->name ? ra->name : "NULL", ra->string ? ra->string : "NULL", // For debug, only print the first element, if present. (ra->description && ra->description[0]) ? ra->description[0] : "NULL" ); } // now replace the global keyindex with this new one PMIX_DESTRUCT(&pmix_globals.keyindex); PMIX_CONSTRUCT(&pmix_globals.keyindex, pmix_keyindex_t); pmix_globals.keyindex.next_id = 0; for (i=0; i < tmpindex.table->size; i++) { rb = (pmix_regattr_input_t*)pmix_pointer_array_get_item(tmpindex.table, i); if (NULL == rb) { // array is left-justified break; } pmix_pointer_array_set_item(tmpindex.table, i, NULL); pmix_pointer_array_set_item(pmix_globals.keyindex.table, rb->index, rb); pmix_globals.keyindex.next_id++; } PMIX_DESTRUCT(&tmpindex); job->client_keyindex_fixup_done = true; return PMIX_SUCCESS; } static inline pmix_status_t unpack_srv_kindx_info( pmix_kval_t *kvbo ) { pmix_status_t rc = PMIX_SUCCESS; int tabsize = 0, tabindex = 0; pmix_regattr_input_t *tmpsrvdict = NULL; char *nspace_name = NULL; // Make sure this is the expected type. if (PMIX_UNLIKELY(PMIX_BYTE_OBJECT != kvbo->value->type)) { rc = PMIX_ERR_TYPE_MISMATCH; PMIX_ERROR_LOG(rc); return rc; } pmix_buffer_t buffer; PMIX_CONSTRUCT(&buffer, pmix_buffer_t); PMIX_LOAD_BUFFER( pmix_client_globals.myserver, &buffer, kvbo->value->data.bo.bytes, kvbo->value->data.bo.size ); pmix_kval_t kv; while (true) { PMIX_CONSTRUCT(&kv, pmix_kval_t); int32_t count = 1; PMIX_BFROPS_UNPACK( rc, pmix_client_globals.myserver, &buffer, &kv, &count, PMIX_KVAL ); if (PMIX_SUCCESS != rc) { break; } if (PMIX_CHECK_KEY(&kv, SHMEM2_KIDX_NSID_KEY)) { int nw = asprintf(&nspace_name, "%s", kv.value->data.string); if (PMIX_UNLIKELY(nw == -1)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(&kv, SHMEM2_KIDX_TAB_SIZE_KEY)) { // Create a temporary dict to unpack into - this is the // size of the server's dictionary assert(kv.value->type == PMIX_UINT32); tabsize = kv.value->data.uint32; if (NULL == tmpsrvdict) { tmpsrvdict = calloc(tabsize, sizeof(*tmpsrvdict)); } if (NULL == tmpsrvdict) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(&kv, SHMEM2_KIDX_INDEX_KEY) && tmpsrvdict) { tmpsrvdict[tabindex].index = kv.value->data.uint32; } else if (PMIX_CHECK_KEY(&kv, SHMEM2_KIDX_TYPE_KEY) && tmpsrvdict) { tmpsrvdict[tabindex].type = (pmix_data_type_t)kv.value->data.uint16; } else if (PMIX_CHECK_KEY(&kv, SHMEM2_KIDX_NAME_KEY) && tmpsrvdict) { const int nw = asprintf( &tmpsrvdict[tabindex].name, "%s", kv.value->data.string ); if (PMIX_UNLIKELY(nw == -1)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(&kv, SHMEM2_KIDX_STRING_KEY) && tmpsrvdict) { const int nw = asprintf( &tmpsrvdict[tabindex].string, "%s", kv.value->data.string ); if (PMIX_UNLIKELY(nw == -1)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(&kv, SHMEM2_KIDX_DESCRIPTION_KEY) && tmpsrvdict) { tmpsrvdict[tabindex].description = PMIx_Argv_split( kv.value->data.string, '\n' ); if (NULL == tmpsrvdict[tabindex].description) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(&kv, SHMEM2_KIDX_ELEM_DONE_KEY) && tmpsrvdict) { // Done with this element, so on to the next one. tabindex += 1; } else { rc = PMIX_ERR_BAD_PARAM; PMIX_ERROR_LOG(rc); break; } // Done with this one. PMIX_DESTRUCT(&kv); } // Catch last kval. PMIX_DESTRUCT(&kv); PMIX_DESTRUCT(&buffer); if (PMIX_UNLIKELY(PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc)) { PMIX_ERROR_LOG(rc); rc = PMIX_ERR_UNPACK_FAILURE; PMIX_ERROR_LOG(rc); } else if (NULL == nspace_name) { // no namespace was given PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); rc = PMIX_ERR_BAD_PARAM; } else { // Last step is to update our view of the // PMIx attributes, if we haven't already. rc = client_update_global_keyindex_if_necessary( nspace_name, tmpsrvdict, tabsize ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } } // No longer needed. regattr_list_free(tmpsrvdict, tabsize); if (NULL != nspace_name) { free(nspace_name); } return rc; } /** * Fetches a complete copy of the job-level information. */ static pmix_status_t fetch_local_job_data( const char *nspace, pmix_cb_t *job_cb ) { pmix_status_t rc = PMIX_SUCCESS; pmix_proc_t wildcard; PMIX_LOAD_PROCID(&wildcard, nspace, PMIX_RANK_WILDCARD); job_cb->key = NULL; job_cb->proc = &wildcard; job_cb->copy = true; job_cb->scope = PMIX_LOCAL; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, job_cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } return rc; } /** * Internally the hash table can do some interesting sizing calculations, so we * just construct a temporary one with the number of expected elements, then * query it for its actual capacity. */ static inline size_t get_actual_hashtab_capacity( size_t num_elements ) { pmix_hash_table_t tmp; PMIX_CONSTRUCT(&tmp, pmix_hash_table_t); pmix_hash_table_init(&tmp, num_elements); // Grab the actual capacity. const size_t result = tmp.ht_capacity; PMIX_DESTRUCT(&tmp); return result; } static inline pmix_status_t get_local_job_data_info( pmix_cb_t *job_cb, pmix_gds_shmem2_packed_local_job_info_t *pji ) { pmix_status_t rc = PMIX_SUCCESS; size_t nhtentries = 0; uint32_t sid = UINT32_MAX; pmix_buffer_t data; PMIX_CONSTRUCT(&data, pmix_buffer_t); pmix_kval_t *kvi; PMIX_LIST_FOREACH (kvi, &job_cb->kvs, pmix_kval_t) { // Calculate some statistics so we can make an educated estimate on the // size of structures we need for our backing store. if (PMIX_DATA_ARRAY == kvi->value->type) { // PMIX_PROC_DATA is stored in the hash table. if (PMIX_CHECK_KEY(kvi, PMIX_PROC_DATA)) { nhtentries += kvi->value->data.darray->size; } // See if this is the job's session ID. If so, capture it. pmix_info_t *info = (pmix_info_t *)kvi->value->data.darray->array; if (PMIX_CHECK_KEY(&info[0], PMIX_SESSION_ID)) { rc = PMIx_Value_get_number(&info[0].value, &sid, PMIX_UINT32); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } } } // Just a key/value pair, so they will likely go into the hash table. else { nhtentries += 1; } PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &data, kvi, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } } pji->session_id = sid; pji->packed_size = data.bytes_used; pji->hash_table_size = get_actual_hashtab_capacity(nhtentries); out: PMIX_DESTRUCT(&data); return rc; } static inline pmix_status_t pack_shmem2_seg_blob( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, struct pmix_peer_t *peer, pmix_buffer_t *reply ) { pmix_status_t rc = PMIX_SUCCESS; // Only pack connection info that is ready for use. Otherwise, // it's bogus data that we shouldn't be sharing it with our clients. const bool ready_for_use = pmix_gds_shmem2_has_status( job, shmem2_id, PMIX_GDS_SHMEM2_READY_FOR_USE ); if (!ready_for_use) { return rc; } pmix_buffer_t buff; do { PMIX_CONSTRUCT(&buff, pmix_buffer_t); rc = pack_shmem2_connection_info( job, shmem2_id, peer, &buff ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } pmix_value_t blob = { .type = PMIX_BYTE_OBJECT }; pmix_kval_t kv = { .key = SHMEM2_SEG_BLOB_KEY, .value = &blob }; PMIX_UNLOAD_BUFFER(&buff, blob.data.bo.bytes, blob.data.bo.size); PMIX_BFROPS_PACK(rc, peer, reply, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } PMIX_VALUE_DESTRUCT(&blob); } while (false); PMIX_DESTRUCT(&buff); return rc; } static inline pmix_status_t pack_server_keyindex_blob( pmix_gds_shmem2_job_t *job, struct pmix_peer_t *peer, pmix_buffer_t *reply ) { pmix_status_t rc = PMIX_SUCCESS; pmix_buffer_t buff; do { PMIX_CONSTRUCT(&buff, pmix_buffer_t); rc = pack_server_keyindex_info(job, peer, &buff); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } pmix_value_t blob = { .type = PMIX_BYTE_OBJECT }; pmix_kval_t kv = { .key = SHMEM2_KIDX_KEY, .value = &blob }; PMIX_UNLOAD_BUFFER(&buff, blob.data.bo.bytes, blob.data.bo.size); PMIX_BFROPS_PACK(rc, peer, reply, &kv, 1, PMIX_KVAL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } PMIX_VALUE_DESTRUCT(&blob); } while (false); PMIX_DESTRUCT(&buff); return rc; } static pmix_status_t cache_connection_info_for_job_shmem2( pmix_gds_shmem2_job_t *job ) { pmix_status_t rc = PMIX_SUCCESS; pmix_peer_t *const me = pmix_globals.mypeer; // Create a new buffer that will store the // job's shared-memory connection info. job->conni = PMIX_NEW(pmix_buffer_t); if (PMIX_UNLIKELY(!job->conni)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); return rc; } // Pack the payload for delivery. Note that the message we are going to send // is simply the shared memory connection information that is shared among // clients on a single node. // Start with the namespace name. PMIX_BFROPS_PACK(rc, me, job->conni, &job->nspace_id, 1, PMIX_STRING); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } // Pack the shared-memory segment information. // First for the job. rc = pack_shmem2_seg_blob( job, PMIX_GDS_SHMEM2_JOB_ID, me, job->conni ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } // Then for the session info. rc = pack_shmem2_seg_blob( job, PMIX_GDS_SHMEM2_SESSION_ID, me, job->conni ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } // PMIx standard attribute index mappings might differ between client/server // versions, so pack the server's mappings and share them with its clients. // Then, clients will unpack those data and update their view of the // standard attributes, so both client and servers start from the same view. rc = pack_server_keyindex_blob(job, me, job->conni); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } out: if (PMIX_SUCCESS != rc) { PMIX_RELEASE(job->conni); } return rc; } static pmix_status_t server_register_new_job_info( pmix_gds_shmem2_job_t *job ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); pmix_status_t rc = PMIX_SUCCESS; // Ask for a complete copy of the job-level information. pmix_cb_t job_cb; PMIX_CONSTRUCT(&job_cb, pmix_cb_t); pmix_gds_shmem2_packed_local_job_info_t pji; PMIX_CONSTRUCT(&pji, pmix_gds_shmem2_packed_local_job_info_t); rc = fetch_local_job_data(job->nspace_id, &job_cb); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } // Pack the data so we can see how large it is. This will help inform how // large to make the shared-memory segments associated with these data. rc = get_local_job_data_info(&job_cb, &pji); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } // Get the shared-memory segments ready for job data. rc = prepare_shmem2_stores_for_local_job_data(job, &pji); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } // Store fetched data into a shared-memory segment. rc = pmix_gds_shmem2_store_local_job_data_in_shmem2(job, &job_cb.kvs); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } out: PMIX_DESTRUCT(&job_cb); PMIX_DESTRUCT(&pji); return rc; } /** * */ static pmix_status_t server_register_job_info( struct pmix_peer_t *peer_struct, pmix_buffer_t *reply ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); pmix_status_t rc = PMIX_SUCCESS; pmix_peer_t *const peer = (pmix_peer_t *)peer_struct; if (!PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { // This function is only available on servers. PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_SUPPORTED; } // Create the job tracker for this peer's nspace. pmix_gds_shmem2_job_t *job; rc = pmix_gds_shmem2_get_job_tracker(peer->nptr->nspace, true, &job); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } do { // First see if we already have processed this // data so we don't waste time doing it again. if (job->conni) { break; } // We don't, so register the new job info. PMIX_GDS_SHMEM2_VVOUT( "%s: %s registering new job info for namespace=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), job->nspace_id ); rc = server_register_new_job_info(job); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } rc = cache_connection_info_for_job_shmem2(job); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } } while (false); if (PMIX_LIKELY(PMIX_SUCCESS == rc)) { // Copy reply over to send the connection info to the given peer. PMIX_BFROPS_COPY_PAYLOAD(rc, peer, reply, job->conni); } else { PMIX_ERROR_LOG(rc); } return rc; } static pmix_status_t unpack_srv_kindx_blob_and_update_if_necessary( pmix_kval_t *kvbo ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); pmix_status_t rc = unpack_srv_kindx_info(kvbo); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } return rc; } static pmix_status_t unpack_shmem2_seg_blob_and_attach_if_necessary( pmix_kval_t *kvbo ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); pmix_status_t rc = PMIX_SUCCESS; pmix_gds_shmem2_unpacked_seg_blob_t usb; PMIX_CONSTRUCT(&usb, pmix_gds_shmem2_unpacked_seg_blob_t); do { rc = unpack_shmem2_connection_info(kvbo, &usb); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } // Get the associated job tracker. pmix_gds_shmem2_job_t *job; rc = pmix_gds_shmem2_get_job_tracker(usb.nsid, true, &job); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } // Make sure we aren't already attached to the given shmem2. if (pmix_gds_shmem2_has_status(job, usb.smid, PMIX_GDS_SHMEM2_ATTACHED)) { break; } // Looks like we have to attach and initialize it. rc = shmem2_segment_attach_and_init(job, &usb); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { break; } } while (false); PMIX_DESTRUCT(&usb); return rc; } static pmix_status_t client_connect_to_shmem2_from_buffi( pmix_buffer_t *buff ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); pmix_status_t rc = PMIX_SUCCESS; pmix_kval_t kval; while (true) { PMIX_CONSTRUCT(&kval, pmix_kval_t); int32_t nvals = 1; PMIX_BFROPS_UNPACK( rc, pmix_client_globals.myserver, buff, &kval, &nvals , PMIX_KVAL ); if (PMIX_SUCCESS != rc) { break; } if (PMIX_CHECK_KEY(&kval, SHMEM2_SEG_BLOB_KEY)) { rc = unpack_shmem2_seg_blob_and_attach_if_necessary(&kval); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { break; } } else if (PMIX_CHECK_KEY(&kval, SHMEM2_KIDX_KEY)) { rc = unpack_srv_kindx_blob_and_update_if_necessary(&kval); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } } else { PMIX_GDS_SHMEM2_VOUT( "%s:ERROR unexpected key=%s", __func__, kval.key ); rc = PMIX_ERR_BAD_PARAM; PMIX_ERROR_LOG(rc); break; } PMIX_DESTRUCT(&kval); }; // Release the leftover kval. PMIX_DESTRUCT(&kval); if (PMIX_UNLIKELY(PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc)) { rc = PMIX_ERR_UNPACK_FAILURE; return rc; } return PMIX_SUCCESS; } static pmix_status_t store_job_info( const char *nspace, pmix_buffer_t *buff ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); PMIX_GDS_SHMEM2_VOUT( "%s:%s for namespace=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), nspace ); // Done. Before this point the server should have populated the // shared-memory segment with the relevant data. return client_connect_to_shmem2_from_buffi(buff); } /** * Returns size required to store modex data. */ static pmix_gds_shmem2_modex_info_t get_modex_sizing_data(const pmix_buffer_t *buff) { const size_t kval_size = sizeof(pmix_kval_t); // The default values if not provided with modex size info. More fluff than // in other places because this calculation is more imprecise. In many ways // this is okay because mmap() implements demand paging. float fluff = 5.0; // Multiplier to fudge compression factor. zlib max compression is 5:1. size_t segment_size = buff->bytes_used * 5; // Get an estimate on the number of kvals we need to store. const size_t nkvals = (segment_size / (float)kval_size) + kval_size; // Get the required hash table size based on number of kvals. const size_t nhtelems = get_actual_hashtab_capacity(nkvals); // We also need storage space for the hash table and its elements. segment_size += sizeof(pmix_hash_table_t); segment_size += nhtelems * pmix_hash_table_sizeof_hash_element(); // Include some extra fluff that empirically seems reasonable. segment_size *= fluff; // Adjust (increase or decrease) segment size by the given parameter size. segment_size *= pmix_gds_shmem2_segment_size_multiplier; pmix_gds_shmem2_modex_info_t result = { .size = segment_size, .num_ht_elements = nhtelems }; return result; } /** * This gets called for each process participating in the modex. */ static pmix_status_t server_store_modex_cb(pmix_proc_t *proc, pmix_buffer_t *pbkt) { pmix_status_t rc = PMIX_SUCCESS; int32_t cnt; pmix_kval_t kv; pmix_gds_shmem2_job_t *job; rc = pmix_gds_shmem2_get_job_tracker(proc->nspace, false, &job); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } if (NULL == pbkt) { // Segment is ready for use. pmix_gds_shmem2_set_status( job, PMIX_GDS_SHMEM2_MODEX_ID, PMIX_GDS_SHMEM2_READY_FOR_USE ); return PMIX_SUCCESS; } PMIX_GDS_SHMEM2_VOUT( "%s:%s for namespace=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), proc->nspace ); const bool attached = pmix_gds_shmem2_has_status( job, PMIX_GDS_SHMEM2_MODEX_ID, PMIX_GDS_SHMEM2_ATTACHED ); if (!attached) { // Get the global packed buffer size from ctx. pmix_gds_shmem2_modex_info_t minfo = get_modex_sizing_data(pbkt); // Create and attach to the shared-memory // segment that will back these data. rc = shmem2_segment_create_and_attach( job, PMIX_GDS_SHMEM2_MODEX_ID, "modexdata", minfo.size ); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } rc = modex_smdata_construct(job, minfo.num_ht_elements); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } pmix_hash_table_t *const ht = job->smmodex->hashtab; // This is data returned via the PMIx_Fence call when data collection was // requested, so it only contains REMOTE/GLOBAL data. The byte object // contains the rank followed by pmix_kval_ts. // Unpack the values until we hit the end of the buffer. while (true) { // it is okay to use a static variable here and construct it // because we are NOT going to actually store the variable // anywhere - the hash_store function COPIES it into an // appropriately allocated object PMIX_CONSTRUCT(&kv, pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, pbkt, &kv, &cnt, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&kv); break; } const pmix_rank_t rank = proc->rank; // If the rank is undefined, then we store it on the remote table of // rank=0 as we know that rank must always exist. if (PMIX_CHECK_KEY(&kv, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_shmem2_store_qualified( ht, (PMIX_RANK_UNDEF == rank) ? 0 : rank, kv.value ); } else { rc = pmix_hash_store( ht, (PMIX_RANK_UNDEF == rank) ? 0 : rank, &kv, NULL, 0, NULL ); } if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kv); break; } PMIX_DESTRUCT(&kv); } if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); } return rc; } /** * This function is only called by the PMIx server when its host has received * data from some other peer. It therefore always contains data solely from * remote procs, and we shall store it accordingly. */ static pmix_status_t server_store_modex(pmix_buffer_t *buff, void *cbdata) { PMIX_GDS_SHMEM2_VVOUT_HERE(); PMIX_GDS_SHMEM2_VOUT( "%s:%s buff_size=%zd", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), buff->bytes_used ); return pmix_gds_base_store_modex(buff, server_store_modex_cb, cbdata); } static pmix_status_t server_setup_fork( const pmix_proc_t *peer, char ***env ) { PMIX_HIDE_UNUSED_PARAMS(peer, env); PMIX_GDS_SHMEM2_VVOUT_HERE(); // Nothing to do here. return PMIX_SUCCESS; } static pmix_status_t server_add_nspace( const char *nspace, uint32_t nlocalprocs, pmix_info_t info[], size_t ninfo ) { PMIX_HIDE_UNUSED_PARAMS(nlocalprocs); PMIX_GDS_SHMEM2_VVOUT_HERE(); // Create a job tracker for this nspace. pmix_gds_shmem2_job_t *job; pmix_status_t rc = pmix_gds_shmem2_get_job_tracker(nspace, true, &job); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } for (size_t i = 0; i < ninfo; ++i) { if (PMIX_CHECK_KEY(&info[i], PMIX_USERID)) { const uid_t nuid = (uid_t)info[i].value.data.uint32; PMIX_GDS_SHMEM2_VOUT( "%s: updating nspace=%s UID from %zd to %zd", __func__, nspace, (size_t)job->uid, (size_t)nuid ); job->uid = nuid; job->chown = true; } else if (PMIX_CHECK_KEY(&info[i], PMIX_GRPID)) { const gid_t ngid = (gid_t)info[i].value.data.uint32; PMIX_GDS_SHMEM2_VOUT( "%s: updating nspace=%s GID from %zd to %zd", __func__, nspace, (size_t)job->gid, (size_t)ngid ); job->gid = ngid; job->chgrp = true; } } return rc; } static pmix_status_t del_nspace( const char *nspace ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); PMIX_GDS_SHMEM2_VOUT( "%s: %s for namespace=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), nspace ); pmix_gds_shmem2_job_t *ji; pmix_gds_shmem2_component_t *const component = &pmix_mca_gds_shmem2_component; PMIX_LIST_FOREACH (ji, &component->jobs, pmix_gds_shmem2_job_t) { if (0 == strcmp(nspace, ji->nspace_id)) { pmix_list_remove_item(&component->jobs, &ji->super); PMIX_RELEASE(ji); break; } } return PMIX_SUCCESS; } static pmix_status_t server_mark_modex_complete( struct pmix_peer_t *peer, pmix_list_t *nslist, pmix_buffer_t *reply ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); pmix_status_t rc = PMIX_SUCCESS; // Pack connection info for each ns in nslist. pmix_nspace_caddy_t *nsi; PMIX_LIST_FOREACH (nsi, nslist, pmix_nspace_caddy_t) { // false here because we should already know about the nspace. pmix_gds_shmem2_job_t *job; rc = pmix_gds_shmem2_get_job_tracker( nsi->ns->nspace, false, &job ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } // Pack modex info, if it is ready to be shared. rc = pack_shmem2_seg_blob( job, PMIX_GDS_SHMEM2_MODEX_ID, peer, reply ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } } return rc; } static pmix_status_t client_recv_modex_complete( pmix_buffer_t *buff ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); return client_connect_to_shmem2_from_buffi(buff); } pmix_gds_base_module_t pmix_shmem2_module = { .name = PMIX_GDS_SHMEM2_NAME, .is_tsafe = false, .init = module_init, .finalize = module_finalize, .assign_module = assign_module, .cache_job_info = server_cache_job_info, .register_job_info = server_register_job_info, .store_job_info = store_job_info, .store = NULL, .store_modex = server_store_modex, .fetch = pmix_gds_shmem2_fetch, .setup_fork = server_setup_fork, .add_nspace = server_add_nspace, .del_nspace = del_nspace, .assemb_kvs_req = NULL, .accept_kvs_resp = NULL, .mark_modex_complete = server_mark_modex_complete, .recv_modex_complete = client_recv_modex_complete }; /* * vim: ft=cpp ts=4 sts=4 sw=4 expandtab */ pmix-6.1.1~rc2/src/mca/gds/shmem2/gds_shmem2_utils.c0000664000175000017500000002010315203536752022404 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "gds_shmem2_utils.h" pmix_status_t pmix_gds_shmem2_get_job_tracker( const pmix_nspace_t nspace, bool create, pmix_gds_shmem2_job_t **job ) { pmix_status_t rc = PMIX_SUCCESS; // Try to find the tracker for this job. pmix_gds_shmem2_job_t *ti = NULL, *ijob = NULL; pmix_gds_shmem2_component_t *const component = &pmix_mca_gds_shmem2_component; PMIX_LIST_FOREACH (ti, &component->jobs, pmix_gds_shmem2_job_t) { if (0 == strcmp(nspace, ti->nspace_id)) { ijob = ti; break; } } // If we didn't find the requested target and we aren't asked // to create a new one, then the request cannot be fulfilled. if (!ijob && !create) { rc = PMIX_ERR_INVALID_NAMESPACE; goto out; } // Create one if not found and asked to create one. if (!ijob && create) { ijob = PMIX_NEW(pmix_gds_shmem2_job_t); if (PMIX_UNLIKELY(!ijob)) { rc = PMIX_ERR_NOMEM; goto out; } ijob->nspace_id = strdup(nspace); if (PMIX_UNLIKELY(!ijob->nspace_id)) { rc = PMIX_ERR_NOMEM; goto out; } // See if we already have this nspace in global namespaces. pmix_namespace_t *nsi = NULL, *inspace = NULL; PMIX_LIST_FOREACH (nsi, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(nsi->nspace, nspace)) { inspace = nsi; break; } } // If not, create one and update global namespace list. if (!inspace) { inspace = PMIX_NEW(pmix_namespace_t); if (PMIX_UNLIKELY(!inspace)) { rc = PMIX_ERR_NOMEM; goto out; } inspace->nspace = strdup(nspace); if (PMIX_UNLIKELY(!inspace->nspace)) { rc = PMIX_ERR_NOMEM; goto out; } pmix_list_append(&pmix_globals.nspaces, &inspace->super); } PMIX_RETAIN(inspace); ijob->nspace = inspace; // Add it to the list of jobs I'm supporting. pmix_list_append(&component->jobs, &ijob->super); } out: if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { if (ijob) { PMIX_RELEASE(ijob); ijob = NULL; } } *job = ijob; return rc; } pmix_gds_shmem2_session_t * pmix_gds_shmem2_get_session_tracker( pmix_gds_shmem2_job_t *job, uint32_t sid, bool create ) { // This is an error: we should always be given a job. if (PMIX_UNLIKELY(!job)) { return NULL; } pmix_tma_t *const tma = pmix_gds_shmem2_get_session_tma(job); pmix_gds_shmem2_component_t *const comp = &pmix_mca_gds_shmem2_component; if (NULL == job->session) { // No session has been assigned to this job. See // if the given ID has already been registered. pmix_gds_shmem2_session_t *si; PMIX_LIST_FOREACH(si, &comp->sessions, pmix_gds_shmem2_session_t) { if (si->smdata->id == sid) { // Found it. Point the job tracker at this session. PMIX_RETAIN(si); job->session = si; return si; } } // If it wasn't found, then create it if permitted. if (create) { si = PMIX_NEW(pmix_gds_shmem2_session_t, tma); si->smdata->id = sid; PMIX_RETAIN(si); job->session = si; pmix_list_append(&comp->sessions, &si->super); return si; } else { return NULL; } } // If the current session object is pointing to the default global session // and we were given a specific session ID, then update it. if (UINT32_MAX == job->session->smdata->id) { if (UINT32_MAX == sid) { // If the given SID is also UINT32_MAX, then we just add to it. return job->session; } // See if the given ID has already been registered. pmix_gds_shmem2_session_t *si; PMIX_LIST_FOREACH(si, &comp->sessions, pmix_gds_shmem2_session_t) { if (si->smdata->id == sid) { // Found it. Update the refcount on the current session object. PMIX_RELEASE(job->session); // Point the job tracker at the new place. PMIX_RETAIN(si); job->session = si; return si; } } // If it wasn't found, then create it if permitted. if (create) { si = PMIX_NEW(pmix_gds_shmem2_session_t, tma); si->smdata->id = sid; PMIX_RETAIN(si); job->session = si; pmix_list_append(&comp->sessions, &si->super); return si; } } else if (UINT32_MAX == sid) { // It's a wildcard request, so return the job-tracker session. return job->session; } // The job tracker already was assigned a session ID. // Check if the new one matches. if (PMIX_UNLIKELY(job->session->smdata->id != sid)) { // This is an error: you cannot assign a given job to multiple sessions. PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return NULL; } // The two must match, so return it. return job->session; } bool pmix_gds_shmem2_hostnames_eq( const char *h1, const char *h2 ) { return (0 == strcmp(h1, h2)); } pmix_status_t pmix_gds_shmem2_get_job_shmem2_by_id( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, pmix_shmem_t **shmem2 ) { switch (shmem2_id) { case PMIX_GDS_SHMEM2_JOB_ID: *shmem2 = job->shmem2; break; case PMIX_GDS_SHMEM2_SESSION_ID: *shmem2 = job->session->shmem2; break; case PMIX_GDS_SHMEM2_MODEX_ID: *shmem2 = job->modex_shmem2; break; case PMIX_GDS_SHMEM2_INVALID_ID: default: PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); abort(); return PMIX_ERR_BAD_PARAM; } return PMIX_SUCCESS; } static inline pmix_gds_shmem2_status_t * get_job_shmem2_status_flagp( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id ) { switch (shmem2_id) { case PMIX_GDS_SHMEM2_JOB_ID: return &job->shmem2_status; case PMIX_GDS_SHMEM2_SESSION_ID: return &job->session->shmem2_status; case PMIX_GDS_SHMEM2_MODEX_ID: return &job->modex_shmem2_status; case PMIX_GDS_SHMEM2_INVALID_ID: default: // This is a fatal internal error. PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); abort(); return NULL; } } void pmix_gds_shmem2_set_status( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, pmix_gds_shmem2_status_flag_t flag ) { *get_job_shmem2_status_flagp(job, shmem2_id) |= flag; } void pmix_gds_shmem2_clear_status( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, pmix_gds_shmem2_status_flag_t flag ) { *get_job_shmem2_status_flagp(job, shmem2_id) &= ~flag; } void pmix_gds_shmem2_clearall_status( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id ) { *get_job_shmem2_status_flagp(job, shmem2_id) = 0; } bool pmix_gds_shmem2_has_status( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, pmix_gds_shmem2_status_flag_t flag ) { return (*get_job_shmem2_status_flagp(job, shmem2_id) & flag); } /* * vim: ft=cpp ts=4 sts=4 sw=4 expandtab */ pmix-6.1.1~rc2/src/mca/gds/shmem2/gds_shmem2_fetch.h0000664000175000017500000000106015203536752022343 0ustar alastairalastair/* * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * Copyright (c) 2024-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_GDS_SHMEM2_FETCH_H #define PMIX_GDS_SHMEM2_FETCH_H #include "gds_shmem2.h" PMIX_EXPORT pmix_status_t pmix_gds_shmem2_fetch( struct pmix_peer_t *peer, const pmix_proc_t *proc, pmix_scope_t scope, bool copy, const char *key, pmix_info_t qualifiers[], size_t nqual, pmix_list_t *kvs ); #endif pmix-6.1.1~rc2/src/mca/gds/shmem2/help-gds-shmem2.txt0000664000175000017500000000125415203536752022433 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. # Copyright (c) 2024 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English general help file for PMIX. # [shmem2-segment-attach:address-mismatch] The gds/shmem2 component attempted to attach to a shared-memory segment at a particular base address, but was given a different one. Your job will now likely abort. Requested Address: 0x%zx Acquired Address: 0x%zx If this problem persists, please consider disabling the gds/shmem2 component by setting in your environment the following: PMIX_MCA_gds=hash pmix-6.1.1~rc2/src/mca/gds/shmem2/configure.m40000664000175000017500000000177015203536752021224 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2021-2024 Nanook Consulting All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # Copyright (c) 2023 Triad National Security, LLC. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AC_DEFUN([MCA_pmix_gds_shmem2_CONFIG], [ AC_CONFIG_FILES([src/mca/gds/shmem2/Makefile]) dnl We rely on large virtual address spaces in gds/shmem2, so make sure that dnl we are dealing with a 64-bit architecture. For example, a 32-bit virtual dnl address space is probably too small for the 'virtual memory hole' dnl finding that we do here. Below assumes support for only 32- and 64-bit dnl architectures. AS_IF([test $ac_cv_sizeof_void_p -ne 4 && test $oac_have_apple = 0], [$1 pmix_gds_shmem2=yes], [$2 pmix_gds_shmem2=no]) PMIX_SUMMARY_ADD([GDS], [Shared-Memory], [], [$pmix_gds_shmem2]) ])dnl pmix-6.1.1~rc2/src/mca/gds/shmem2/gds_shmem2.h0000664000175000017500000001415015203536752021176 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_GDS_SHMEM2_H #define PMIX_GDS_SHMEM2_H #include "pmix_config.h" #include "include/pmix_common.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_shmem.h" #include "src/mca/gds/base/base.h" #ifdef HAVE_STDINT_h #include #endif /** * The name of this module. */ #define PMIX_GDS_SHMEM2_NAME "shmem2" /** * Default component/module priority. */ #define PMIX_GDS_SHMEM2_DEFAULT_PRIORITY 20 BEGIN_C_DECLS extern pmix_gds_base_module_t pmix_shmem2_module; /** * Stores MCA parameter value for segment_size_multiplier. */ PMIX_EXPORT extern double pmix_gds_shmem2_segment_size_multiplier; /** * IDs for pmix_shmem_ts in pmix_gds_shmem2_job_t. */ typedef enum { PMIX_GDS_SHMEM2_JOB_ID = 0, PMIX_GDS_SHMEM2_SESSION_ID, PMIX_GDS_SHMEM2_MODEX_ID, PMIX_GDS_SHMEM2_INVALID_ID } pmix_gds_shmem2_job_shmem2_id_t; /** * Bitmap container for flags associated with a pmix_shmem_t structure. */ typedef uint8_t pmix_gds_shmem2_status_t; typedef enum { /** Indicates that caller is shmem2 creator. */ PMIX_GDS_SHMEM2_MINE = 0x01, /** Indicates that the shared-memory segment is attached to. */ PMIX_GDS_SHMEM2_ATTACHED = 0x02, /** Indicates that the shared-memory segment is ready for use. */ PMIX_GDS_SHMEM2_READY_FOR_USE = 0x04 } pmix_gds_shmem2_status_flag_t; typedef struct { pmix_gds_base_component_t super; /** List of jobs that I'm supporting. */ pmix_list_t jobs; /** List of sessions that I'm supporting. */ pmix_list_t sessions; } pmix_gds_shmem2_component_t; // The component must be visible data for the linker to find it. PMIX_EXPORT extern pmix_gds_shmem2_component_t pmix_mca_gds_shmem2_component; typedef struct { pmix_list_item_t super; /** Hostname. */ char *name; } pmix_gds_shmem2_host_alias_t; PMIX_CLASS_DECLARATION(pmix_gds_shmem2_host_alias_t); typedef struct { pmix_list_item_t super; /** Node ID. */ uint32_t nodeid; /** Hostname. */ char *hostname; /** Node name aliases. */ pmix_list_t *aliases; /** Node information. */ pmix_list_t *info; } pmix_gds_shmem2_nodeinfo_t; PMIX_CLASS_DECLARATION(pmix_gds_shmem2_nodeinfo_t); typedef struct { /** Shared-memory allocator for data this structure. */ pmix_tma_t tma; /** Holds the current address of the shared-memory allocator. */ void *current_addr; /** Session ID. */ uint32_t id; /** Session information. */ pmix_list_t *sessioninfo; /** Node information. */ pmix_list_t *nodeinfo; } pmix_gds_shmem2_shared_session_data_t; typedef struct { pmix_list_item_t super; /** Shared-memory object that maintains backing store for session data. */ pmix_shmem_t *shmem2; /** Stores status for shmem2. */ pmix_gds_shmem2_status_t shmem2_status; /** Session data stored in shared-memory. */ pmix_gds_shmem2_shared_session_data_t *smdata; } pmix_gds_shmem2_session_t; PMIX_CLASS_DECLARATION(pmix_gds_shmem2_session_t); /** * Shared data structures that reside in shared-memory. The server populates * these data and clients are only permitted to read from them. * * Note that the shared data structures in pmix_gds_shmem2_shared_*_data_t are * pointers since their respective locations must reside on the shared heap * located in shared-memory and managed by a shared-memory TMA. */ typedef struct { /** Shared-memory allocator for data this structure. */ pmix_tma_t tma; /** Holds the current address of the shared-memory allocator. */ void *current_addr; /** List containing job information. */ pmix_list_t *jobinfo; /** List containing this job's node information. */ pmix_list_t *nodeinfo; /** List of applications in this job. */ pmix_list_t *appinfo; /** Stores static local (node) job data. */ pmix_hash_table_t *local_hashtab; } pmix_gds_shmem2_shared_job_data_t; typedef struct { /** Shared-memory allocator for data this structure. */ pmix_tma_t tma; /** Holds the current address of the shared-memory allocator. */ void *current_addr; /** Stores static modex data. */ pmix_hash_table_t *hashtab; } pmix_gds_shmem2_shared_modex_data_t; typedef struct { pmix_list_item_t super; /** User ID */ uid_t uid; /** Group ID */ gid_t gid; /** Change owner? */ bool chown; /** Change group? */ bool chgrp; /** Namespace identifier (name). */ char *nspace_id; /** Pointer to the namespace. */ pmix_namespace_t *nspace; /** Pointer to this job's session information. */ pmix_gds_shmem2_session_t *session; /** Stores status for shmem2. */ pmix_gds_shmem2_status_t shmem2_status; /** Shared-memory object that maintains backing store for smdata data. */ pmix_shmem_t *shmem2; /** Stores status for modex_shmem2. */ pmix_gds_shmem2_status_t modex_shmem2_status; /** Shared-memory object that maintains backing store for smmodex data. */ pmix_shmem_t *modex_shmem2; /** Points to shared job data located in a shared-memory segment. */ pmix_gds_shmem2_shared_job_data_t *smdata; /** Points to shared modex data located in a shared-memory segment. */ pmix_gds_shmem2_shared_modex_data_t *smmodex; /** Packed connection information to this segment. */ pmix_buffer_t *conni; /** Flag indicating whether client-side keyindex updates have been done. */ bool client_keyindex_fixup_done; } pmix_gds_shmem2_job_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_gds_shmem2_job_t); typedef struct { pmix_list_item_t super; /** Application number. */ uint32_t appnum; /** Application info. */ pmix_list_t *appinfo; /** Node information. */ pmix_list_t *nodeinfo; /* Application job info. */ pmix_gds_shmem2_job_t *job; } pmix_gds_shmem2_app_t; PMIX_CLASS_DECLARATION(pmix_gds_shmem2_app_t); END_C_DECLS #endif /* * vim: ft=cpp ts=4 sts=4 sw=4 expandtab */ pmix-6.1.1~rc2/src/mca/gds/shmem2/gds_shmem2_component.c0000664000175000017500000000677715203536752023273 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2022-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "pmix_info" from having to import * entire components just to query their version and parameters. */ #include "gds_shmem2.h" static int gds_shmem2_component_register(void); static int component_query(pmix_mca_base_module_t **module, int *priority) { // See if the required system file is present. // See pmix_vmem_find_hole() for more information. if (access("/proc/self/maps", F_OK) == -1) { *priority = 0; *module = NULL; return PMIX_ERROR; } *priority = PMIX_GDS_SHMEM2_DEFAULT_PRIORITY; *module = (pmix_mca_base_module_t *)&pmix_shmem2_module; return PMIX_SUCCESS; } /** * Instantiate the public struct with all of our public * information and pointers to our public functions in it. */ pmix_gds_shmem2_component_t pmix_mca_gds_shmem2_component = { .super = { PMIX_GDS_BASE_VERSION_1_0_0, /** Component name and version. */ .pmix_mca_component_name = PMIX_GDS_SHMEM2_NAME, PMIX_MCA_BASE_MAKE_VERSION( component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION ), /** Component register. */ .pmix_mca_register_component_params = gds_shmem2_component_register, /** Component query function. */ .pmix_mca_query_component = component_query, .reserved = {0} }, .jobs = PMIX_LIST_STATIC_INIT, .sessions = PMIX_LIST_STATIC_INIT }; double pmix_gds_shmem2_segment_size_multiplier = 1.0; static int gds_shmem2_component_register(void) { int varidx; varidx = pmix_mca_base_component_var_register( &pmix_mca_gds_shmem2_component.super, "segment_size_multiplier", "Multiplier that influences the ultimate sizes of the shared-memory " "segments used for gds data storage. As a percentage, values less or " "greater than 1.0 decrease or increase the final segment sizes, " "respectively.", PMIX_MCA_BASE_VAR_TYPE_DOUBLE, &pmix_gds_shmem2_segment_size_multiplier ); if (varidx < 0) { return PMIX_ERROR; } return PMIX_SUCCESS; } PMIX_MCA_BASE_COMPONENT_INIT(pmix, gds, shmem2) /* * vim: ft=cpp ts=4 sts=4 sw=4 expandtab */ pmix-6.1.1~rc2/src/mca/gds/shmem2/gds_shmem2_fetch.c0000664000175000017500000006750015203536752022351 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022-2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "gds_shmem2_fetch.h" #include "gds_shmem2_utils.h" #include "src/util/pmix_hash.h" #include "src/mca/ptl/base/base.h" #include "src/mca/ptl/ptl_types.h" // TODO(skg) Avoid copies where appropriate. static pmix_gds_shmem2_nodeinfo_t * get_nodeinfo_by_nodename( pmix_list_t *nodes, const char *hostname ) { bool aliases_exist = false; if (PMIX_UNLIKELY(NULL == hostname)) { return NULL; } // First, just check all the node names as this is the most likely match. pmix_gds_shmem2_nodeinfo_t *ni; PMIX_LIST_FOREACH (ni, nodes, pmix_gds_shmem2_nodeinfo_t) { if (pmix_gds_shmem2_hostnames_eq(ni->hostname, hostname)) { return ni; } if (!pmix_list_is_empty(ni->aliases)) { aliases_exist = true; } } // We didn't find it by name and name aliases do not exists. if (!aliases_exist) { return NULL; } // If a match wasn't found, then we have to try the aliases. PMIX_LIST_FOREACH (ni, nodes, pmix_gds_shmem2_nodeinfo_t) { pmix_gds_shmem2_host_alias_t *nai = NULL; PMIX_LIST_FOREACH (nai, ni->aliases, pmix_gds_shmem2_host_alias_t) { if (pmix_gds_shmem2_hostnames_eq(nai->name, hostname)) { return ni; } } } // No match found. return NULL; } /** * Fetches all node info from a given nodeinfo. */ static pmix_status_t fetch_all_node_info( char *key, pmix_gds_shmem2_nodeinfo_t *nodeinfo, pmix_list_t *kvs ) { size_t i = 0; pmix_kval_t *kv = PMIX_NEW(pmix_kval_t); kv->key = key; kv->value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } size_t nds = pmix_list_get_size(nodeinfo->info); if (NULL != nodeinfo->hostname) { ++nds; } if (UINT32_MAX != nodeinfo->nodeid) { ++nds; } // Create the data array. pmix_data_array_t *darray; PMIX_DATA_ARRAY_CREATE(darray, nds, PMIX_INFO); if (NULL == darray) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } pmix_info_t *dainfo = (pmix_info_t *)darray->array; if (NULL != nodeinfo->hostname) { PMIX_INFO_LOAD( &dainfo[i++], PMIX_HOSTNAME, nodeinfo->hostname, PMIX_STRING ); } if (UINT32_MAX != nodeinfo->nodeid) { PMIX_INFO_LOAD( &dainfo[i++], PMIX_NODEID, &nodeinfo->nodeid, PMIX_UINT32 ); } pmix_kval_t *kvi; PMIX_LIST_FOREACH (kvi, nodeinfo->info, pmix_kval_t) { PMIX_GDS_SHMEM2_VVOUT( "%s:%s adding key=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), kvi->key ); PMIX_LOAD_KEY(dainfo[i].key, kvi->key); pmix_status_t rc = PMIx_Value_xfer(&dainfo[i].value, kvi->value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DATA_ARRAY_FREE(darray); PMIX_RELEASE(kv); return rc; } i++; } kv->value->data.darray = darray; kv->value->type = PMIX_DATA_ARRAY; pmix_list_append(kvs, &kv->super); return PMIX_SUCCESS; } /** * Fetches all node info from a given list of node infos. */ static pmix_status_t fetch_all_node_info_from_list( pmix_peer_t *peer, pmix_list_t *nodeinfos, pmix_list_t *kvs ) { pmix_status_t rc = PMIX_SUCCESS; pmix_gds_shmem2_nodeinfo_t *ni; PMIX_LIST_FOREACH (ni, nodeinfos, pmix_gds_shmem2_nodeinfo_t) { char *key = NULL; // If the proc's version is earlier than v3.1, then the info must be // provided as a data_array with a key of the node's name as earlier // versions don't understand node_info arrays. if (PMIX_PEER_IS_EARLIER(peer, 3, 1, 0)) { if (NULL == ni->hostname) { // Skip this one. continue; } key = strdup(ni->hostname); } else { // Everyone else uses a node_info array. key = strdup(PMIX_NODE_INFO_ARRAY); } rc = fetch_all_node_info(key, ni, kvs); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { free(key); break; } } return rc; } static pmix_status_t fetch_nodeinfo( pmix_peer_t *peer, const char *key, pmix_list_t *nodeinfos, pmix_info_t *info, size_t ninfo, pmix_list_t *kvs ) { pmix_status_t rc = PMIX_SUCCESS; pmix_gds_shmem2_nodeinfo_t *nodeinfo = NULL; uint32_t nid = UINT32_MAX; char *hostname = NULL; bool found = false; PMIX_GDS_SHMEM2_VOUT( "%s:%s key=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), (NULL == key) ? "NULL" : key ); // Scan for the nodeID or hostname to identify // which node they are asking about. for (size_t n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_NODEID)) { rc = PMIx_Value_get_number(&info[n].value, &nid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { return rc; } found = true; break; } else if (PMIX_CHECK_KEY(&info[n], PMIX_HOSTNAME)) { hostname = info[n].value.data.string; found = true; break; } } if (!found) { // If the key is NULL, then they want all the info from all nodes. if (NULL == key) { return fetch_all_node_info_from_list(peer, nodeinfos, kvs); } // Else assume they want it from this node. hostname = pmix_globals.hostname; } // Scan the list of nodes to find the matching entry. if (UINT32_MAX != nid) { pmix_gds_shmem2_nodeinfo_t *ndi; PMIX_LIST_FOREACH (ndi, nodeinfos, pmix_gds_shmem2_nodeinfo_t) { if (UINT32_MAX != ndi->nodeid && nid == ndi->nodeid) { nodeinfo = ndi; break; } } } else if (NULL != hostname) { nodeinfo = get_nodeinfo_by_nodename(nodeinfos, hostname); } if (NULL == nodeinfo) { // the node is not present in the job, which means // there were no procs on that node - or the node // is unknown, which would indicate an error in // specifying it return PMIX_ERR_NOT_FOUND; } // If they want it all, give it to them. if (NULL == key) { // The key used for the node info. char *nikey = NULL; // If the proc's version is earlier than v3.1, then the info must be // provided as a data_array with a key of the node's name as earlier // versions don't understand node_info arrays. if (PMIX_PEER_IS_EARLIER(peer, 3, 1, 0)) { if (NULL == nodeinfo->hostname) { nikey = strdup(pmix_globals.hostname); } else { nikey = strdup(nodeinfo->hostname); } } else { // Everyone else uses a node_info array. nikey = strdup(PMIX_NODE_INFO_ARRAY); } rc = fetch_all_node_info(nikey, nodeinfo, kvs); if (PMIX_SUCCESS != rc) { free(nikey); } return rc; } // If we are here, then they want a specific key/value pair. So, scan the // info list of this node to find the key they want. rc = PMIX_ERR_DATA_VALUE_NOT_FOUND; pmix_kval_t *kvi; PMIX_LIST_FOREACH (kvi, nodeinfo->info, pmix_kval_t) { if (!PMIX_CHECK_KEY(kvi, key)) { continue; } PMIX_GDS_SHMEM2_VOUT( "%s:%s: adding key=%s", PMIX_NAME_PRINT(&pmix_globals.myid), __func__, kvi->key ); // Since they only asked for one key, return just that value. pmix_kval_t *kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(kvi->key); kv->value = NULL; PMIX_VALUE_XFER(rc, kv->value, kvi->value); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kv); return rc; } pmix_list_append(kvs, &kv->super); break; } return rc; } static pmix_status_t fetch_all_app_info( pmix_list_t *apps, pmix_list_t *kvs ) { pmix_status_t rc = PMIX_SUCCESS; pmix_gds_shmem2_app_t *appi; PMIX_LIST_FOREACH (appi, apps, pmix_gds_shmem2_app_t) { pmix_data_array_t *darray = NULL; size_t i = 0; pmix_kval_t *kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { return PMIX_ERR_NOMEM; } kv->key = strdup(PMIX_APP_INFO_ARRAY); kv->value = (pmix_value_t *)calloc(1, sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } const size_t nds = pmix_list_get_size(appi->appinfo) + 1; PMIX_DATA_ARRAY_CREATE(darray, nds, PMIX_INFO); if (NULL == darray) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } pmix_info_t *info = (pmix_info_t *)darray->array; // Put in the appnum. PMIX_INFO_LOAD(&info[i++], PMIX_APPNUM, &appi->appnum, PMIX_UINT32); // Transfer the app infos. pmix_kval_t *kvi; PMIX_LIST_FOREACH (kvi, appi->appinfo, pmix_kval_t) { PMIX_LOAD_KEY(info[i].key, kvi->key); rc = PMIx_Value_xfer(&info[i].value, kvi->value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DATA_ARRAY_FREE(darray); PMIX_RELEASE(kv); return rc; } i++; } kv->value->data.darray = darray; kv->value->type = PMIX_DATA_ARRAY; pmix_list_append(kvs, &kv->super); } return rc; } static pmix_status_t fetch_appinfo( pmix_peer_t *peer, const char *key, pmix_list_t *target, pmix_info_t *info, size_t ninfo, pmix_list_t *kvs ) { pmix_status_t rc = PMIX_SUCCESS; pmix_gds_shmem2_app_t *app = NULL; uint32_t appnum = 0; bool found = false; PMIX_GDS_SHMEM2_VOUT( "%s FETCHING APP INFO WITH NAPPS=%zd", PMIX_NAME_PRINT(&pmix_globals.myid), pmix_list_get_size(target) ); // Scan for the appnum to identify which app they are asking about. for (size_t n = 0; n < ninfo; n++) { if (!PMIX_CHECK_KEY(&info[n], PMIX_APPNUM)) { continue; } rc = PMIx_Value_get_number(&info[n].value, &appnum, PMIX_UINT32); if (PMIX_SUCCESS != rc) { return rc; } found = true; break; } if (!found) { /* if the key is NULL, then they want all the info from * all apps */ if (NULL == key) { rc = fetch_all_app_info(target, kvs); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } return rc; } // Else assume they are asking for our app. appnum = pmix_globals.appnum; } // Scan the list of apps to find the matching entry. pmix_gds_shmem2_app_t *appi; PMIX_LIST_FOREACH (appi, target, pmix_gds_shmem2_app_t) { if (appnum == appi->appnum) { app = appi; break; } } if (NULL == app) { return PMIX_ERR_NOT_FOUND; } // See if they wanted to know something about // a node that is associated with this app. rc = fetch_nodeinfo( peer, key, app->nodeinfo, info, ninfo, kvs ); if (PMIX_ERR_DATA_VALUE_NOT_FOUND != rc && PMIX_ERR_NOT_FOUND != rc) { return rc; } // Scan the info list of this app to generate the results. rc = PMIX_ERR_NOT_FOUND; pmix_kval_t *kvi; PMIX_LIST_FOREACH (kvi, app->appinfo, pmix_kval_t) { if (NULL == key || PMIX_CHECK_KEY(kvi, key)) { pmix_kval_t *kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(kvi->key); kv->value = NULL; PMIX_VALUE_XFER(rc, kv->value, kvi->value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kv); return rc; } pmix_list_append(kvs, &kv->super); rc = PMIX_SUCCESS; if (NULL != key) { break; } } } return rc; } static pmix_status_t xfer_sessioninfo( pmix_peer_t *peer, pmix_gds_shmem2_session_t *sesh, const char *key, pmix_list_t *kvs ) { pmix_status_t rc = PMIX_SUCCESS; pmix_list_t *const sessionlist = sesh->smdata->sessioninfo; const uint32_t sid = sesh->smdata->id; if (NULL == key) { if (PMIX_PEER_IS_EARLIER(peer, 4, 2, 0)) { // We can only transfer the data as independent values. pmix_kval_t *kvi; PMIX_LIST_FOREACH(kvi, sessionlist, pmix_kval_t) { pmix_kval_t *kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(kvi->key); PMIX_VALUE_XFER(rc, kv->value, kvi->value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kv); return rc; } pmix_list_append(kvs, &kv->super); } } else { // Return it as an info array. pmix_kval_t *kv; PMIX_KVAL_NEW(kv, PMIX_SESSION_INFO_ARRAY); kv->value->type = PMIX_DATA_ARRAY; const size_t n = pmix_list_get_size(sessionlist) + 1; PMIX_DATA_ARRAY_CREATE(kv->value->data.darray, n, PMIX_INFO); pmix_info_t *info = (pmix_info_t *)kv->value->data.darray->array; // First element is the session id. PMIX_INFO_LOAD(&info[0], PMIX_SESSION_ID, &sid, PMIX_UINT32); // Populate the rest of the array. size_t i = 1; pmix_kval_t *kvi; PMIX_LIST_FOREACH(kvi, sessionlist, pmix_kval_t) { PMIX_LOAD_KEY(info[i].key, kvi->key); rc = PMIx_Value_xfer(&info[i].value, kvi->value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kv); return rc; } i++; } pmix_list_append(kvs, &kv->super); } return PMIX_SUCCESS; } // Else we were given a specific key. pmix_kval_t *kvi; PMIX_LIST_FOREACH(kvi, sessionlist, pmix_kval_t) { if (PMIX_CHECK_KEY(kvi, key)) { pmix_kval_t *kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(kvi->key); PMIX_VALUE_XFER(rc, kv->value, kvi->value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kv); return rc; } pmix_list_append(kvs, &kv->super); return PMIX_SUCCESS; } } return PMIX_ERR_NOT_FOUND; } static pmix_status_t fetch_sessioninfo( pmix_peer_t *peer, const char *key, pmix_gds_shmem2_job_t *job, pmix_info_t *info, size_t ninfo, pmix_list_t *kvs ) { pmix_status_t rc = PMIX_SUCCESS; PMIX_GDS_SHMEM2_VOUT("%s: FETCHING SESSION INFO", __func__); // Scan for the session ID to identify which session they are asking about. uint32_t sid = UINT32_MAX; for (size_t n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SESSION_ID)) { rc = PMIx_Value_get_number(&info[n].value, &sid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { return rc; } break; } } pmix_gds_shmem2_session_t *sesh; sesh = pmix_gds_shmem2_get_session_tracker(job, sid, false); if (PMIX_UNLIKELY(NULL == sesh)) { return PMIX_ERR_NOT_FOUND; } return xfer_sessioninfo(peer, sesh, key, kvs); } // TODO(skg) This needs plenty of work. pmix_status_t pmix_gds_shmem2_fetch( struct pmix_peer_t *pr, const pmix_proc_t *proc, pmix_scope_t scope, bool copy, const char *key, pmix_info_t qualifiers[], size_t nqual, pmix_list_t *kvs ) { PMIX_GDS_SHMEM2_VVOUT_HERE(); pmix_peer_t *peer = (pmix_peer_t*)pr; pmix_status_t rc = PMIX_SUCCESS; bool sessioninfo = false; bool nodeinfo = false; bool appinfo = false; bool sidgiven = false; bool nigiven = false; bool apigiven = false; PMIX_HIDE_UNUSED_PARAMS(copy); PMIX_GDS_SHMEM2_VOUT( "%s:%s key=%s for proc=%s on scope=%s on behalf of %s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), !key ? "NULL" : key, PMIX_NAME_PRINT(proc), PMIx_Scope_string(scope), PMIX_PEER_PRINT(peer) ); // Get the tracker for this job. We should have already created one, so // that's why we pass false in pmix_gds_shmem2_get_job_tracker(). pmix_gds_shmem2_job_t *job; rc = pmix_gds_shmem2_get_job_tracker(proc->nspace, false, &job); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { return rc; } pmix_hash_table_t *const local_ht = job->smdata->local_hashtab; // Modex data ready for use? const bool mdrfu = pmix_gds_shmem2_has_status( job, PMIX_GDS_SHMEM2_MODEX_ID, PMIX_GDS_SHMEM2_READY_FOR_USE ); // Modex data are stored in PMIX_REMOTE. pmix_hash_table_t *const remote_ht = mdrfu ? job->smmodex->hashtab : NULL; // If the rank is wildcard and key is NULL, then the caller is asking for a // complete copy of the job-level info for this nspace, so retrieve it. if (NULL == key && PMIX_RANK_WILDCARD == proc->rank) { // Fetch all values from the hash table tied to rank=wildcard. rc = pmix_hash_fetch( local_ht, PMIX_RANK_WILDCARD, NULL, NULL, 0, kvs, NULL ); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { return rc; } // Also need to add any job-level info. // TODO(skg) Pass back the pointer to kv->value. pmix_kval_t *kvi; PMIX_LIST_FOREACH (kvi, job->smdata->jobinfo, pmix_kval_t) { pmix_kval_t *kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(kvi->key); PMIX_VALUE_XFER(rc, kv->value, kvi->value); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_RELEASE(kv); return rc; } pmix_list_append(kvs, &kv->super); } // Collect all the relevant session-level info. rc = fetch_sessioninfo(peer, NULL, job, qualifiers, nqual, kvs); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { return rc; } // Collect the relevant node-level info. rc = fetch_nodeinfo( peer, NULL, job->smdata->nodeinfo, qualifiers, nqual, kvs ); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { return rc; } // Collect the relevant app-level info. rc = fetch_appinfo( peer, NULL, job->smdata->appinfo, qualifiers, nqual, kvs ); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { return rc; } // Finally, we need the job-level info for each rank in the job. for (pmix_rank_t rank = 0; rank < job->nspace->nprocs; rank++) { pmix_list_t rkvs; PMIX_CONSTRUCT(&rkvs, pmix_list_t); rc = pmix_hash_fetch( local_ht, rank, NULL, NULL, 0, &rkvs, NULL ); if (PMIX_UNLIKELY(PMIX_ERR_NOMEM == rc)) { PMIX_LIST_DESTRUCT(&rkvs); return rc; } const size_t ninfo = pmix_list_get_size(&rkvs); if (0 == ninfo) { PMIX_DESTRUCT(&rkvs); continue; } // Setup to return the result. // TODO(skg) Maybe place to help with zero-copy? pmix_kval_t *kv; PMIX_KVAL_NEW(kv, PMIX_PROC_DATA); kv->value->type = PMIX_DATA_ARRAY; const size_t niptr = ninfo + 1; // Need space for the rank. PMIX_DATA_ARRAY_CREATE(kv->value->data.darray, niptr, PMIX_INFO); pmix_info_t *iptr = (pmix_info_t *)kv->value->data.darray->array; // Start with the rank. PMIX_INFO_LOAD(&iptr[0], PMIX_RANK, &rank, PMIX_PROC_RANK); // Now transfer rest of data across. size_t i = 1; PMIX_LIST_FOREACH(kvi, &rkvs, pmix_kval_t) { PMIX_LOAD_KEY(iptr[i].key, kvi->key); PMIx_Value_xfer(&iptr[i].value, kvi->value); i++; } // Add to the results. pmix_list_append(kvs, &kv->super); // Release the search result. PMIX_LIST_DESTRUCT(&rkvs); } return PMIX_SUCCESS; } for (size_t n = 0; n < nqual; n++) { if (PMIX_CHECK_KEY(&qualifiers[n], PMIX_SESSION_INFO)) { sessioninfo = PMIX_INFO_TRUE(&qualifiers[n]); sidgiven = true; } else if (PMIX_CHECK_KEY(&qualifiers[n], PMIX_NODE_INFO)) { nodeinfo = PMIX_INFO_TRUE(&qualifiers[n]); nigiven = true; } else if (PMIX_CHECK_KEY(&qualifiers[n], PMIX_APP_INFO)) { appinfo = PMIX_INFO_TRUE(&qualifiers[n]); apigiven = true; } } // Check for node/app keys in the absence of corresponding qualifier. if (NULL != key && !sidgiven && !nigiven && !apigiven) { if (pmix_check_session_info(key)) { sessioninfo = true; } else if (pmix_check_node_info(key)) { nodeinfo = true; } else if (pmix_check_app_info(key)) { appinfo = true; } } if (sessioninfo) { return fetch_sessioninfo(peer, key, job, qualifiers, nqual, kvs); } if (!PMIX_RANK_IS_VALID(proc->rank)) { if (nodeinfo) { rc = fetch_nodeinfo( peer, key, job->smdata->nodeinfo, qualifiers, nqual, kvs ); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc && (PMIX_RANK_WILDCARD == proc->rank || PMIX_RANK_UNDEF == proc->rank)) { // Let hash deal with this one. rc = PMIX_ERR_NOT_FOUND; } return rc; } else if (appinfo) { rc = fetch_appinfo( peer, key, job->smdata->appinfo, qualifiers, nqual, kvs ); if (PMIX_SUCCESS != rc && PMIX_RANK_WILDCARD == proc->rank) { // Let hash deal with this one. rc = PMIX_ERR_NOT_FOUND; } return rc; } } // Fetch from the corresponding hash table. // TODO(skg) I'm guessing this is one spot where we can decide if a copy is // appropriate. pmix_hash_table_t *ht = NULL; if (PMIX_INTERNAL == scope || PMIX_LOCAL == scope || PMIX_GLOBAL == scope || PMIX_SCOPE_UNDEF == scope || PMIX_RANK_WILDCARD == proc->rank) { ht = local_ht; } else if (PMIX_REMOTE == scope) { // Note that this ht can be NULL. ht = remote_ht; } else { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } doover: // If rank=PMIX_RANK_UNDEF, then we need to search all // known ranks for this nspace as any one of them could // be the source. if (PMIX_RANK_UNDEF == proc->rank && ht) { for (pmix_rank_t rnk = 0; rnk < job->nspace->nprocs; rnk++) { rc = pmix_hash_fetch(ht, rnk, key, qualifiers, nqual, kvs, NULL); if (PMIX_ERR_NOMEM == rc) { return rc; } if (PMIX_SUCCESS == rc && NULL != key) { return rc; } } // Also need to check any job-level info. pmix_kval_t *kvi; PMIX_LIST_FOREACH (kvi, job->smdata->jobinfo, pmix_kval_t) { if (NULL == key || PMIX_CHECK_KEY(kvi, key)) { pmix_kval_t *kv; kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(kvi->key); PMIX_VALUE_XFER(rc, kv->value, kvi->value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kv); return rc; } pmix_list_append(kvs, &kv->super); if (NULL != key) { break; } } } if (NULL == key) { // And need to add all job info just in case // that was passed via a different GDS component. rc = pmix_hash_fetch( local_ht, PMIX_RANK_WILDCARD, NULL, NULL, 0, kvs, NULL ); } else { rc = PMIX_ERR_NOT_FOUND; } } else { if (ht) { rc = pmix_hash_fetch( ht, proc->rank, key, qualifiers, nqual, kvs, NULL ); } else { rc = PMIX_ERR_NOT_FOUND; } } if (PMIX_SUCCESS == rc) { if (NULL != key && PMIX_CHECK_RESERVED_KEY(key)) { // there is no need to check other scopes for // reserved keys return PMIX_SUCCESS; } if (PMIX_GLOBAL == scope) { if (ht == local_ht) { // We need to do this again for the remote data. ht = remote_ht; goto doover; } } } else { if (PMIX_GLOBAL == scope || PMIX_SCOPE_UNDEF == scope) { if (ht == local_ht) { // We need to also try the remote data. ht = remote_ht; goto doover; } } } if (0 == pmix_list_get_size(kvs)) { /* if we didn't find it and the rank was valid, then * check to see if the data exists in a different scope. * This is done to avoid having the process go into a * timeout wait when the data will never appear within * the specified scope */ if (PMIX_RANK_IS_VALID(proc->rank)) { pmix_kval_t *kv; if (PMIX_LOCAL == scope) { if (NULL != remote_ht) { /* check the remote scope */ rc = pmix_hash_fetch(remote_ht, proc->rank, key, qualifiers, nqual, kvs, NULL); if (PMIX_SUCCESS == rc || 0 < pmix_list_get_size(kvs)) { while (NULL != (kv = (pmix_kval_t *) pmix_list_remove_first(kvs))) { PMIX_RELEASE(kv); } rc = PMIX_ERR_EXISTS_OUTSIDE_SCOPE; } else { rc = PMIX_ERR_NOT_FOUND; } } else { rc = PMIX_ERR_NOT_FOUND; } } else if (PMIX_REMOTE == scope) { /* check the local scope */ rc = pmix_hash_fetch(local_ht, proc->rank, key, qualifiers, nqual, kvs, NULL); if (PMIX_SUCCESS == rc || 0 < pmix_list_get_size(kvs)) { while (NULL != (kv = (pmix_kval_t *) pmix_list_remove_first(kvs))) { PMIX_RELEASE(kv); } rc = PMIX_ERR_EXISTS_OUTSIDE_SCOPE; } else { rc = PMIX_ERR_NOT_FOUND; } } } else { rc = PMIX_ERR_NOT_FOUND; } } else { // since we found something, the fetch is a success. // We need to set the status here because the fetch on the // last scope we tried might not have succeeded, but // we found things in an earlier scope we tried rc = PMIX_SUCCESS; } return rc; } /* * vim: ft=cpp ts=4 sts=4 sw=4 expandtab */ pmix-6.1.1~rc2/src/mca/gds/shmem2/gds_shmem2_store.c0000664000175000017500000004764315203536752022422 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022-2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "gds_shmem2_store.h" #include "gds_shmem2_utils.h" #include "src/util/pmix_hash.h" #include "src/mca/bfrops/base/bfrop_base_tma.h" /** * Convenience function for creating an initialized pmix_kval_t. */ static pmix_kval_t * newkval( const char *key, pmix_tma_t *tma ) { pmix_kval_t *kv = PMIX_NEW(pmix_kval_t, tma); if (PMIX_LIKELY(kv)) { kv->key = pmix_tma_strdup(tma, key); if (PMIX_UNLIKELY(!kv->key)) { PMIX_RELEASE(kv); return kv; } kv->value = pmix_tma_calloc(tma, 1, sizeof(pmix_value_t)); if (PMIX_UNLIKELY(!kv->value)) { PMIX_RELEASE(kv); return kv; } } return kv; } /** * Populates the provided with the elements present in the given comma-delimited * string. If the list is not empty, it is first cleared and then set. */ static inline pmix_status_t set_host_aliases_from_cds( pmix_list_t *list, const char *cds ) { pmix_status_t rc = PMIX_SUCCESS; pmix_tma_t *const tma = pmix_obj_get_tma(&list->super); // If the list isn't empty, release remove and release its items. if (!pmix_list_is_empty(list)) { pmix_list_item_t *it; while (NULL != (it = pmix_list_remove_first(list))) { PMIX_RELEASE(it); } } // Now, add each element present in the comma-delimited string list. Not // using our TMA because this is a temporary value. char **tmp = PMIx_Argv_split(cds, ','); if (PMIX_UNLIKELY(!tmp)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } for (size_t i = 0; NULL != tmp[i]; i++) { pmix_gds_shmem2_host_alias_t *alias; alias = PMIX_NEW(pmix_gds_shmem2_host_alias_t, tma); if (PMIX_UNLIKELY(!alias)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } alias->name = pmix_tma_strdup(tma, tmp[i]); if (PMIX_UNLIKELY(!alias->name)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } pmix_list_append(list, &alias->super); } out: PMIx_Argv_free(tmp); return rc; } static pmix_status_t cache_node_info( pmix_info_t *info, size_t ninfo, pmix_list_t *cache, pmix_gds_shmem2_nodeinfo_t **nodeinfo ) { pmix_status_t rc = PMIX_SUCCESS; pmix_tma_t *const tma = pmix_obj_get_tma(&cache->super); bool have_node_id_info = false; pmix_gds_shmem2_nodeinfo_t *iinfo = PMIX_NEW(pmix_gds_shmem2_nodeinfo_t, tma); if (PMIX_UNLIKELY(!iinfo)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); return rc; } // Cache the values while searching for the nodeid and/or hostname. for (size_t j = 0; j < ninfo; j++) { PMIX_GDS_SHMEM2_VVOUT( "%s:%s for key=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), info[j].key ); if (PMIX_CHECK_KEY(&info[j], PMIX_NODEID)) { have_node_id_info = true; rc = PMIx_Value_get_number(&info[j].value, &iinfo->nodeid, PMIX_UINT32); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } } else if (PMIX_CHECK_KEY(&info[j], PMIX_HOSTNAME)) { have_node_id_info = true; iinfo->hostname = pmix_tma_strdup( tma, info[j].value.data.string ); if (PMIX_UNLIKELY(!iinfo->hostname)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } } else if (PMIX_CHECK_KEY(&info[j], PMIX_HOSTNAME_ALIASES)) { have_node_id_info = true; // info[j].value.data.string is a // comma-delimited string of hostnames. rc = set_host_aliases_from_cds( iinfo->aliases, info[j].value.data.string ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } // Need to cache this value as well. pmix_kval_t *kv = newkval(info[j].key, tma); if (PMIX_UNLIKELY(!kv)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } rc = pmix_bfrops_base_tma_value_xfer(kv->value, &info[j].value, tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kv); goto out; } pmix_list_append(cache, &kv->super); } else { pmix_kval_t *kv = newkval(info[j].key, tma); if (PMIX_UNLIKELY(!kv)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } rc = pmix_bfrops_base_tma_value_xfer(kv->value, &info[j].value, tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kv); break; } pmix_list_append(cache, &kv->super); } } // Make sure that the caller passed us node identifier info. if (PMIX_UNLIKELY(!have_node_id_info)) { rc = PMIX_ERR_BAD_PARAM; } out: if (PMIX_SUCCESS != rc) { PMIX_RELEASE(iinfo); } *nodeinfo = iinfo; return rc; } static pmix_status_t store_node_array( pmix_value_t *val, pmix_list_t *target ) { pmix_status_t rc = PMIX_SUCCESS; // We expect an array of node-level info for a specific // node. Make sure we were given the correct type. if (PMIX_UNLIKELY(PMIX_DATA_ARRAY != val->type)) { rc = PMIX_ERR_TYPE_MISMATCH; PMIX_ERROR_LOG(rc); return rc; } // Construct node info cache from provided data. pmix_tma_t *const tma = pmix_obj_get_tma(&target->super); pmix_list_t *cache = PMIX_NEW(pmix_list_t, tma); if (PMIX_UNLIKELY(!cache)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); return rc; } pmix_gds_shmem2_nodeinfo_t *nodeinfo; rc = cache_node_info( (pmix_info_t *)val->data.darray->array, val->data.darray->size, cache, &nodeinfo ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { goto out; } pmix_kval_t *cache_kv; while ((cache_kv = (pmix_kval_t *)pmix_list_remove_first(cache))) { pmix_list_append(nodeinfo->info, &cache_kv->super); } pmix_list_append(target, &nodeinfo->super); out: PMIX_LIST_DESTRUCT(cache); return rc; } static pmix_status_t store_app_array( pmix_gds_shmem2_job_t *job, pmix_value_t *val ) { pmix_status_t rc = PMIX_SUCCESS; pmix_gds_shmem2_app_t *app = NULL; // Apps must belong to a job. if (PMIX_UNLIKELY(!job)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } // We expect an array of node-level info for a specific // node. Make sure we were given the correct type. if (PMIX_UNLIKELY(PMIX_DATA_ARRAY != val->type)) { PMIX_ERROR_LOG(PMIX_ERR_TYPE_MISMATCH); return PMIX_ERR_TYPE_MISMATCH; } pmix_tma_t *const tma = pmix_gds_shmem2_get_job_tma(job); // Setup arrays and lists. pmix_list_t *app_cache = PMIX_NEW(pmix_list_t, tma); if (PMIX_UNLIKELY(!app_cache)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); return rc; } pmix_list_t *node_cache = PMIX_NEW(pmix_list_t, tma); if (PMIX_UNLIKELY(!node_cache)) { PMIX_LIST_DESTRUCT(app_cache); rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); return rc; } const size_t size = val->data.darray->size; pmix_info_t *info = (pmix_info_t *)val->data.darray->array; for (size_t j = 0; j < size; j++) { PMIX_GDS_SHMEM2_VVOUT( "%s:%s for key=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), info[j].key ); if (PMIX_CHECK_KEY(&info[j], PMIX_APPNUM)) { uint32_t appnum; rc = PMIx_Value_get_number(&info[j].value, &appnum, PMIX_UINT32); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } // This is an error: there can be only // one app described in this array. if (PMIX_UNLIKELY(NULL != app)) { PMIX_RELEASE(app); rc = PMIX_ERR_BAD_PARAM; PMIX_ERROR_LOG(rc); goto out; } app = PMIX_NEW(pmix_gds_shmem2_app_t, tma); if (PMIX_UNLIKELY(!app)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } app->appnum = appnum; } else if (PMIX_CHECK_KEY(&info[j], PMIX_NODE_INFO_ARRAY)) { rc = store_node_array(&info[j].value, node_cache); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } } else { pmix_kval_t *kv = newkval(info[j].key, tma); if (PMIX_UNLIKELY(!kv)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } rc = pmix_bfrops_base_tma_value_xfer(kv->value, &info[j].value, tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kv); goto out; } pmix_list_append(app_cache, &kv->super); } } if (NULL == app) { // Per the standard, they don't have to provide us with // an appnum so long as only one app is in the job. if (0 == pmix_list_get_size(job->smdata->appinfo)) { app = PMIX_NEW(pmix_gds_shmem2_app_t, tma); if (PMIX_UNLIKELY(!app)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } app->appnum = 0; } else { // This is not allowed to happen: they are required // to provide us with an app number per the standard. rc = PMIX_ERR_BAD_PARAM; PMIX_ERROR_LOG(rc); goto out; } } // Add it to our list of apps. pmix_list_append(job->smdata->appinfo, &app->super); // Point the app at its job. if (NULL == app->job) { // Do NOT retain the tracker. We will not release it in the app // destructor. If we retain the tracker, then we won't release it later // because the refcount is wrong. app->job = job; } // Transfer the app-level data across. pmix_kval_t *akv; while ((akv = (pmix_kval_t *)pmix_list_remove_first(app_cache))) { pmix_list_append(app->appinfo, &akv->super); } // Transfer the associated node-level data across. pmix_gds_shmem2_nodeinfo_t *nd; while ((nd = (pmix_gds_shmem2_nodeinfo_t *)pmix_list_remove_first(node_cache))) { pmix_list_append(app->nodeinfo, &nd->super); } out: PMIX_LIST_DESTRUCT(app_cache); PMIX_LIST_DESTRUCT(node_cache); return rc; } static pmix_status_t store_proc_data( pmix_gds_shmem2_job_t *job, const pmix_kval_t *kval ) { pmix_status_t rc = PMIX_SUCCESS; // First, make sure this is proc data. if (PMIX_UNLIKELY(!PMIX_CHECK_KEY(kval, PMIX_PROC_DATA))) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } // We are expecting an array of data pertaining to a specific proc. if (PMIX_UNLIKELY(PMIX_DATA_ARRAY != kval->value->type)) { PMIX_ERROR_LOG(PMIX_ERR_TYPE_MISMATCH); return PMIX_ERR_TYPE_MISMATCH; } pmix_info_t *const info = (pmix_info_t *)kval->value->data.darray->array; // First element of the array must be the rank. if (PMIX_UNLIKELY(!PMIX_CHECK_KEY(&info[0], PMIX_RANK)) || info[0].value.type != PMIX_PROC_RANK) { rc = PMIX_ERR_TYPE_MISMATCH; PMIX_ERROR_LOG(rc); return rc; } pmix_hash_table_t *const ht = job->smdata->local_hashtab; pmix_tma_t *const tma = pmix_obj_get_tma(&ht->super); const pmix_rank_t rank = info[0].value.data.rank; const size_t size = kval->value->data.darray->size; // Cycle through the values for this rank and store them. for (size_t j = 1; j < size; j++) { pmix_kval_t *kv = PMIX_NEW(pmix_kval_t, tma); kv->key = info[j].key; kv->value = &info[j].value; PMIX_GDS_SHMEM2_VVOUT( "%s:%s for nspace=%s rank=%u key=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), job->nspace_id, rank, kv->key ); // Store it in the hash_table. rc = pmix_hash_store(ht, rank, kv, NULL, 0, NULL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } } return rc; } static pmix_status_t store_session_array( pmix_gds_shmem2_job_t *job, pmix_value_t *val ) { pmix_status_t rc = PMIX_SUCCESS; // We expect an array of session-level info. if (PMIX_UNLIKELY(PMIX_DATA_ARRAY != val->type)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_TYPE_MISMATCH; } // The first value is required to be the session ID. pmix_info_t *const info = (pmix_info_t *)val->data.darray->array; if (PMIX_UNLIKELY(!PMIX_CHECK_KEY(&info[0], PMIX_SESSION_ID))) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } uint32_t sid; rc = PMIx_Value_get_number(&info[0].value, &sid, PMIX_UINT32); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); return rc; } pmix_gds_shmem2_session_t *sesh; sesh = pmix_gds_shmem2_get_session_tracker(job, sid, false); if (PMIX_UNLIKELY(!sesh)) { rc = PMIX_ERROR; PMIX_ERROR_LOG(rc); return rc; } pmix_tma_t *const tma = pmix_gds_shmem2_get_session_tma(job); pmix_list_t *ncache = PMIX_NEW(pmix_list_t, tma); if (PMIX_UNLIKELY(!ncache)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); return rc; } const size_t size = val->data.darray->size; for (size_t j = 1; j < size; j++) { PMIX_GDS_SHMEM2_VVOUT( "%s:%s key=%s", __func__, PMIX_NAME_PRINT(&pmix_globals.myid), info[j].key ); if (PMIX_CHECK_KEY(&info[j], PMIX_NODE_INFO_ARRAY)) { rc = store_node_array(&info[j].value, ncache); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } } else { pmix_kval_t *kval = newkval(info[j].key, tma); if (PMIX_UNLIKELY(!kval)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } rc = pmix_bfrops_base_tma_value_xfer(kval->value, &info[j].value, tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kval); goto out; } pmix_list_append(sesh->smdata->sessioninfo, &kval->super); } } pmix_gds_shmem2_nodeinfo_t *ni; while ((ni = (pmix_gds_shmem2_nodeinfo_t *)pmix_list_remove_first(ncache))) { pmix_list_append(sesh->smdata->nodeinfo, &ni->super); } out: PMIX_LIST_DESTRUCT(ncache); return rc; } pmix_status_t pmix_gds_shmem2_store_qualified( pmix_hash_table_t *ht, pmix_rank_t rank, pmix_value_t *value ) { pmix_status_t rc = PMIX_SUCCESS; pmix_tma_t *const tma = pmix_obj_get_tma(&ht->super); // The value contains a pmix_data_array_t whose first position contains the // key-value being stored, followed by one or more qualifiers. pmix_info_t *const info = (pmix_info_t *)value->data.darray->array; const size_t ninfo = value->data.darray->size; // This does not need to use the TMA since its contents are later copied in // hash_store() using a TMA. This is just temporary storage. const size_t nquals = ninfo - 1; pmix_info_t *quals = pmix_bfrops_base_tma_info_create(nquals, tma); for (size_t i = 1; i < ninfo; i++) { pmix_bfrops_base_tma_info_qualifier(&quals[i - 1], tma); rc = pmix_bfrops_base_tma_info_xfer(&quals[i - 1], &info[i], tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); goto out; } } // Extract the primary value. pmix_kval_t *kv = PMIX_NEW(pmix_kval_t, tma); if (PMIX_UNLIKELY(!kv)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto out; } kv->key = info[0].key; kv->value = &info[0].value; // Store the result. rc = pmix_hash_store(ht, rank, kv, quals, nquals, NULL); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); } out: pmix_bfrops_base_tma_info_free(quals, nquals, tma); return rc; } pmix_status_t pmix_gds_shmem2_store_local_job_data_in_shmem2( pmix_gds_shmem2_job_t *job, pmix_list_t *job_data ) { pmix_status_t rc = PMIX_SUCCESS; pmix_hash_table_t *const local_ht = job->smdata->local_hashtab; pmix_tma_t *const tma = pmix_obj_get_tma(&local_ht->super); pmix_kval_t *kvi; PMIX_LIST_FOREACH (kvi, job_data, pmix_kval_t) { PMIX_GDS_SHMEM2_VVOUT("%s: key=%s", __func__, kvi->key); // We support the following data array keys. if (PMIX_CHECK_KEY(kvi, PMIX_APP_INFO_ARRAY)) { rc = store_app_array(job, kvi->value); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(kvi, PMIX_NODE_INFO_ARRAY)) { rc = store_node_array( kvi->value, job->smdata->nodeinfo ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(kvi, PMIX_PROC_INFO_ARRAY)) { rc = store_proc_data(job, kvi); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } } else if (PMIX_CHECK_KEY(kvi, PMIX_SESSION_INFO_ARRAY)) { rc = store_session_array(job, kvi->value); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); break; } } else { pmix_kval_t *kv = newkval(kvi->key, tma); if (PMIX_UNLIKELY(!kv)) { rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); break; } rc = pmix_bfrops_base_tma_value_xfer(kv->value, kvi->value, tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_RELEASE(kv); PMIX_ERROR_LOG(rc); break; } rc = pmix_hash_store( local_ht, PMIX_RANK_WILDCARD, kv, NULL, 0, NULL ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_RELEASE(kv); PMIX_ERROR_LOG(rc); break; } } } if (PMIX_SUCCESS == rc) { // Segments are ready for use. pmix_gds_shmem2_set_status( job, PMIX_GDS_SHMEM2_JOB_ID, PMIX_GDS_SHMEM2_READY_FOR_USE ); pmix_gds_shmem2_set_status( job, PMIX_GDS_SHMEM2_SESSION_ID, PMIX_GDS_SHMEM2_READY_FOR_USE ); } return rc; } /* * vim: ft=cpp ts=4 sts=4 sw=4 expandtab */ pmix-6.1.1~rc2/src/mca/gds/shmem2/Makefile.am0000664000175000017500000000462615203536752021040 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2022-2025 Nanook Consulting All rights reserved. # Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(gds_shmem2_CPPFLAGS) EXTRA_DIST = help-gds-shmem2.txt headers = \ gds_shmem2.h \ gds_shmem2_utils.h \ gds_shmem2_store.h \ gds_shmem2_fetch.h sources = \ gds_shmem2_component.c \ gds_shmem2.c \ gds_shmem2_utils.c \ gds_shmem2_store.c \ gds_shmem2_fetch.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_gds_shmem2_DSO lib = lib_sources = component = pmix_mca_gds_shmem2.la component_sources = $(headers) $(sources) else lib = libpmix_mca_gds_shmem2.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_gds_shmem2_la_SOURCES = $(component_sources) pmix_mca_gds_shmem2_la_LIBADD = $(gds_shmem2_LIBS) pmix_mca_gds_shmem2_la_LDFLAGS = -module -avoid-version $(gds_shmem2_LDFLAGS) if NEED_LIBPMIX pmix_mca_gds_shmem2_la_LIBADD += $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_gds_shmem2_la_SOURCES = $(lib_sources) libpmix_mca_gds_shmem2_la_LIBADD = $(gds_shmem2_LIBS) libpmix_mca_gds_shmem2_la_LDFLAGS = -module -avoid-version $(gds_shmem2_LDFLAGS) pmix-6.1.1~rc2/src/mca/gds/shmem2/gds_shmem2_utils.h0000664000175000017500000001235015203536752022416 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * Copyright (c) 2022-2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_GDS_SHMEM2_UTILS_H #define PMIX_GDS_SHMEM2_UTILS_H #include "gds_shmem2.h" #define PMIX_GDS_SHMEM2_OUT(...) \ do { \ pmix_output(0, "gds:" PMIX_GDS_SHMEM2_NAME ":" __VA_ARGS__); \ } while (0) #define PMIX_GDS_SHMEM2_VOUT(...) \ do { \ pmix_output_verbose(2, pmix_gds_base_framework.framework_output, \ "gds:" PMIX_GDS_SHMEM2_NAME ":" __VA_ARGS__); \ } while (0) #if PMIX_ENABLE_DEBUG #define PMIX_GDS_SHMEM2_VVOUT(...) \ do { \ pmix_output_verbose(8, pmix_gds_base_framework.framework_output, \ "gds:" PMIX_GDS_SHMEM2_NAME ":" __VA_ARGS__); \ } while (0) #define PMIX_GDS_SHMEM2_VVVOUT(...) \ do { \ pmix_output_verbose(9, pmix_gds_base_framework.framework_output, \ "gds:" PMIX_GDS_SHMEM2_NAME ":" __VA_ARGS__); \ } while (0) #else #define PMIX_GDS_SHMEM2_VVOUT(...) \ do { } while (0) #define PMIX_GDS_SHMEM2_VVVOUT(...) \ do { } while (0) #endif #define PMIX_GDS_SHMEM2_VVOUT_HERE() \ PMIX_GDS_SHMEM2_VVOUT("HERE AT %s,%d", __func__, __LINE__) BEGIN_C_DECLS PMIX_EXPORT pmix_status_t pmix_gds_shmem2_get_job_tracker( const pmix_nspace_t nspace, bool create, pmix_gds_shmem2_job_t **job ); PMIX_EXPORT pmix_gds_shmem2_session_t * pmix_gds_shmem2_get_session_tracker( pmix_gds_shmem2_job_t *job, uint32_t sid, bool create ); PMIX_EXPORT bool pmix_gds_shmem2_hostnames_eq( const char *h1, const char *h2 ); /** * Sets shmem2 to the appropriate pmix_shmem_t *. */ PMIX_EXPORT pmix_status_t pmix_gds_shmem2_get_job_shmem2_by_id( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, pmix_shmem_t **shmem2 ); PMIX_EXPORT void pmix_gds_shmem2_set_status( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, pmix_gds_shmem2_status_flag_t flag ); PMIX_EXPORT void pmix_gds_shmem2_clear_status( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, pmix_gds_shmem2_status_flag_t flag ); PMIX_EXPORT void pmix_gds_shmem2_clearall_status( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id ); PMIX_EXPORT bool pmix_gds_shmem2_has_status( pmix_gds_shmem2_job_t *job, pmix_gds_shmem2_job_shmem2_id_t shmem2_id, pmix_gds_shmem2_status_flag_t flag ); static inline pmix_tma_t * pmix_gds_shmem2_get_job_tma( pmix_gds_shmem2_job_t *job ) { return &job->smdata->tma; } static inline pmix_tma_t * pmix_gds_shmem2_get_session_tma( pmix_gds_shmem2_job_t *job ) { assert(job->session); if (!job->session) { return NULL; } return &job->session->smdata->tma; } static inline void pmix_gds_shmem2_vout_smdata( pmix_gds_shmem2_job_t *job ) { PMIX_GDS_SHMEM2_VOUT( "shmem2_hdr@%p, " "shmem2_data@%p, " "smdata tma@%p, " "jobinfo@%p, " "appinfo@%p, " "nodeinfo@%p, " "local_hashtab@%p", (void *)job->shmem2->hdr_address, (void *)job->shmem2->data_address, (void *)&job->smdata->tma, (void *)job->smdata->jobinfo, (void *)job->smdata->appinfo, (void *)job->smdata->nodeinfo, (void *)job->smdata->local_hashtab ); } static inline void pmix_gds_shmem2_vout_smmodex( pmix_gds_shmem2_job_t *job ) { PMIX_GDS_SHMEM2_VOUT( "modex_shmem2@%p, " "smmodex tma@%p, " "hashtab@%p", (void *)job->modex_shmem2->data_address, (void *)&job->smmodex->tma, (void *)job->smmodex->hashtab ); } static inline void pmix_gds_shmem2_vout_smsession( pmix_gds_shmem2_session_t *sesh ) { PMIX_GDS_SHMEM2_VOUT( "shmem2_hdr@%p, " "shmem2_data@%p, " "smdata tma@%p, " "sessioninfo@%p, " "nodeinfo@%p", (void *)sesh->shmem2->hdr_address, (void *)sesh->shmem2->data_address, (void *)&sesh->smdata->tma, (void *)sesh->smdata->sessioninfo, (void *)sesh->smdata->nodeinfo ); } END_C_DECLS #endif /* * vim: ft=cpp ts=4 sts=4 sw=4 expandtab */ pmix-6.1.1~rc2/src/mca/gds/base/0000775000175000017500000000000015203536752016513 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/gds/base/gds_base_fns.c0000664000175000017500000002321515203536752021277 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2018 IBM Corporation. All rights reserved. * Copyright (c) 2018-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/class/pmix_list.h" #include "src/mca/pcompress/pcompress.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_show_help.h" #include "src/mca/gds/base/base.h" #include "src/server/pmix_server_ops.h" char *pmix_gds_base_get_available_modules(void) { if (!pmix_gds_globals.initialized) { return NULL; } return strdup(pmix_gds_globals.all_mods); } /* Select a gds module per the given directives */ pmix_gds_base_module_t *pmix_gds_base_assign_module(pmix_info_t *info, size_t ninfo) { pmix_gds_base_active_module_t *active; pmix_gds_base_module_t *mod = NULL; int pri, priority = -1; if (!pmix_gds_globals.initialized) { return NULL; } PMIX_LIST_FOREACH (active, &pmix_gds_globals.actives, pmix_gds_base_active_module_t) { if (NULL == active->module->assign_module) { continue; } if (PMIX_SUCCESS == active->module->assign_module(info, ninfo, &pri)) { if (pri < 0) { /* use the default priority from the component */ pri = active->pri; } if (priority < pri) { mod = active->module; priority = pri; } } } return mod; } pmix_status_t pmix_gds_base_setup_fork(const pmix_proc_t *proc, char ***env) { pmix_gds_base_active_module_t *active; pmix_status_t rc; if (!pmix_gds_globals.initialized) { return PMIX_ERR_INIT; } PMIX_LIST_FOREACH (active, &pmix_gds_globals.actives, pmix_gds_base_active_module_t) { if (NULL == active->module->setup_fork) { continue; } rc = active->module->setup_fork(proc, env); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_AVAILABLE != rc) { return rc; } } return PMIX_SUCCESS; } pmix_status_t pmix_gds_base_store_modex(pmix_buffer_t *buff, pmix_gds_base_store_modex_cb_fn_t cb_fn, void *cbdata) { pmix_status_t rc = PMIX_SUCCESS; pmix_buffer_t bkt, bkt3; pmix_byte_object_t bo, bo3, bo4, wbo; int32_t cnt = 1; pmix_server_trkr_t *trk = (pmix_server_trkr_t *) cbdata; pmix_proc_t proc; pmix_buffer_t pbkt; bool compressed, decompressed, found; pmix_collect_t last_blob_info_byte, blob_info_byte; pmix_list_t nspaces; pmix_proclist_t *plist; PMIX_CONSTRUCT(&nspaces, pmix_list_t); last_blob_info_byte = PMIX_COLLECT_INVALID; PMIX_CONSTRUCT(&bkt, pmix_buffer_t); /* Loop over the enclosed byte object envelopes and * store them in our GDS module. There is a byte object * from each server involved in the operation. */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, buff, &bo, &cnt, PMIX_BYTE_OBJECT); /* If the collect flag is set, we should have some data for unpacking */ if ((PMIX_COLLECT_YES == trk->collect_type) && (PMIX_SUCCESS != rc)) { goto exit; } while (PMIX_SUCCESS == rc) { // setup to unpack the server-level blob PMIX_LOAD_BUFFER(pmix_globals.mypeer, &bkt, bo.bytes, bo.size); while (PMIX_SUCCESS == rc) { // each server contribution contains a compression flag followed by // a series of rank-level byte objects // first element is a bool indicating if the collection of rank-level // objects was compressed cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &compressed, &cnt, PMIX_BOOL); if (PMIX_SUCCESS != rc) { if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { // just indicates we reached the end, so silently break break; } PMIX_ERROR_LOG(rc); goto exit; } // unpack the byte object containing all the rank-level objects // provided by this server cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &bo3, &cnt, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } // decompress it if required if (compressed) { decompressed = pmix_compress.decompress((uint8_t**)&wbo.bytes, &wbo.size, (uint8_t*)bo3.bytes, bo3.size); if (decompressed) { PMIX_BYTE_OBJECT_DESTRUCT(&bo3); bo3.bytes = wbo.bytes; bo3.size = wbo.size; } } // set it up for unpacking PMIX_CONSTRUCT(&bkt3, pmix_buffer_t); PMIX_LOAD_BUFFER(pmix_globals.mypeer, &bkt3, bo3.bytes, bo3.size); // unpack the flag indicating if data was collected on that node cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt3, &blob_info_byte, &cnt, PMIX_BYTE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&bkt3); goto exit; } if (PMIX_COLLECT_INVALID == last_blob_info_byte) { last_blob_info_byte = blob_info_byte; } else if (last_blob_info_byte != blob_info_byte) { // we have a mismatch - report the error pmix_show_help("help-pmix-server.txt", "collection-mismatch", true); rc = PMIX_ERR_BAD_PARAM; PMIX_DESTRUCT(&bkt3); goto exit; } /* unpack the enclosed blobs from the various peers */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt3, &bo4, &cnt, PMIX_BYTE_OBJECT); while (PMIX_SUCCESS == rc) { /* unpack all the kval's from this peer and store them in * our GDS. Note that PMIx by design holds all data at * the server level until requested. If our GDS is a * shared memory region, then the data may be available * right away - but the client still has to be notified * of its presence. */ /* setup the byte object for unpacking */ PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); PMIX_LOAD_BUFFER(pmix_globals.mypeer, &pbkt, bo4.bytes, bo4.size); // unpack the proc that provided this data cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &pbkt, &proc, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); break; } // track the nspace involved found = false; PMIX_LIST_FOREACH(plist, &nspaces, pmix_proclist_t) { if (PMIX_CHECK_NSPACE(plist->proc.nspace, proc.nspace)) { found = true; break; } } if (!found) { plist = PMIX_NEW(pmix_proclist_t); PMIX_LOAD_NSPACE(plist->proc.nspace, proc.nspace); pmix_list_append(&nspaces, &plist->super); } // call the specific GDS component-provided function to store it rc = cb_fn(&proc, &pbkt); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); break; } PMIX_DESTRUCT(&pbkt); /* get the next peer-level blob */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt3, &bo4, &cnt, PMIX_BYTE_OBJECT); } PMIX_DESTRUCT(&bkt3); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { rc = PMIX_SUCCESS; } else if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } // prep for next cycle PMIX_DESTRUCT(&bkt); PMIX_CONSTRUCT(&bkt, pmix_buffer_t); /* unpack and process the next server-level blob */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, buff, &bo, &cnt, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS == rc) { PMIX_LOAD_BUFFER(pmix_globals.mypeer, &bkt, bo.bytes, bo.size); } } } if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { rc = PMIX_SUCCESS; } else if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto exit; } // indicate that we are done processing the modex - need to alert // for each nspace involved PMIX_LIST_FOREACH(plist, &nspaces, pmix_proclist_t) { rc = cb_fn(&plist->proc, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); break; } } exit: PMIX_DESTRUCT(&bkt); PMIX_LIST_DESTRUCT(&nspaces); return rc; } pmix-6.1.1~rc2/src/mca/gds/base/base.h0000664000175000017500000001000115203536752017566 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018 IBM Corporation. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_GDS_BASE_H_ #define PMIX_GDS_BASE_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/mca.h" #include "src/mca/gds/gds.h" BEGIN_C_DECLS /* * MCA Framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_gds_base_framework; /** * GDS select function * * Cycle across available components and construct the list * of active modules */ PMIX_EXPORT pmix_status_t pmix_gds_base_select(pmix_info_t info[], size_t ninfo); /** * Track an active component / module */ struct pmix_gds_base_active_module_t { pmix_list_item_t super; int pri; pmix_gds_base_module_t *module; pmix_gds_base_component_t *component; }; typedef struct pmix_gds_base_active_module_t pmix_gds_base_active_module_t; PMIX_CLASS_DECLARATION(pmix_gds_base_active_module_t); /* framework globals */ struct pmix_gds_globals_t { pmix_list_t actives; bool initialized; bool selected; char *all_mods; }; typedef enum { PMIX_MODEX_KEY_INVALID = -1, PMIX_MODEX_KEY_NATIVE_FMT, PMIX_MODEX_KEY_KEYMAP_FMT, PMIX_MODEX_KEY_MAX } pmix_gds_modex_key_fmt_t; /* define a modex blob info */ typedef uint8_t pmix_gds_modex_blob_info_t; #define PMIX_GDS_COLLECT_BIT 0x0001 #define PMIX_GDS_KEYMAP_BIT 0x0002 #define PMIX_GDS_KEYMAP_IS_SET(byte) (PMIX_GDS_KEYMAP_BIT & (byte)) #define PMIX_GDS_COLLECT_IS_SET(byte) (PMIX_GDS_COLLECT_BIT & (byte)) typedef struct pmix_gds_globals_t pmix_gds_globals_t; typedef pmix_status_t (*pmix_gds_base_store_modex_cb_fn_t)(pmix_proc_t *proc, pmix_buffer_t *pbkt); PMIX_EXPORT extern pmix_gds_globals_t pmix_gds_globals; /* get a list of available support - caller must free results * when done. The list is returned as a comma-delimited string * of available components in priority order */ PMIX_EXPORT char *pmix_gds_base_get_available_modules(void); /* Select a gds module based on the provided directives */ PMIX_EXPORT pmix_gds_base_module_t *pmix_gds_base_assign_module(pmix_info_t *info, size_t ninfo); /** * Add any envars to a peer's environment that the module needs * to communicate. The API stub will rotate across all active modules, giving * each a chance to contribute * * @return PMIX_SUCCESS on success. */ PMIX_EXPORT pmix_status_t pmix_gds_base_setup_fork(const pmix_proc_t *proc, char ***env); PMIX_EXPORT pmix_status_t pmix_gds_base_store_modex(pmix_buffer_t *buff, pmix_gds_base_store_modex_cb_fn_t cb_fn, void *cbdata); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/gds/base/Makefile.include0000664000175000017500000000221315203536752021573 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2017 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from # src/Makefile.am headers += \ base/base.h sources += \ base/gds_base_frame.c \ base/gds_base_select.c \ base/gds_base_fns.c pmix-6.1.1~rc2/src/mca/gds/base/gds_base_frame.c0000664000175000017500000000663215203536752021607 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2009 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/util/pmix_argv.h" #include "src/mca/base/pmix_base.h" #include "src/mca/gds/base/base.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public mca_base_component_t struct. */ #include "src/mca/gds/base/static-components.h" /* Instantiate the global vars */ pmix_gds_globals_t pmix_gds_globals = { .actives = PMIX_LIST_STATIC_INIT, .initialized = false, .selected = false, .all_mods = NULL }; int pmix_gds_base_output = -1; static pmix_status_t pmix_gds_close(void) { pmix_gds_base_active_module_t *active, *prev; if (!pmix_gds_globals.initialized) { return PMIX_SUCCESS; } pmix_gds_globals.initialized = false; pmix_gds_globals.selected = false; PMIX_LIST_FOREACH_SAFE (active, prev, &pmix_gds_globals.actives, pmix_gds_base_active_module_t) { pmix_list_remove_item(&pmix_gds_globals.actives, &active->super); if (NULL != active->module->finalize) { active->module->finalize(); } PMIX_RELEASE(active); } PMIX_DESTRUCT(&pmix_gds_globals.actives); if (NULL != pmix_gds_globals.all_mods) { free(pmix_gds_globals.all_mods); } return pmix_mca_base_framework_components_close(&pmix_gds_base_framework, NULL); } static pmix_status_t pmix_gds_open(pmix_mca_base_open_flag_t flags) { pmix_status_t rc; /* initialize globals */ pmix_gds_globals.initialized = true; pmix_gds_globals.all_mods = NULL; PMIX_CONSTRUCT(&pmix_gds_globals.actives, pmix_list_t); /* Open up all available components */ rc = pmix_mca_base_framework_components_open(&pmix_gds_base_framework, flags); pmix_gds_base_output = pmix_gds_base_framework.framework_output; return rc; } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, gds, "PMIx Generalized Data Store", NULL, pmix_gds_open, pmix_gds_close, pmix_mca_gds_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); PMIX_CLASS_INSTANCE(pmix_gds_base_active_module_t, pmix_list_item_t, NULL, NULL); pmix-6.1.1~rc2/src/mca/gds/base/gds_base_select.c0000664000175000017500000001270515203536752021772 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_show_help.h" #include "src/mca/gds/base/base.h" /* Function for selecting a prioritized list of components * from all those that are available. */ int pmix_gds_base_select(pmix_info_t info[], size_t ninfo) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_mca_base_component_t *component = NULL; pmix_mca_base_module_t *module = NULL; pmix_gds_base_module_t *nmodule; pmix_gds_base_active_module_t *newmodule, *mod; int rc, priority; bool inserted; char **mods = NULL; if (pmix_gds_globals.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_gds_globals.selected = true; /* Query all available components and ask if they have a module */ PMIX_LIST_FOREACH (cli, &pmix_gds_base_framework.framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_mca_base_component_t *) cli->cli_component; pmix_output_verbose(5, pmix_gds_base_framework.framework_output, "mca:gds:select: checking available component %s", component->pmix_mca_component_name); /* If there's no query function, skip it */ if (NULL == component->pmix_mca_query_component) { pmix_output_verbose( 5, pmix_gds_base_framework.framework_output, "mca:gds:select: Skipping component [%s]. It does not implement a query function", component->pmix_mca_component_name); continue; } /* Query the component */ pmix_output_verbose(5, pmix_gds_base_framework.framework_output, "mca:gds:select: Querying component [%s]", component->pmix_mca_component_name); rc = component->pmix_mca_query_component(&module, &priority); /* If no module was returned, then skip component */ if (PMIX_SUCCESS != rc || NULL == module) { pmix_output_verbose( 5, pmix_gds_base_framework.framework_output, "mca:gds:select: Skipping component [%s]. Query failed to return a module", component->pmix_mca_component_name); continue; } /* If we got a module, keep it */ nmodule = (pmix_gds_base_module_t *) module; /* let it initialize */ if (NULL != nmodule->init && PMIX_SUCCESS != nmodule->init(info, ninfo)) { continue; } /* add to the list of selected modules */ newmodule = PMIX_NEW(pmix_gds_base_active_module_t); newmodule->pri = priority; newmodule->module = nmodule; newmodule->component = (pmix_gds_base_component_t *) cli->cli_component; /* maintain priority order */ inserted = false; PMIX_LIST_FOREACH (mod, &pmix_gds_globals.actives, pmix_gds_base_active_module_t) { if (priority > mod->pri) { pmix_list_insert_pos(&pmix_gds_globals.actives, (pmix_list_item_t *) mod, &newmodule->super); inserted = true; break; } } if (!inserted) { /* must be lowest priority - add to end */ pmix_list_append(&pmix_gds_globals.actives, &newmodule->super); } } /* if no modules were found, then that's an error as we require at least one */ if (0 == pmix_list_get_size(&pmix_gds_globals.actives)) { pmix_show_help("help-pmix-runtime.txt", "no-plugins", true, "GDS"); return PMIX_ERR_SILENT; } /* setup the list of all module names */ PMIX_LIST_FOREACH (mod, &pmix_gds_globals.actives, pmix_gds_base_active_module_t) { PMIx_Argv_append_nosize(&mods, mod->module->name); } pmix_gds_globals.all_mods = PMIx_Argv_join(mods, ','); PMIx_Argv_free(mods); if (4 < pmix_output_get_verbosity(pmix_gds_base_framework.framework_output)) { pmix_output(0, "Final gds priorities"); /* show the prioritized list */ PMIX_LIST_FOREACH (mod, &pmix_gds_globals.actives, pmix_gds_base_active_module_t) { pmix_output(0, "\tgds: %s Priority: %d", mod->component->pmix_mca_component_name, mod->pri); } } return PMIX_SUCCESS; ; } pmix-6.1.1~rc2/src/mca/gds/hash/0000775000175000017500000000000015203536752016524 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/gds/hash/gds_hash_component.c0000664000175000017500000001225715203536752022541 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/class/pmix_hash_table.h" #include "src/util/pmix_hash.h" #include "gds_hash.h" #include "src/mca/gds/gds.h" static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_gds_hash_component_t pmix_mca_gds_hash_component = { .super = { PMIX_GDS_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "hash", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_query_component = component_query, .reserved = {0} }, .mysessions = PMIX_LIST_STATIC_INIT, .myjobs = PMIX_LIST_STATIC_INIT }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, gds, hash) static int component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 10; *module = (pmix_mca_base_module_t *) &pmix_hash_module; return PMIX_SUCCESS; } /**********************************************/ /* class instantiations */ static void scon(pmix_session_t *s) { s->session = UINT32_MAX; PMIX_CONSTRUCT(&s->sessioninfo, pmix_list_t); PMIX_CONSTRUCT(&s->nodeinfo, pmix_list_t); } static void sdes(pmix_session_t *s) { PMIX_LIST_DESTRUCT(&s->sessioninfo); PMIX_LIST_DESTRUCT(&s->nodeinfo); } PMIX_CLASS_INSTANCE(pmix_session_t, pmix_list_item_t, scon, sdes); static void htcon(pmix_job_t *p) { p->ns = NULL; p->nptr = NULL; PMIX_CONSTRUCT(&p->jobinfo, pmix_list_t); PMIX_CONSTRUCT(&p->internal, pmix_hash_table_t); pmix_hash_table_init(&p->internal, 256); p->internal.ht_label = "internal"; PMIX_CONSTRUCT(&p->remote, pmix_hash_table_t); pmix_hash_table_init(&p->remote, 256); p->remote.ht_label = "remote"; PMIX_CONSTRUCT(&p->local, pmix_hash_table_t); pmix_hash_table_init(&p->local, 256); p->local.ht_label = "local"; p->gdata_added = false; PMIX_CONSTRUCT(&p->apps, pmix_list_t); PMIX_CONSTRUCT(&p->nodeinfo, pmix_list_t); p->session = NULL; } static void htdes(pmix_job_t *p) { if (NULL != p->ns) { free(p->ns); } if (NULL != p->nptr) { PMIX_RELEASE(p->nptr); } PMIX_LIST_DESTRUCT(&p->jobinfo); pmix_hash_remove_data(&p->internal, PMIX_RANK_WILDCARD, NULL, NULL); PMIX_DESTRUCT(&p->internal); pmix_hash_remove_data(&p->remote, PMIX_RANK_WILDCARD, NULL, NULL); PMIX_DESTRUCT(&p->remote); pmix_hash_remove_data(&p->local, PMIX_RANK_WILDCARD, NULL, NULL); PMIX_DESTRUCT(&p->local); PMIX_LIST_DESTRUCT(&p->apps); PMIX_LIST_DESTRUCT(&p->nodeinfo); if (NULL != p->session) { PMIX_RELEASE(p->session); } } PMIX_CLASS_INSTANCE(pmix_job_t, pmix_list_item_t, htcon, htdes); static void apcon(pmix_apptrkr_t *p) { p->appnum = 0; PMIX_CONSTRUCT(&p->appinfo, pmix_list_t); PMIX_CONSTRUCT(&p->nodeinfo, pmix_list_t); p->job = NULL; } static void apdes(pmix_apptrkr_t *p) { PMIX_LIST_DESTRUCT(&p->appinfo); PMIX_LIST_DESTRUCT(&p->nodeinfo); } PMIX_CLASS_INSTANCE(pmix_apptrkr_t, pmix_list_item_t, apcon, apdes); static void ndinfocon(pmix_nodeinfo_t *p) { p->nodeid = UINT32_MAX; p->hostname = NULL; p->aliases = NULL; PMIX_CONSTRUCT(&p->info, pmix_list_t); } static void ndinfodes(pmix_nodeinfo_t *p) { if (NULL != p->hostname) { free(p->hostname); } if (NULL != p->aliases) { PMIx_Argv_free(p->aliases); } PMIX_LIST_DESTRUCT(&p->info); } PMIX_CLASS_INSTANCE(pmix_nodeinfo_t, pmix_list_item_t, ndinfocon, ndinfodes); pmix-6.1.1~rc2/src/mca/gds/hash/process_arrays.c0000664000175000017500000004704115203536752021735 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Mellanox Technologies, Inc. * All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/pcompress/base/base.h" #include "src/mca/pmdl/pmdl.h" #include "src/mca/preg/preg.h" #include "src/mca/ptl/base/base.h" #include "src/runtime/pmix_rte.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_hash.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_net.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "gds_hash.h" #include "src/mca/gds/base/base.h" /* process a node array - contains an array of * node-level info for a single node. Either the * nodeid, hostname, or both must be included * in the array to identify the node */ pmix_status_t pmix_gds_hash_process_node_array(pmix_value_t *val, pmix_list_t *tgt) { size_t size, j, n; pmix_info_t *iptr; pmix_status_t rc = PMIX_SUCCESS; pmix_kval_t *kp2, *k1; pmix_list_t cache; pmix_nodeinfo_t *nd = NULL, *ndptr; bool update; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "PROCESSING NODE ARRAY"); /* array of node-level info for a specific node */ if (PMIX_DATA_ARRAY != val->type) { PMIX_ERROR_LOG(PMIX_ERR_TYPE_MISMATCH); return PMIX_ERR_TYPE_MISMATCH; } /* setup arrays */ size = val->data.darray->size; iptr = (pmix_info_t *) val->data.darray->array; PMIX_CONSTRUCT(&cache, pmix_list_t); /* cache the values while searching for the nodeid * and/or hostname */ for (j = 0; j < size; j++) { pmix_output_verbose(12, pmix_gds_base_framework.framework_output, "%s gds:hash:node_array for key %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIx_Get_attribute_name(iptr[j].key)); if (PMIX_CHECK_KEY(&iptr[j], PMIX_NODEID)) { if (NULL == nd) { nd = PMIX_NEW(pmix_nodeinfo_t); } rc = PMIx_Value_get_number(&iptr[j].value, &nd->nodeid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(nd); PMIX_LIST_DESTRUCT(&cache); return rc; } } else if (PMIX_CHECK_KEY(&iptr[j], PMIX_HOSTNAME)) { if (NULL == nd) { nd = PMIX_NEW(pmix_nodeinfo_t); } nd->hostname = strdup(iptr[j].value.data.string); } else if (PMIX_CHECK_KEY(&iptr[j], PMIX_HOSTNAME_ALIASES)) { if (NULL == nd) { nd = PMIX_NEW(pmix_nodeinfo_t); } nd->aliases = PMIx_Argv_split(iptr[j].value.data.string, ','); /* need to cache this value as well */ kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(iptr[j].key); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_XFER(rc, kp2->value, &iptr[j].value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); PMIX_RELEASE(nd); PMIX_LIST_DESTRUCT(&cache); return rc; } pmix_list_append(&cache, &kp2->super); } else { kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(iptr[j].key); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_XFER(rc, kp2->value, &iptr[j].value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); if (NULL != nd) { PMIX_RELEASE(nd); } PMIX_LIST_DESTRUCT(&cache); return rc; } pmix_list_append(&cache, &kp2->super); } } if (NULL == nd) { /* they forgot to pass us the ident for the node */ PMIX_LIST_DESTRUCT(&cache); return PMIX_ERR_BAD_PARAM; } if (NULL != nd->hostname) { pmix_set_aliases(&nd->aliases, nd->hostname); } /* see if we already have this node on the * provided list */ update = false; PMIX_LIST_FOREACH (ndptr, tgt, pmix_nodeinfo_t) { if (UINT32_MAX != ndptr->nodeid && UINT32_MAX != nd->nodeid) { if (ndptr->nodeid == nd->nodeid) { if (NULL == ndptr->hostname && NULL != nd->hostname) { ndptr->hostname = strdup(nd->hostname); } if (NULL != nd->aliases) { for (n=0; NULL != nd->aliases[n]; n++) { PMIx_Argv_append_unique_nosize(&ndptr->aliases, nd->aliases[n]); } } PMIX_RELEASE(nd); nd = ndptr; update = true; break; } } else if (NULL != ndptr->hostname && NULL != nd->hostname) { if (0 == strcmp(ndptr->hostname, nd->hostname)) { if (UINT32_MAX == ndptr->nodeid && UINT32_MAX != nd->nodeid) { ndptr->nodeid = nd->nodeid; } if (NULL != nd->aliases) { for (n=0; NULL != nd->aliases[n]; n++) { PMIx_Argv_append_unique_nosize(&ndptr->aliases, nd->aliases[n]); } } PMIX_RELEASE(nd); nd = ndptr; update = true; break; } } } if (!update) { pmix_list_append(tgt, &nd->super); } /* transfer the cached items to the nodeinfo list */ kp2 = (pmix_kval_t *) pmix_list_remove_first(&cache); while (NULL != kp2) { /* if this is an update, we have to ensure each data * item only appears once on the list */ if (update) { PMIX_LIST_FOREACH (k1, &nd->info, pmix_kval_t) { if (PMIX_CHECK_KEY(k1, kp2->key)) { pmix_list_remove_item(&nd->info, &k1->super); PMIX_RELEASE(k1); break; } } } pmix_list_append(&nd->info, &kp2->super); kp2 = (pmix_kval_t *) pmix_list_remove_first(&cache); } PMIX_LIST_DESTRUCT(&cache); return PMIX_SUCCESS; } /* process an app array - contains an array of * app-level info for a single app. If the * appnum is not included in the array, then * it is assumed that only one app is in the job. * This assumption is checked and generates * an error if violated */ pmix_status_t pmix_gds_hash_process_app_array(pmix_value_t *val, pmix_job_t *trk) { pmix_list_t cache, ncache; size_t size, j; pmix_info_t *iptr; pmix_status_t rc = PMIX_SUCCESS; uint32_t appnum; pmix_apptrkr_t *app = NULL, *apptr; pmix_kval_t *kp2, *k1; pmix_nodeinfo_t *nd; bool update; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "PROCESSING APP ARRAY"); /* apps have to belong to a job */ if (NULL == trk) { return PMIX_ERR_BAD_PARAM; } /* array of app-level info */ if (PMIX_DATA_ARRAY != val->type) { PMIX_ERROR_LOG(PMIX_ERR_TYPE_MISMATCH); return PMIX_ERR_TYPE_MISMATCH; } /* setup arrays and lists */ PMIX_CONSTRUCT(&cache, pmix_list_t); PMIX_CONSTRUCT(&ncache, pmix_list_t); size = val->data.darray->size; iptr = (pmix_info_t *) val->data.darray->array; for (j = 0; j < size; j++) { pmix_output_verbose(12, pmix_gds_base_framework.framework_output, "%s gds:hash:app_array for key %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIx_Get_attribute_name(iptr[j].key)); if (PMIX_CHECK_KEY(&iptr[j], PMIX_APPNUM)) { rc = PMIx_Value_get_number(&iptr[j].value, &appnum, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } if (NULL != app) { /* this is an error - there can be only one app * described in this array */ PMIX_RELEASE(app); PMIX_LIST_DESTRUCT(&cache); PMIX_LIST_DESTRUCT(&ncache); return PMIX_ERR_BAD_PARAM; } app = PMIX_NEW(pmix_apptrkr_t); app->appnum = appnum; } else if (PMIX_CHECK_KEY(&iptr[j], PMIX_NODE_INFO_ARRAY)) { if (PMIX_SUCCESS != (rc = pmix_gds_hash_process_node_array(&iptr[j].value, &ncache))) { PMIX_ERROR_LOG(rc); goto release; } } else { kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(iptr[j].key); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_XFER(rc, kp2->value, &iptr[j].value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); goto release; } pmix_list_append(&cache, &kp2->super); } } if (NULL == app) { /* per the standard, they don't have to provide us with * an appnum so long as only one app is in the job */ if (0 == pmix_list_get_size(&trk->apps)) { app = PMIX_NEW(pmix_apptrkr_t); app->appnum = 0; } else { /* this is not allowed to happen - they are required * to provide us with an app number per the standard */ rc = PMIX_ERR_BAD_PARAM; PMIX_ERROR_LOG(rc); goto release; } } /* see if we already have this app on the * provided list */ update = false; PMIX_LIST_FOREACH (apptr, &trk->apps, pmix_apptrkr_t) { if (apptr->appnum == app->appnum) { /* we assume that the data is updating the current * values */ PMIX_RELEASE(app); app = apptr; update = true; break; } } if (!update) { pmix_list_append(&trk->apps, &app->super); } /* point the app at its job */ if (NULL == app->job) { /* do NOT retain the tracker - we will not release * it in the app destructor. If we retain the tracker, * then we won't release it later because the refcount * is wrong */ app->job = trk; } /* transfer the app-level data across */ kp2 = (pmix_kval_t *) pmix_list_remove_first(&cache); while (NULL != kp2) { /* if this is an update, we have to ensure each data * item only appears once on the list */ if (update) { PMIX_LIST_FOREACH (k1, &app->appinfo, pmix_kval_t) { if (PMIX_CHECK_KEY(k1, kp2->key)) { pmix_list_remove_item(&app->appinfo, &k1->super); PMIX_RELEASE(k1); break; } } } if (PMIX_CHECK_KEY(kp2, PMIX_MODEL_LIBRARY_NAME) || PMIX_CHECK_KEY(kp2, PMIX_PROGRAMMING_MODEL) || PMIX_CHECK_KEY(kp2, PMIX_MODEL_LIBRARY_VERSION) || PMIX_CHECK_KEY(kp2, PMIX_PERSONALITY)) { // pass this info to the pmdl framework pmix_pmdl.setup_nspace_kv(trk->nptr, kp2); } pmix_list_append(&app->appinfo, &kp2->super); kp2 = (pmix_kval_t *) pmix_list_remove_first(&cache); } /* transfer the associated node-level data across */ nd = (pmix_nodeinfo_t *) pmix_list_remove_first(&ncache); while (NULL != nd) { pmix_list_append(&app->nodeinfo, &nd->super); nd = (pmix_nodeinfo_t *) pmix_list_remove_first(&ncache); } release: PMIX_LIST_DESTRUCT(&cache); PMIX_LIST_DESTRUCT(&ncache); return rc; } /* process a job array */ pmix_status_t pmix_gds_hash_process_job_array(pmix_info_t *info, pmix_job_t *trk, uint32_t *flags, char ***procs, char ***nodes) { pmix_list_t cache; size_t j, size; pmix_info_t *iptr; pmix_kval_t *kp2; pmix_status_t rc; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "PROCESSING JOB ARRAY"); /* array of job-level info */ if (PMIX_DATA_ARRAY != info->value.type) { PMIX_ERROR_LOG(PMIX_ERR_TYPE_MISMATCH); return PMIX_ERR_TYPE_MISMATCH; } size = info->value.data.darray->size; iptr = (pmix_info_t *) info->value.data.darray->array; PMIX_CONSTRUCT(&cache, pmix_list_t); for (j = 0; j < size; j++) { pmix_output_verbose(12, pmix_gds_base_framework.framework_output, "%s gds:hash:job_array for key %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIx_Get_attribute_name(iptr[j].key)); if (PMIX_CHECK_KEY(&iptr[j], PMIX_APP_INFO_ARRAY)) { if (PMIX_SUCCESS != (rc = pmix_gds_hash_process_app_array(&iptr[j].value, trk))) { return rc; } } else if (PMIX_CHECK_KEY(&iptr[j], PMIX_NODE_INFO_ARRAY)) { if (PMIX_SUCCESS != (rc = pmix_gds_hash_process_node_array(&iptr[j].value, &trk->nodeinfo))) { PMIX_ERROR_LOG(rc); return rc; } } else if (PMIX_CHECK_KEY(&iptr[j], PMIX_PROC_MAP)) { /* not allowed to get this more than once */ if (*flags & PMIX_HASH_PROC_MAP) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* parse the regex to get the argv array containing proc ranks on each node */ if (PMIX_SUCCESS != (rc = pmix_preg.parse_procs(iptr[j].value.data.bo.bytes, procs))) { PMIX_ERROR_LOG(rc); return rc; } /* mark that we got the map */ *flags |= PMIX_HASH_PROC_MAP; } else if (PMIX_CHECK_KEY(&iptr[j], PMIX_NODE_MAP)) { /* not allowed to get this more than once */ if (*flags & PMIX_HASH_NODE_MAP) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* parse the regex to get the argv array of node names */ if (PMIX_SUCCESS != (rc = pmix_preg.parse_nodes(iptr[j].value.data.bo.bytes, nodes))) { PMIX_ERROR_LOG(rc); return rc; } /* mark that we got the map */ *flags |= PMIX_HASH_NODE_MAP; } else if (PMIX_CHECK_KEY(&iptr[j], PMIX_MODEL_LIBRARY_NAME) || PMIX_CHECK_KEY(&iptr[j], PMIX_PROGRAMMING_MODEL) || PMIX_CHECK_KEY(&iptr[j], PMIX_MODEL_LIBRARY_VERSION) || PMIX_CHECK_KEY(&iptr[j], PMIX_PERSONALITY)) { // pass this info to the pmdl framework pmix_pmdl.setup_nspace(trk->nptr, &iptr[j]); } else { kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(iptr[j].key); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_XFER(rc, kp2->value, &iptr[j].value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kp2); PMIX_LIST_DESTRUCT(&cache); return rc; } pmix_list_append(&trk->jobinfo, &kp2->super); /* check for job size */ if (PMIX_CHECK_KEY(&iptr[j], PMIX_JOB_SIZE)) { if (!(PMIX_HASH_JOB_SIZE & *flags)) { trk->nptr->nprocs = iptr[j].value.data.uint32; *flags |= PMIX_HASH_JOB_SIZE; } } else { pmix_iof_check_flags(&iptr[j], &trk->nptr->iof_flags); } } } return PMIX_SUCCESS; } pmix_status_t pmix_gds_hash_process_session_array(pmix_value_t *val, pmix_job_t *trk) { pmix_session_t *sptr = NULL; size_t j, size; pmix_info_t *iptr; pmix_list_t ncache, scache; pmix_status_t rc; pmix_kval_t *kp2; pmix_nodeinfo_t *nd; uint32_t sid = UINT32_MAX; /* array of session-level info */ if (PMIX_DATA_ARRAY != val->type) { PMIX_ERROR_LOG(PMIX_ERR_TYPE_MISMATCH); return PMIX_ERR_TYPE_MISMATCH; } size = val->data.darray->size; iptr = (pmix_info_t *) val->data.darray->array; PMIX_CONSTRUCT(&ncache, pmix_list_t); PMIX_CONSTRUCT(&scache, pmix_list_t); for (j = 0; j < size; j++) { pmix_output_verbose(12, pmix_gds_base_framework.framework_output, "%s gds:hash:session_array for key %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIx_Get_attribute_name(iptr[j].key)); if (PMIX_CHECK_KEY(&iptr[j], PMIX_SESSION_ID)) { rc = PMIx_Value_get_number(&iptr[j].value, &sid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_LIST_DESTRUCT(&ncache); PMIX_LIST_DESTRUCT(&scache); return rc; } sptr = pmix_gds_hash_check_session(trk, sid, true); } else if (PMIX_CHECK_KEY(&iptr[j], PMIX_NODE_INFO_ARRAY)) { if (PMIX_SUCCESS != (rc = pmix_gds_hash_process_node_array(&iptr[j].value, &ncache))) { PMIX_ERROR_LOG(rc); PMIX_LIST_DESTRUCT(&ncache); PMIX_LIST_DESTRUCT(&scache); return rc; } } else { kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(iptr[j].key); kp2->value = (pmix_value_t*)malloc(sizeof(pmix_value_t)); PMIX_VALUE_XFER(rc, kp2->value, &iptr[j].value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); PMIX_LIST_DESTRUCT(&ncache); PMIX_LIST_DESTRUCT(&scache); return rc; } pmix_list_append(&scache, &kp2->super); } } /* if we never got a session ID, then that's an error */ if (NULL == sptr) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_LIST_DESTRUCT(&ncache); PMIX_LIST_DESTRUCT(&scache); return PMIX_ERR_BAD_PARAM; } /* transfer across the results */ kp2 = (pmix_kval_t*)pmix_list_remove_first(&scache); while (NULL != kp2) { pmix_list_append(&sptr->sessioninfo, &kp2->super); kp2 = (pmix_kval_t*)pmix_list_remove_first(&scache); } PMIX_LIST_DESTRUCT(&scache); nd = (pmix_nodeinfo_t*)pmix_list_remove_first(&ncache); while (NULL != nd) { pmix_list_append(&sptr->nodeinfo, &nd->super); nd = (pmix_nodeinfo_t*)pmix_list_remove_first(&ncache); } PMIX_LIST_DESTRUCT(&ncache); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/gds/hash/gds_utils.c0000664000175000017500000005352415203536752020676 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/pcompress/base/base.h" #include "src/mca/pmdl/pmdl.h" #include "src/mca/preg/preg.h" #include "src/mca/ptl/base/base.h" #include "src/runtime/pmix_rte.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_hash.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_net.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "gds_hash.h" #include "src/mca/gds/base/base.h" pmix_job_t *pmix_gds_hash_get_tracker(const pmix_nspace_t nspace, bool create) { pmix_job_t *trk, *t; pmix_namespace_t *ns, *nptr; /* find the hash table for this nspace */ trk = NULL; PMIX_LIST_FOREACH (t, &pmix_mca_gds_hash_component.myjobs, pmix_job_t) { if (0 == strcmp(nspace, t->ns)) { trk = t; break; } } if (NULL == trk && create) { /* create one */ trk = PMIX_NEW(pmix_job_t); trk->ns = strdup(nspace); /* see if we already have this nspace */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(ns->nspace, nspace)) { nptr = ns; break; } } if (NULL == nptr) { nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { PMIX_RELEASE(trk); return NULL; } nptr->nspace = strdup(nspace); pmix_list_append(&pmix_globals.nspaces, &nptr->super); } PMIX_RETAIN(nptr); trk->nptr = nptr; pmix_list_append(&pmix_mca_gds_hash_component.myjobs, &trk->super); } return trk; } bool pmix_gds_hash_check_hostname(char *h1, char *h2) { if (0 == strcmp(h1, h2)) { return true; } return false; } bool pmix_gds_hash_check_node(pmix_nodeinfo_t *n1, pmix_nodeinfo_t *n2) { int i, j; if (UINT32_MAX != n1->nodeid && UINT32_MAX != n2->nodeid && n1->nodeid == n2->nodeid) { return true; } if (NULL == n1->hostname || NULL == n2->hostname) { return false; } if (pmix_gds_hash_check_hostname(n1->hostname, n2->hostname)) { return true; } if (NULL != n1->aliases) { for (i = 0; NULL != n1->aliases[i]; i++) { if (pmix_gds_hash_check_hostname(n1->aliases[i], n2->hostname)) { return true; } if (NULL != n2->aliases) { for (j = 0; NULL != n2->aliases[j]; j++) { if (pmix_gds_hash_check_hostname(n1->hostname, n2->aliases[j])) { return true; } if (pmix_gds_hash_check_hostname(n1->aliases[i], n2->aliases[j])) { return true; } } } } } else if (NULL != n2->aliases) { for (j = 0; NULL != n2->aliases[j]; j++) { if (pmix_gds_hash_check_hostname(n1->hostname, n2->aliases[j])) { return true; } } } return false; } pmix_session_t* pmix_gds_hash_check_session(pmix_job_t *trk, uint32_t sid, bool create) { pmix_session_t *sptr; bool found; /* if the tracker is NULL, then they are asking for the * session tracker for a specific sid (which can be UINT32_MAX) */ if (NULL == trk) { PMIX_LIST_FOREACH(sptr, &pmix_mca_gds_hash_component.mysessions, pmix_session_t) { if (sptr->session == sid) { return sptr; } } /* if it wasn't found, then add it if permitted */ if (create) { sptr = PMIX_NEW(pmix_session_t); sptr->session = sid; pmix_list_append(&pmix_mca_gds_hash_component.mysessions, &sptr->super); return sptr; } else { /* we didn't find it */ return NULL; } } if (NULL == trk->session) { /* no session has been assigned to this job - see * if the given ID has already been registered */ found = false; PMIX_LIST_FOREACH(sptr, &pmix_mca_gds_hash_component.mysessions, pmix_session_t) { if (sptr->session == sid) { found = true; break; } } if (found) { /* point the job tracker at this session */ PMIX_RETAIN(sptr); trk->session = sptr; return sptr; } /* if it wasn't found, then create it if permitted */ if (create) { sptr = PMIX_NEW(pmix_session_t); sptr->session = sid; PMIX_RETAIN(sptr); trk->session = sptr; pmix_list_append(&pmix_mca_gds_hash_component.mysessions, &sptr->super); return sptr; } else { return NULL; } } /* if the current session object is pointing to the default * global session and we were given a specific session ID, * then update it */ if (UINT32_MAX == trk->session->session) { if (UINT32_MAX == sid) { /* if the given sid is also UINT32_MAX, then we just add to it */ return trk->session; } /* see if the given ID has already been registered */ found = false; PMIX_LIST_FOREACH(sptr, &pmix_mca_gds_hash_component.mysessions, pmix_session_t) { if (sptr->session == sid) { found = true; break; } } if (found) { /* update the refcount on the current session object */ PMIX_RELEASE(trk->session); /* point the job tracker at the new place */ PMIX_RETAIN(sptr); trk->session = sptr; return sptr; } /* if it wasn't found, then create it */ if (create) { sptr = PMIX_NEW(pmix_session_t); sptr->session = sid; PMIX_RETAIN(sptr); trk->session = sptr; pmix_list_append(&pmix_mca_gds_hash_component.mysessions, &sptr->super); return sptr; } } else if (UINT32_MAX == sid) { /* it's a wildcard request, so return the job-tracker session */ return trk->session; } /* the job tracker already was assigned a session ID - check * if the new one matches */ if (trk->session->session != sid) { /* this is an error - you cannot assign a given job * to multiple sessions */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return NULL; } /* the two must match, so return it */ sptr = trk->session; return sptr; } pmix_nodeinfo_t* pmix_gds_hash_check_nodename(pmix_list_t *nodes, char *hostname) { int i; pmix_nodeinfo_t *nd; bool aliases_exist = false; if (NULL == hostname) { return NULL; } /* first, just check all the node names as this is the * most likely match */ PMIX_LIST_FOREACH (nd, nodes, pmix_nodeinfo_t) { if (0 == strcmp(nd->hostname, hostname)) { return nd; } if (NULL != nd->aliases) { aliases_exist = true; } } if (!aliases_exist) { return NULL; } /* if a match wasn't found, then we have to try the aliases */ PMIX_LIST_FOREACH (nd, nodes, pmix_nodeinfo_t) { if (NULL != nd->aliases) { for (i = 0; NULL != nd->aliases[i]; i++) { if (0 == strcmp(nd->aliases[i], hostname)) { return nd; } } } } /* no match was found */ return NULL; } pmix_status_t pmix_gds_hash_store_map(pmix_job_t *trk, char **nodes, char **ppn, uint32_t flags) { pmix_status_t rc; size_t m, n; pmix_rank_t rank; pmix_kval_t *kp1, *kp2; char **procs; uint32_t totalprocs = 0; pmix_hash_table_t *ht = &trk->internal; pmix_nodeinfo_t *nd; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map", pmix_globals.myid.nspace, pmix_globals.myid.rank); /* if the lists don't match, then that's wrong */ if (PMIx_Argv_count(nodes) != PMIx_Argv_count(ppn)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* if they didn't provide the number of nodes, then * compute it from the list of nodes */ if (!(PMIX_HASH_NUM_NODES & flags)) { kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(PMIX_NUM_NODES); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); kp2->value->type = PMIX_UINT32; kp2->value->data.uint32 = PMIx_Argv_count(nodes); pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map adding key %s to job info", pmix_globals.myid.nspace, pmix_globals.myid.rank, kp2->key); if (PMIX_SUCCESS != (rc = pmix_hash_store(ht, PMIX_RANK_WILDCARD, kp2, NULL, 0, NULL))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); return rc; } PMIX_RELEASE(kp2); // maintain acctg } for (n = 0; NULL != nodes[n]; n++) { /* check and see if we already have this node */ nd = pmix_gds_hash_check_nodename(&trk->nodeinfo, nodes[n]); if (NULL == nd) { nd = PMIX_NEW(pmix_nodeinfo_t); nd->hostname = strdup(nodes[n]); pmix_set_aliases(&nd->aliases, nd->hostname); nd->nodeid = n; pmix_list_append(&trk->nodeinfo, &nd->super); } /* store the proc list as-is */ kp2 = PMIX_NEW(pmix_kval_t); if (NULL == kp2) { return PMIX_ERR_NOMEM; } kp2->key = strdup(PMIX_LOCAL_PEERS); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kp2->value) { PMIX_RELEASE(kp2); return PMIX_ERR_NOMEM; } kp2->value->type = PMIX_STRING; kp2->value->data.string = strdup(ppn[n]); pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map adding key %s to node %s info", pmix_globals.myid.nspace, pmix_globals.myid.rank, kp2->key, nodes[n]); /* ensure this item only appears once on the list */ PMIX_LIST_FOREACH (kp1, &nd->info, pmix_kval_t) { if (PMIX_CHECK_KEY(kp1, kp2->key)) { pmix_list_remove_item(&nd->info, &kp1->super); PMIX_RELEASE(kp1); break; } } pmix_list_append(&nd->info, &kp2->super); /* save the local leader */ rank = strtoul(ppn[n], NULL, 10); kp2 = PMIX_NEW(pmix_kval_t); if (NULL == kp2) { return PMIX_ERR_NOMEM; } kp2->key = strdup(PMIX_LOCALLDR); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kp2->value) { PMIX_RELEASE(kp2); return PMIX_ERR_NOMEM; } kp2->value->type = PMIX_PROC_RANK; kp2->value->data.rank = rank; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map adding key %s to node %s info", pmix_globals.myid.nspace, pmix_globals.myid.rank, kp2->key, nodes[n]); /* ensure this item only appears once on the list */ PMIX_LIST_FOREACH (kp1, &nd->info, pmix_kval_t) { if (PMIX_CHECK_KEY(kp1, kp2->key)) { pmix_list_remove_item(&nd->info, &kp1->super); PMIX_RELEASE(kp1); break; } } pmix_list_append(&nd->info, &kp2->super); /* split the list of procs so we can store their * individual location data */ procs = PMIx_Argv_split(ppn[n], ','); /* save the local size in case they don't * give it to us */ kp2 = PMIX_NEW(pmix_kval_t); if (NULL == kp2) { PMIx_Argv_free(procs); return PMIX_ERR_NOMEM; } kp2->key = strdup(PMIX_LOCAL_SIZE); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kp2->value) { PMIX_RELEASE(kp2); PMIx_Argv_free(procs); return PMIX_ERR_NOMEM; } kp2->value->type = PMIX_UINT32; kp2->value->data.uint32 = PMIx_Argv_count(procs); pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map adding key %s to node %s info", pmix_globals.myid.nspace, pmix_globals.myid.rank, kp2->key, nodes[n]); /* ensure this item only appears once on the list */ PMIX_LIST_FOREACH (kp1, &nd->info, pmix_kval_t) { if (PMIX_CHECK_KEY(kp1, kp2->key)) { pmix_list_remove_item(&nd->info, &kp1->super); PMIX_RELEASE(kp1); break; } } pmix_list_append(&nd->info, &kp2->super); /* track total procs in job in case they * didn't give it to us */ totalprocs += PMIx_Argv_count(procs); for (m = 0; NULL != procs[m]; m++) { /* store the hostname for each proc */ kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(PMIX_HOSTNAME); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); kp2->value->type = PMIX_STRING; kp2->value->data.string = strdup(nd->hostname); rank = strtol(procs[m], NULL, 10); pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map for [%s:%u]: key %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, trk->ns, rank, kp2->key); if (PMIX_SUCCESS != (rc = pmix_hash_store(ht, rank, kp2, NULL, 0, NULL))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); PMIx_Argv_free(procs); return rc; } PMIX_RELEASE(kp2); // maintain acctg if (!(PMIX_HASH_PROC_DATA & flags)) { /* add an entry for the nodeid */ kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(PMIX_NODEID); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); kp2->value->type = PMIX_UINT32; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map for [%s:%u]: key %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, trk->ns, rank, kp2->key); kp2->value->data.uint32 = n; if (PMIX_SUCCESS != (rc = pmix_hash_store(ht, rank, kp2, NULL, 0, NULL))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); PMIx_Argv_free(procs); return rc; } PMIX_RELEASE(kp2); // maintain acctg /* add an entry for the local rank */ kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(PMIX_LOCAL_RANK); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); kp2->value->type = PMIX_UINT16; kp2->value->data.uint16 = m; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map for [%s:%u]: key %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, trk->ns, rank, kp2->key); if (PMIX_SUCCESS != (rc = pmix_hash_store(ht, rank, kp2, NULL, 0, NULL))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); PMIx_Argv_free(procs); return rc; } PMIX_RELEASE(kp2); // maintain acctg /* add an entry for the node rank - for now, we assume * only the one job is running */ kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(PMIX_NODE_RANK); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); kp2->value->type = PMIX_UINT16; kp2->value->data.uint16 = m; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map for [%s:%u]: key %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, trk->ns, rank, kp2->key); if (PMIX_SUCCESS != (rc = pmix_hash_store(ht, rank, kp2, NULL, 0, NULL))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); PMIx_Argv_free(procs); return rc; } PMIX_RELEASE(kp2); // maintain acctg } } PMIx_Argv_free(procs); } /* store the comma-delimited list of nodes hosting * procs in this nspace in case someone using PMIx v2 * requests it */ kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(PMIX_NODE_LIST); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); kp2->value->type = PMIX_STRING; kp2->value->data.string = PMIx_Argv_join(nodes, ','); pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map for nspace %s: key %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, trk->ns, kp2->key); if (PMIX_SUCCESS != (rc = pmix_hash_store(ht, PMIX_RANK_WILDCARD, kp2, NULL, 0, NULL))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); return rc; } PMIX_RELEASE(kp2); // maintain acctg /* if they didn't provide the job size, compute it as * being the number of provided procs (i.e., size of * ppn list) */ if (!(PMIX_HASH_JOB_SIZE & flags)) { kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(PMIX_JOB_SIZE); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); kp2->value->type = PMIX_UINT32; kp2->value->data.uint32 = totalprocs; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map for nspace %s: key %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, trk->ns, kp2->key); if (PMIX_SUCCESS != (rc = pmix_hash_store(ht, PMIX_RANK_WILDCARD, kp2, NULL, 0, NULL))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); return rc; } PMIX_RELEASE(kp2); // maintain acctg flags |= PMIX_HASH_JOB_SIZE; trk->nptr->nprocs = totalprocs; } /* if they didn't provide a value for max procs, just * assume it is the same as the number of procs in the * job and store it */ if (!(PMIX_HASH_MAX_PROCS & flags)) { kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(PMIX_MAX_PROCS); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); kp2->value->type = PMIX_UINT32; kp2->value->data.uint32 = totalprocs; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_map for nspace %s: key %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, trk->ns, kp2->key); if (PMIX_SUCCESS != (rc = pmix_hash_store(ht, PMIX_RANK_WILDCARD, kp2, NULL, 0, NULL))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); return rc; } PMIX_RELEASE(kp2); // maintain acctg flags |= PMIX_HASH_MAX_PROCS; } return PMIX_SUCCESS; } pmix_status_t pmix_gds_hash_store_qualified(pmix_hash_table_t *ht, pmix_rank_t rank, pmix_value_t *value) { pmix_info_t *iptr, *quals; size_t n, sz, nquals; pmix_kval_t kv; pmix_status_t rc; /* the value contains a pmix_data_array_t whose first position * contains the key-value being stored, followed by one or more * qualifiers */ iptr = (pmix_info_t*)value->data.darray->array; sz = value->data.darray->size; /* extract the primary value */ PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = iptr[0].key; kv.value = &iptr[0].value; nquals = sz - 1; PMIX_INFO_CREATE(quals, nquals); for (n=1; n < sz; n++) { PMIX_INFO_SET_QUALIFIER(&quals[n-1]); PMIX_INFO_XFER(&quals[n-1], &iptr[n]); } /* store the result */ rc = pmix_hash_store(ht, rank, &kv, quals, nquals, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } PMIX_INFO_FREE(quals, nquals); return rc; } pmix-6.1.1~rc2/src/mca/gds/hash/configure.m40000664000175000017500000000122715203536752020751 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # Copyright (c) 2023 Triad National Security, LLC. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AC_DEFUN([MCA_pmix_gds_hash_CONFIG], [ AC_CONFIG_FILES([src/mca/gds/hash/Makefile]) dnl This component is always available. AS_IF([test "yes" = "yes"], [$1 pmix_gds_hash=yes], [$2 pmix_gds_hash=no]) PMIX_SUMMARY_ADD([GDS], [Hash], [], [$pmix_gds_hash]) ])dnl pmix-6.1.1~rc2/src/mca/gds/hash/gds_hash.c0000664000175000017500000017320515203536752020460 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/pcompress/base/base.h" #include "src/mca/pmdl/pmdl.h" #include "src/mca/preg/preg.h" #include "src/mca/ptl/base/base.h" #include "src/runtime/pmix_rte.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_hash.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "gds_hash.h" #include "src/mca/gds/base/base.h" static pmix_status_t hash_init(pmix_info_t info[], size_t ninfo); static void hash_finalize(void); static pmix_status_t hash_assign_module(pmix_info_t *info, size_t ninfo, int *priority); static pmix_status_t hash_cache_job_info(struct pmix_namespace_t *ns, pmix_info_t info[], size_t ninfo); static pmix_status_t hash_register_job_info(struct pmix_peer_t *pr, pmix_buffer_t *reply); static pmix_status_t hash_store_job_info(const char *nspace, pmix_buffer_t *buf); static pmix_status_t hash_store_modex(pmix_buffer_t *buff, void *cbdata); static pmix_status_t _hash_store_modex(pmix_proc_t *proc, pmix_buffer_t *pbkt); static pmix_status_t setup_fork(const pmix_proc_t *peer, char ***env); static pmix_status_t nspace_add(const char *nspace, uint32_t nlocalprocs, pmix_info_t info[], size_t ninfo); static pmix_status_t nspace_del(const char *nspace); static pmix_status_t assemb_kvs_req(const pmix_proc_t *proc, pmix_list_t *kvs, pmix_buffer_t *bo, void *cbdata); static pmix_status_t accept_kvs_resp(pmix_buffer_t *buf); static pmix_status_t mark_modex_complete(struct pmix_peer_t *peer, pmix_list_t *nslist, pmix_buffer_t *buff); static pmix_status_t recv_modex_complete(pmix_buffer_t *buff); pmix_gds_base_module_t pmix_hash_module = { .name = "hash", .is_tsafe = false, .init = hash_init, .finalize = hash_finalize, .assign_module = hash_assign_module, .cache_job_info = hash_cache_job_info, .register_job_info = hash_register_job_info, .store_job_info = hash_store_job_info, .store = pmix_gds_hash_store, .store_modex = hash_store_modex, .fetch = pmix_gds_hash_fetch, .setup_fork = setup_fork, .add_nspace = nspace_add, .del_nspace = nspace_del, .assemb_kvs_req = assemb_kvs_req, .accept_kvs_resp = accept_kvs_resp, .fetch_arrays = pmix_gds_hash_fetch_arrays, .mark_modex_complete = mark_modex_complete, .recv_modex_complete = recv_modex_complete }; static pmix_status_t hash_init(pmix_info_t info[], size_t ninfo) { PMIX_HIDE_UNUSED_PARAMS(info, ninfo); PMIX_CONSTRUCT(&pmix_mca_gds_hash_component.mysessions, pmix_list_t); PMIX_CONSTRUCT(&pmix_mca_gds_hash_component.myjobs, pmix_list_t); return PMIX_SUCCESS; } static void hash_finalize(void) { PMIX_LIST_DESTRUCT(&pmix_mca_gds_hash_component.mysessions); PMIX_LIST_DESTRUCT(&pmix_mca_gds_hash_component.myjobs); return; } static pmix_status_t hash_assign_module(pmix_info_t *info, size_t ninfo, int *priority) { size_t n, m; char **options; *priority = 10; if (NULL != info) { for (n = 0; n < ninfo; n++) { if (0 == strncmp(info[n].key, PMIX_GDS_MODULE, PMIX_MAX_KEYLEN)) { options = PMIx_Argv_split(info[n].value.data.string, ','); for (m = 0; NULL != options[m]; m++) { if (0 == strcmp(options[m], "hash")) { /* they specifically asked for us */ *priority = 100; break; } } PMIx_Argv_free(options); break; } } } return PMIX_SUCCESS; } static pmix_status_t hash_cache_job_info(struct pmix_namespace_t *ns, pmix_info_t info[], size_t ninfo) { pmix_namespace_t *nptr = (pmix_namespace_t *) ns; pmix_job_t *trk; pmix_session_t *s = NULL; pmix_hash_table_t *ht; pmix_kval_t *kp2 = NULL, *kvptr, kv; pmix_value_t val; pmix_info_t *iptr; char **nodes = NULL, **procs = NULL; uint32_t sid = UINT32_MAX; pmix_rank_t rank; pmix_status_t rc = PMIX_SUCCESS; size_t n, j, size; uint32_t flags = 0; pmix_nodeinfo_t *nd; pmix_apptrkr_t *apptr; bool found; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:cache_job_info for nspace %s with %lu info", pmix_globals.myid.nspace, pmix_globals.myid.rank, nptr->nspace, ninfo); trk = pmix_gds_hash_get_tracker(nptr->nspace, true); if (NULL == trk) { return PMIX_ERR_NOMEM; } /* if there isn't any data, then be content with just * creating the tracker */ if (NULL == info || 0 == ninfo) { return PMIX_SUCCESS; } /* cache the job info on the internal hash table for this nspace */ ht = &trk->internal; for (n = 0; n < ninfo; n++) { pmix_output_verbose(12, pmix_gds_base_framework.framework_output, "%s gds:hash:cache_job_info for key %s", PMIX_NAME_PRINT(&pmix_globals.myid), info[n].key); if (PMIX_CHECK_KEY(&info[n], PMIX_SESSION_ID)) { rc = PMIx_Value_get_number(&info[n].value, &sid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } s = pmix_gds_hash_check_session(trk, sid, true); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SESSION_INFO_ARRAY)) { if (PMIX_SUCCESS != (rc = pmix_gds_hash_process_session_array(&info[n].value, trk))) { PMIX_ERROR_LOG(rc); goto release; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_JOB_INFO_ARRAY)) { rc = pmix_gds_hash_process_job_array(&info[n], trk, &flags, &procs, &nodes); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_APP_INFO_ARRAY)) { if (PMIX_SUCCESS != (rc = pmix_gds_hash_process_app_array(&info[n].value, trk))) { PMIX_ERROR_LOG(rc); goto release; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_NODE_INFO_ARRAY)) { rc = pmix_gds_hash_process_node_array(&info[n].value, &trk->nodeinfo); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_NODE_MAP)) { /* not allowed to get this more than once */ if (flags & PMIX_HASH_NODE_MAP) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* parse the regex to get the argv array of node names */ if (PMIX_REGEX == info[n].value.type) { rc = pmix_preg.parse_nodes(info[n].value.data.bo.bytes, &nodes); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } } else if (PMIX_STRING == info[n].value.type) { rc = pmix_preg.parse_nodes(info[n].value.data.string, &nodes); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } } else { PMIX_ERROR_LOG(PMIX_ERR_TYPE_MISMATCH); rc = PMIX_ERR_TYPE_MISMATCH; goto release; } /* mark that we got the map */ flags |= PMIX_HASH_NODE_MAP; } else if (PMIX_CHECK_KEY(&info[n], PMIX_PROC_MAP)) { /* not allowed to get this more than once */ if (flags & PMIX_HASH_PROC_MAP) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* parse the regex to get the argv array containing proc ranks on each node */ if (PMIX_REGEX == info[n].value.type) { if (PMIX_SUCCESS != (rc = pmix_preg.parse_procs(info[n].value.data.bo.bytes, &procs))) { PMIX_ERROR_LOG(rc); goto release; } } else if (PMIX_STRING == info[n].value.type) { if (PMIX_SUCCESS != (rc = pmix_preg.parse_procs(info[n].value.data.string, &procs))) { PMIX_ERROR_LOG(rc); goto release; } } else { PMIX_ERROR_LOG(PMIX_ERR_TYPE_MISMATCH); rc = PMIX_ERR_TYPE_MISMATCH; goto release; } /* mark that we got the map */ flags |= PMIX_HASH_PROC_MAP; } else if (PMIX_CHECK_KEY(&info[n], PMIX_PROC_DATA)) { flags |= PMIX_HASH_PROC_DATA; found = false; /* an array of data pertaining to a specific proc */ if (PMIX_DATA_ARRAY != info[n].value.type) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); rc = PMIX_ERR_TYPE_MISMATCH; goto release; } size = info[n].value.data.darray->size; iptr = (pmix_info_t *) info[n].value.data.darray->array; /* first element of the array must be the rank */ if (0 != strcmp(iptr[0].key, PMIX_RANK) || PMIX_PROC_RANK != iptr[0].value.type) { rc = PMIX_ERR_TYPE_MISMATCH; PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); goto release; } rank = iptr[0].value.data.rank; /* cycle thru the values for this rank and store them */ for (j = 1; j < size; j++) { /* if the key is PMIX_QUALIFIED_VALUE, then the value * consists of a data array that starts with the key-value * itself followed by the qualifiers */ pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:cache_job_info proc data for [%s:%u]: key %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, trk->ns, rank, iptr[j].key); if (PMIX_CHECK_KEY(&iptr[j], PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(ht, rank, &iptr[j].value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } } else { kv.key = iptr[j].key; kv.value = &iptr[j].value; /* store it in the hash_table */ rc = pmix_hash_store(ht, rank, &kv, NULL, 0, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } } /* if this is the appnum, pass it to the pmdl framework */ if (PMIX_CHECK_KEY(&iptr[j], PMIX_APPNUM)) { pmix_pmdl.setup_client(trk->nptr, rank, iptr[j].value.data.uint32); found = true; if (rank == pmix_globals.myid.rank) { pmix_globals.appnum = iptr[j].value.data.uint32; } } } if (!found) { /* if they didn't give us an appnum for this proc, we have * to assume it is appnum=0 */ uint32_t zero = 0; kv.key = PMIX_APPNUM; kv.value = &val; PMIX_VALUE_LOAD(&val, &zero, PMIX_UINT32); rc = pmix_hash_store(ht, rank, &kv, NULL, 0, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } pmix_pmdl.setup_client(trk->nptr, rank, val.data.uint32); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_MODEL_LIBRARY_NAME) || PMIX_CHECK_KEY(&info[n], PMIX_PROGRAMMING_MODEL) || PMIX_CHECK_KEY(&info[n], PMIX_MODEL_LIBRARY_VERSION) || PMIX_CHECK_KEY(&info[n], PMIX_PERSONALITY)) { // pass this info to the pmdl framework pmix_pmdl.setup_nspace(trk->nptr, &info[n]); } else if (pmix_check_session_info(info[n].key)) { /* a lone key must belong to this job's session */ if (NULL == s) { s = pmix_gds_hash_check_session(trk, sid, true); } /* ensure the value isn't already on the session info */ found = false; PMIX_LIST_FOREACH (kp2, &s->sessioninfo, pmix_kval_t) { if (PMIX_CHECK_KEY(kp2, info[n].key)) { if (PMIX_EQUAL == PMIx_Value_compare(kp2->value, &info[n].value)) { found = true; } else { pmix_list_remove_item(&s->sessioninfo, &kp2->super); PMIX_RELEASE(kp2); } break; } } if (!found) { /* add the provided value */ kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(info[n].key); PMIX_VALUE_XFER(rc, kp2->value, &info[n].value); pmix_list_append(&s->sessioninfo, &kp2->super); } } else if (pmix_check_node_info(info[n].key)) { /* they are passing us the node-level info for just this * node - start by seeing if our node is on the list */ nd = pmix_gds_hash_check_nodename(&trk->nodeinfo, pmix_globals.hostname); /* if not, then add it */ if (NULL == nd) { nd = PMIX_NEW(pmix_nodeinfo_t); nd->hostname = strdup(pmix_globals.hostname); pmix_set_aliases(&nd->aliases, nd->hostname); pmix_list_append(&trk->nodeinfo, &nd->super); } /* ensure the value isn't already on the node info */ found = false; PMIX_LIST_FOREACH (kp2, &nd->info, pmix_kval_t) { if (PMIX_CHECK_KEY(kp2, info[n].key)) { if (PMIX_EQUAL == PMIx_Value_compare(kp2->value, &info[n].value)) { found = true; } else { pmix_list_remove_item(&nd->info, &kp2->super); PMIX_RELEASE(kp2); } break; } } if (!found) { /* add the provided value */ kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(info[n].key); PMIX_VALUE_XFER(rc, kp2->value, &info[n].value); pmix_list_append(&nd->info, &kp2->super); } } else if (pmix_check_app_info(info[n].key)) { /* they are passing us app-level info for a default * app number - have to assume it is app=0 */ if (0 == pmix_list_get_size(&trk->apps)) { apptr = PMIX_NEW(pmix_apptrkr_t); pmix_list_append(&trk->apps, &apptr->super); } else if (1 < pmix_list_get_size(&trk->apps)) { rc = PMIX_ERR_BAD_PARAM; goto release; } else { apptr = (pmix_apptrkr_t *) pmix_list_get_first(&trk->apps); } /* ensure the value isn't already on the app info */ found = false; PMIX_LIST_FOREACH (kp2, &apptr->appinfo, pmix_kval_t) { if (PMIX_CHECK_KEY(kp2, info[n].key)) { if (PMIX_EQUAL == PMIx_Value_compare(kp2->value, &info[n].value)) { found = true; } else { pmix_list_remove_item(&apptr->appinfo, &kp2->super); PMIX_RELEASE(kp2); } break; } } if (!found) { /* add the provided value */ kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(info[n].key); PMIX_VALUE_XFER(rc, kp2->value, &info[n].value); pmix_list_append(&apptr->appinfo, &kp2->super); } } else { if (PMIX_CHECK_KEY(&info[n], PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(ht, PMIX_RANK_WILDCARD, &info[n].value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } } else { /* just a value relating to the entire job */ kv.key = info[n].key; kv.value = &info[n].value; rc = pmix_hash_store(ht, PMIX_RANK_WILDCARD, &kv, NULL, 0, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto release; } /* if this is the job size, then store it in * the nptr tracker and flag that we were given it */ if (PMIX_CHECK_KEY(&info[n], PMIX_JOB_SIZE)) { nptr->nprocs = info[n].value.data.uint32; flags |= PMIX_HASH_JOB_SIZE; } else if (PMIX_CHECK_KEY(&info[n], PMIX_NUM_NODES)) { flags |= PMIX_HASH_NUM_NODES; } else if (PMIX_CHECK_KEY(&info[n], PMIX_MAX_PROCS)) { flags |= PMIX_HASH_MAX_PROCS; } else { pmix_iof_check_flags(&info[n], &nptr->iof_flags); } } } } /* now add any global data that was provided */ if (!trk->gdata_added) { PMIX_LIST_FOREACH (kvptr, &pmix_server_globals.gdata, pmix_kval_t) { if (PMIX_CHECK_KEY(kvptr, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(ht, PMIX_RANK_WILDCARD, kvptr->value); } else { rc = pmix_hash_store(ht, PMIX_RANK_WILDCARD, kvptr, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); break; } } trk->gdata_added = true; } /* we must have the proc AND node maps */ if (NULL != procs && NULL != nodes) { if (PMIX_SUCCESS != (rc = pmix_gds_hash_store_map(trk, nodes, procs, flags))) { PMIX_ERROR_LOG(rc); } } release: if (NULL != nodes) { PMIx_Argv_free(nodes); } if (NULL != procs) { PMIx_Argv_free(procs); } return rc; } static pmix_status_t register_info(pmix_peer_t *peer, pmix_namespace_t *ns, pmix_buffer_t *reply) { pmix_job_t *trk; pmix_hash_table_t *ht; pmix_value_t blob; pmix_list_t values; pmix_status_t rc = PMIX_SUCCESS; pmix_info_t *info; size_t ninfo, n; pmix_kval_t kv, *kvptr; pmix_buffer_t buf; pmix_rank_t rank; pmix_list_t results; char *hname; pmix_session_t *sptr; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "REGISTERING FOR PEER %s type %d.%d.%d", PMIX_PNAME_PRINT(&peer->info->pname), peer->proc_type.major, peer->proc_type.minor, peer->proc_type.release); trk = pmix_gds_hash_get_tracker(ns->nspace, true); if (NULL == trk) { return PMIX_ERR_NOMEM; } /* the job data is stored on the internal hash table */ ht = &trk->internal; /* fetch all values from the hash table tied to rank=wildcard */ PMIX_CONSTRUCT(&values, pmix_list_t); rc = pmix_hash_fetch(ht, PMIX_RANK_WILDCARD, NULL, NULL, 0, &values, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_LIST_DESTRUCT(&values); return rc; } PMIX_LIST_FOREACH(kvptr, &values, pmix_kval_t) { PMIX_BFROPS_PACK(rc, peer, reply, kvptr, 1, PMIX_KVAL); } PMIX_LIST_DESTRUCT(&values); /* add all values in the jobinfo list */ PMIX_LIST_FOREACH (kvptr, &trk->jobinfo, pmix_kval_t) { PMIX_BFROPS_PACK(rc, peer, reply, kvptr, 1, PMIX_KVAL); } /* get any session-level info for this job */ PMIX_CONSTRUCT(&results, pmix_list_t); rc = pmix_gds_hash_fetch_sessioninfo(peer, NULL, trk, NULL, 0, &results); if (PMIX_SUCCESS == rc) { PMIX_LIST_FOREACH (kvptr, &results, pmix_kval_t) { PMIX_BFROPS_PACK(rc, peer, reply, kvptr, 1, PMIX_KVAL); } } PMIX_LIST_DESTRUCT(&results); /* if the job's tracker points to a non-default session ID, * then we add the default session information to it */ if (NULL != trk->session && UINT32_MAX != trk->session->session) { sptr = pmix_gds_hash_check_session(NULL, UINT32_MAX, false); if (NULL != sptr) { PMIX_CONSTRUCT(&results, pmix_list_t); rc = pmix_gds_hash_xfer_sessioninfo(peer, sptr, NULL, &results); if (PMIX_SUCCESS == rc) { PMIX_LIST_FOREACH (kvptr, &results, pmix_kval_t) { PMIX_BFROPS_PACK(rc, peer, reply, kvptr, 1, PMIX_KVAL); } } PMIX_LIST_DESTRUCT(&results); } } /* get any node-level info for this job */ PMIX_CONSTRUCT(&results, pmix_list_t); rc = pmix_gds_hash_fetch_nodeinfo(peer, NULL, &trk->nodeinfo, NULL, 0, &results); if (PMIX_SUCCESS == rc) { PMIX_LIST_FOREACH (kvptr, &results, pmix_kval_t) { /* if the peer is earlier than v3.2.x, it is expecting * node info to be in the form of an array, but with the * hostname as the key. Detect and convert that here */ if (PMIX_PEER_IS_EARLIER(peer, 3, 1, 100)) { info = (pmix_info_t *) kvptr->value->data.darray->array; ninfo = kvptr->value->data.darray->size; hname = NULL; /* find the hostname */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_HOSTNAME)) { free(kvptr->key); kvptr->key = strdup(info[n].value.data.string); PMIX_BFROPS_PACK(rc, peer, reply, kvptr, 1, PMIX_KVAL); hname = kvptr->key; break; } } if (NULL != hname && pmix_gds_hash_check_hostname(pmix_globals.hostname, hname)) { /* older versions are looking for node-level keys for * only their own node as standalone keys */ for (n = 0; n < ninfo; n++) { if (pmix_check_node_info(info[n].key)) { kv.key = strdup(info[n].key); kv.value = &info[n].value; PMIX_BFROPS_PACK(rc, peer, reply, &kv, 1, PMIX_KVAL); PMIX_DESTRUCT(&kv); } } } } else { PMIX_BFROPS_PACK(rc, peer, reply, kvptr, 1, PMIX_KVAL); } } } PMIX_LIST_DESTRUCT(&results); /* get any app-level info for this job */ PMIX_CONSTRUCT(&results, pmix_list_t); rc = pmix_gds_hash_fetch_appinfo(peer, NULL, &trk->apps, NULL, 0, &results); if (PMIX_SUCCESS == rc) { PMIX_LIST_FOREACH (kvptr, &results, pmix_kval_t) { PMIX_BFROPS_PACK(rc, peer, reply, kvptr, 1, PMIX_KVAL); } } PMIX_LIST_DESTRUCT(&results); /* get the proc-level data for each proc in the job */ pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "FETCHING PROC INFO FOR NSPACE %s NPROCS %u", ns->nspace, ns->nprocs); for (rank = 0; rank < ns->nprocs; rank++) { pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "FETCHING PROC INFO FOR RANK %s", PMIX_RANK_PRINT(rank)); PMIX_CONSTRUCT(&values, pmix_list_t); rc = pmix_hash_fetch(ht, rank, NULL, NULL, 0, &values, NULL); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { PMIX_ERROR_LOG(rc); PMIX_LIST_DESTRUCT(&values); return rc; } if (0 == pmix_list_get_size(&values)) { PMIX_LIST_DESTRUCT(&values); continue; } PMIX_CONSTRUCT(&buf, pmix_buffer_t); PMIX_BFROPS_PACK(rc, peer, &buf, &rank, 1, PMIX_PROC_RANK); PMIX_LIST_FOREACH(kvptr, &values, pmix_kval_t) { PMIX_BFROPS_PACK(rc, peer, &buf, kvptr, 1, PMIX_KVAL); } PMIX_LIST_DESTRUCT(&values); kv.key = PMIX_PROC_BLOB; kv.value = &blob; blob.type = PMIX_BYTE_OBJECT; PMIX_UNLOAD_BUFFER(&buf, blob.data.bo.bytes, blob.data.bo.size); PMIX_BFROPS_PACK(rc, peer, reply, &kv, 1, PMIX_KVAL); PMIX_VALUE_DESTRUCT(&blob); PMIX_DESTRUCT(&buf); } return rc; } /* the purpose of this function is to pack the job-level * info stored in the pmix_namespace_t into a buffer and send * it to the given client */ static pmix_status_t hash_register_job_info(struct pmix_peer_t *pr, pmix_buffer_t *reply) { pmix_peer_t *peer = (pmix_peer_t *) pr; pmix_namespace_t *ns = peer->nptr; char *msg; pmix_status_t rc; pmix_job_t *trk; if (!PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { /* this function is only available on servers */ PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_SUPPORTED; } pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "%s gds:hash:register_job_info for peer %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_PEER_PRINT(peer)); /* first see if we already have processed this data * for another peer in this nspace so we don't waste * time doing it again */ if (NULL != ns->jobbkt) { pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:register_job_info copying prepacked payload", pmix_globals.myid.nspace, pmix_globals.myid.rank); /* we have packed this before - can just deliver it */ PMIX_BFROPS_COPY_PAYLOAD(rc, peer, reply, ns->jobbkt); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } /* now see if we have delivered it to all our local * clients for this nspace */ if (!PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) && ns->ndelivered == ns->nlocalprocs) { /* we have, so let's get rid of the packed * copy of the data */ PMIX_RELEASE(ns->jobbkt); ns->jobbkt = NULL; } return rc; } /* setup a tracker for this nspace as we will likely * need it again */ trk = pmix_gds_hash_get_tracker(ns->nspace, true); if (NULL == trk) { return PMIX_ERR_NOMEM; } /* the job info for the specified nspace has * been given to us in the info array - pack * them for delivery */ /* pack the name of the nspace */ pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:register_job_info packing new payload", pmix_globals.myid.nspace, pmix_globals.myid.rank); msg = ns->nspace; PMIX_BFROPS_PACK(rc, peer, reply, &msg, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } rc = register_info(peer, ns, reply); if (PMIX_SUCCESS == rc) { /* if we have more than one local client for this nspace, * save this packed object so we don't do this again */ if (PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) || 1 < ns->nlocalprocs) { PMIX_RETAIN(reply); ns->jobbkt = reply; } } else { PMIX_ERROR_LOG(rc); } return rc; } static pmix_status_t hash_store_job_info(const char *nspace, pmix_buffer_t *buf) { pmix_status_t rc = PMIX_SUCCESS; pmix_kval_t kptr, kp2, *kp3, *kp4, kv, kv2; pmix_value_t val; int32_t cnt; size_t nnodes, n, sz; uint32_t i, j, sid = UINT32_MAX; char **procs = NULL; pmix_byte_object_t *bo; pmix_buffer_t buf2; pmix_rank_t rank; pmix_job_t *trk; pmix_hash_table_t *ht; char **nodelist = NULL; pmix_nodeinfo_t *nd; pmix_namespace_t *ns, *nptr; pmix_info_t *iptr; pmix_session_t *s = NULL; pmix_apptrkr_t *apptr; bool found; bool myproc; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%u] pmix:gds:hash store job info for nspace %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, nspace); /* check buf data */ if ((NULL == buf) || (0 == buf->bytes_used)) { rc = PMIX_ERR_BAD_PARAM; PMIX_ERROR_LOG(rc); return rc; } trk = pmix_gds_hash_get_tracker(nspace, true); if (NULL == trk) { return PMIX_ERR_NOMEM; } ht = &trk->internal; /* retrieve the nspace pointer */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(ns->nspace, nspace)) { nptr = ns; break; } } if (NULL == nptr) { /* only can happen if we are out of mem */ return PMIX_ERR_NOMEM; } cnt = 1; PMIX_CONSTRUCT(&kptr, pmix_kval_t); PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &kptr, &cnt, PMIX_KVAL); while (PMIX_SUCCESS == rc) { pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%u] pmix:gds:hash store job info working key %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, PMIx_Get_attribute_name(kptr.key)); if (PMIX_CHECK_KEY(&kptr, PMIX_PROC_BLOB)) { bo = &(kptr.value->data.bo); PMIX_CONSTRUCT(&buf2, pmix_buffer_t); PMIX_LOAD_BUFFER(pmix_client_globals.myserver, &buf2, bo->bytes, bo->size); /* start by unpacking the rank */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, &buf2, &rank, &cnt, PMIX_PROC_RANK); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kptr); PMIX_DESTRUCT(&buf2); return rc; } if (PMIX_CHECK_NSPACE(pmix_globals.myid.nspace, nptr->nspace) && rank == pmix_globals.myid.rank) { myproc = true; } else { myproc = false; } /* unpack the blob and save the values for this rank */ cnt = 1; PMIX_CONSTRUCT(&kp2, pmix_kval_t); PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, &buf2, &kp2, &cnt, PMIX_KVAL); while (PMIX_SUCCESS == rc) { /* this is data provided by a job-level exchange, so store it * in the job-level data hash_table */ pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "%s pmix:gds:hash store proc info for rank %u working key %s", PMIX_NAME_PRINT(&pmix_globals.myid), rank, kp2.key); if (PMIX_CHECK_KEY(&kp2, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(ht, rank, kp2.value); } else { rc = pmix_hash_store(ht, rank, &kp2, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kp2); PMIX_DESTRUCT(&kptr); PMIX_DESTRUCT(&buf2); return rc; } if (myproc) { if (PMIX_CHECK_KEY(&kp2, PMIX_APPNUM)) { rc = PMIx_Value_get_number(kp2.value, &pmix_globals.appnum, PMIX_UINT32); } else if (PMIX_CHECK_KEY(&kp2, PMIX_NODEID)) { rc = PMIx_Value_get_number(kp2.value, &pmix_globals.nodeid, PMIX_UINT32); } else if (PMIX_CHECK_KEY(&kp2, PMIX_HOSTNAME)) { pmix_globals.hostname = strdup(kp2.value->data.string); } } cnt = 1; PMIX_DESTRUCT(&kp2); PMIX_CONSTRUCT(&kp2, pmix_kval_t); PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, &buf2, &kp2, &cnt, PMIX_KVAL); } /* cleanup */ PMIX_DESTRUCT(&buf2); // releases the original kptr data PMIX_DESTRUCT(&kp2); } else if (PMIX_CHECK_KEY(&kptr, PMIX_MAP_BLOB)) { /* transfer the byte object for unpacking */ bo = &(kptr.value->data.bo); PMIX_CONSTRUCT(&buf2, pmix_buffer_t); PMIX_LOAD_BUFFER(pmix_client_globals.myserver, &buf2, bo->bytes, bo->size); /* start by unpacking the number of nodes */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, &buf2, &nnodes, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kptr); PMIX_DESTRUCT(&buf2); return rc; } for (i = 0; i < nnodes; i++) { /* unpack the list of procs on each node */ cnt = 1; PMIX_CONSTRUCT(&kv, pmix_kval_t); PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, &buf2, &kv, &cnt, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kptr); PMIX_DESTRUCT(&buf2); PMIX_DESTRUCT(&kv); return rc; } /* track the nodes in this nspace */ PMIx_Argv_append_nosize(&nodelist, kv.key); /* check and see if we already have this node */ nd = pmix_gds_hash_check_nodename(&trk->nodeinfo, kv.key); if (NULL == nd) { nd = PMIX_NEW(pmix_nodeinfo_t); nd->hostname = strdup(kv.key); pmix_list_append(&trk->nodeinfo, &nd->super); } /* save the list of peers for this node */ kp3 = PMIX_NEW(pmix_kval_t); if (NULL == kp3) { PMIX_DESTRUCT(&kptr); return PMIX_ERR_NOMEM; } kp3->key = strdup(PMIX_LOCAL_PEERS); kp3->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kp3->value) { PMIX_RELEASE(kp3); PMIX_DESTRUCT(&kptr); return PMIX_ERR_NOMEM; } kp3->value->type = PMIX_STRING; kp3->value->data.string = strdup(kv.value->data.string); /* ensure this item only appears once on the list */ PMIX_LIST_FOREACH (kp4, &nd->info, pmix_kval_t) { if (PMIX_CHECK_KEY(kp4, kp3->key)) { pmix_list_remove_item(&nd->info, &kp4->super); PMIX_RELEASE(kp4); break; } } pmix_list_append(&nd->info, &kp3->super); /* split the list of procs so we can store their * individual location data */ procs = PMIx_Argv_split(kv.value->data.string, ','); kv2.value = &val; val.type = PMIX_STRING; for (j = 0; NULL != procs[j]; j++) { /* store the hostname for each proc - again, this is * data obtained via a job-level exchange, so store it * in the job-level data hash_table */ kv2.key = PMIX_HOSTNAME; val.data.string = kv.key; rank = strtol(procs[j], NULL, 10); pmix_output_verbose( 2, pmix_gds_base_framework.framework_output, "[%s:%u] pmix:gds:hash store map info for rank %u working key %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, rank, kv2.key); rc = pmix_hash_store(ht, PMIX_RANK_WILDCARD, &kv2, NULL, 0, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kptr); PMIX_DESTRUCT(&kv); PMIX_DESTRUCT(&buf2); PMIx_Argv_free(procs); return rc; } } PMIx_Argv_free(procs); PMIX_DESTRUCT(&kv); } if (NULL != nodelist) { /* store the comma-delimited list of nodes hosting * procs in this nspace */ kv2.key = PMIX_NODE_LIST; kv2.value = &val; val.type = PMIX_STRING; val.data.string = PMIx_Argv_join(nodelist, ','); PMIx_Argv_free(nodelist); rc = pmix_hash_store(ht, PMIX_RANK_WILDCARD, &kv2, NULL, 0, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kptr); PMIX_VALUE_DESTRUCT(&val); PMIX_DESTRUCT(&kv); PMIX_DESTRUCT(&buf2); return rc; } PMIX_VALUE_DESTRUCT(&val); } /* cleanup */ PMIX_DESTRUCT(&buf2); } else if (PMIX_CHECK_KEY(&kptr, PMIX_SESSION_ID)) { rc = PMIx_Value_get_number(kptr.value, &sid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } s = pmix_gds_hash_check_session(trk, sid, true); if (PMIX_CHECK_NSPACE(nspace, pmix_globals.myid.nspace)) { pmix_globals.sessionid = sid; } } else if (PMIX_CHECK_KEY(&kptr, PMIX_SESSION_INFO_ARRAY)) { if (PMIX_SUCCESS != (rc = pmix_gds_hash_process_session_array(kptr.value, trk))) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kptr); return rc; } } else if (pmix_check_session_info(kptr.key)) { /* a lone key must belong to this job's session */ if (NULL == s) { s = pmix_gds_hash_check_session(trk, sid, true); } /* ensure the value isn't already on the session info */ found = false; PMIX_LIST_FOREACH (kp3, &s->sessioninfo, pmix_kval_t) { if (PMIX_CHECK_KEY(kp3, kptr.key)) { if (PMIX_EQUAL == PMIx_Value_compare(kp3->value, kptr.value)) { found = true; } else { pmix_list_remove_item(&s->sessioninfo, &kp3->super); PMIX_RELEASE(kp3); } break; } } if (!found) { /* add the provided value */ kp3 = PMIX_NEW(pmix_kval_t); kp3->key = strdup(kptr.key); PMIX_VALUE_XFER(rc, kp3->value, kptr.value); pmix_list_append(&s->sessioninfo, &kp3->super); } } else if (PMIX_CHECK_KEY(&kptr, PMIX_APP_INFO_ARRAY)) { if (PMIX_SUCCESS != (rc = pmix_gds_hash_process_app_array(kptr.value, trk))) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kptr); return rc; } } else if (pmix_check_app_info(kptr.key)) { /* they are passing us app-level info for a default * app number - have to assume it is app=0 */ if (0 == pmix_list_get_size(&trk->apps)) { apptr = PMIX_NEW(pmix_apptrkr_t); pmix_list_append(&trk->apps, &apptr->super); } else if (1 < pmix_list_get_size(&trk->apps)) { rc = PMIX_ERR_BAD_PARAM; return rc; } else { apptr = (pmix_apptrkr_t *) pmix_list_get_first(&trk->apps); } /* ensure the value isn't already on the app info */ found = false; PMIX_LIST_FOREACH (kp3, &apptr->appinfo, pmix_kval_t) { if (PMIX_CHECK_KEY(kp3, kptr.key)) { if (PMIX_EQUAL == PMIx_Value_compare(kp3->value, kptr.value)) { found = true; } else { pmix_list_remove_item(&apptr->appinfo, &kp3->super); PMIX_RELEASE(kp3); } break; } } if (!found) { /* add the provided value */ kp3 = PMIX_NEW(pmix_kval_t); kp3->key = strdup(kptr.key); PMIX_VALUE_XFER(rc, kp3->value, kptr.value); pmix_list_append(&apptr->appinfo, &kp3->super); } } else if (PMIX_CHECK_KEY(&kptr, PMIX_NODE_INFO_ARRAY)) { rc = pmix_gds_hash_process_node_array(kptr.value, &trk->nodeinfo); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kptr); return rc; } } else if (pmix_check_node_info(kptr.key)) { /* they are passing us the node-level info for just this * node - start by seeing if our node is on the list */ nd = pmix_gds_hash_check_nodename(&trk->nodeinfo, pmix_globals.hostname); /* if not, then add it */ if (NULL == nd) { nd = PMIX_NEW(pmix_nodeinfo_t); nd->hostname = strdup(pmix_globals.hostname); pmix_list_append(&trk->nodeinfo, &nd->super); } /* ensure the value isn't already on the node info */ found = false; PMIX_LIST_FOREACH (kp3, &nd->info, pmix_kval_t) { if (PMIX_CHECK_KEY(kp3, kptr.key)) { if (PMIX_EQUAL == PMIx_Value_compare(kp3->value, kptr.value)) { found = true; } else { pmix_list_remove_item(&nd->info, &kp3->super); PMIX_RELEASE(kp3); } break; } } if (!found) { /* add the provided value */ kp3 = PMIX_NEW(pmix_kval_t); kp3->key = strdup(kptr.key); PMIX_VALUE_XFER(rc, kp3->value, kptr.value); pmix_list_append(&nd->info, &kp3->super); } } else if (PMIX_CHECK_KEY(&kptr, PMIX_PROC_DATA)) { iptr = (pmix_info_t*)kptr.value->data.darray->array; sz = kptr.value->data.darray->size; /* the first position is the rank */ if (PMIX_CHECK_KEY(&iptr[0], PMIX_RANK)) { rank = iptr[0].value.data.rank; } else { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&kptr); return rc; } for (n=1; n < sz; n++) { PMIX_CONSTRUCT(&kv, pmix_kval_t); kv.key = iptr[n].key; kv.value = &iptr[n].value; if (PMIX_CHECK_KEY(&kv, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(ht, rank, kv.value); } else { rc = pmix_hash_store(ht, rank, &kv, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kptr); return rc; } } } else { pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%u] pmix:gds:hash store job info storing key %s for WILDCARD rank", pmix_globals.myid.nspace, pmix_globals.myid.rank, kptr.key); if (PMIX_CHECK_KEY(&kptr, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(ht, PMIX_RANK_WILDCARD, kptr.value); } else { rc = pmix_hash_store(ht, PMIX_RANK_WILDCARD, &kptr, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kptr); return rc; } /* if this is the job size, then store it in * the nptr tracker */ if (0 == nptr->nprocs && PMIX_CHECK_KEY(&kptr, PMIX_JOB_SIZE)) { nptr->nprocs = kptr.value->data.uint32; } } PMIX_DESTRUCT(&kptr); PMIX_CONSTRUCT(&kptr, pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &kptr, &cnt, PMIX_KVAL); } /* need to release the leftover kptr */ PMIX_DESTRUCT(&kptr); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); } else { rc = PMIX_SUCCESS; } return rc; } pmix_status_t pmix_gds_hash_store(const pmix_proc_t *proc, pmix_scope_t scope, pmix_kval_t *kv) { pmix_job_t *trk; pmix_status_t rc; pmix_kval_t kp; pmix_rank_t rank; size_t j, size; pmix_info_t *iptr; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "%s gds:hash:hash_store for proc %s key %s type %s scope %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_NAME_PRINT(proc), PMIx_Get_attribute_name(kv->key), PMIx_Data_type_string(kv->value->type), PMIx_Scope_string(scope)); if (NULL == kv->key) { return PMIX_ERR_BAD_PARAM; } /* find the hash table for this nspace */ trk = pmix_gds_hash_get_tracker(proc->nspace, true); if (NULL == trk) { return PMIX_ERR_NOMEM; } /* if this is node/app data, then process it accordingly */ if (PMIX_CHECK_KEY(kv, PMIX_NODE_INFO_ARRAY)) { rc = pmix_gds_hash_process_node_array(kv->value, &trk->nodeinfo); return rc; } else if (PMIX_CHECK_KEY(kv, PMIX_APP_INFO_ARRAY)) { rc = pmix_gds_hash_process_app_array(kv->value, trk); return rc; } else if (PMIX_CHECK_KEY(kv, PMIX_SESSION_INFO_ARRAY)) { rc = pmix_gds_hash_process_session_array(kv->value, trk); return rc; } else if (PMIX_CHECK_KEY(kv, PMIX_JOB_INFO_ARRAY)) { return PMIX_ERR_NOT_SUPPORTED; } /* see if the proc is me - cannot use CHECK_PROCID as * we don't want rank=wildcard to match */ if (proc->rank == pmix_globals.myid.rank && PMIX_CHECK_NSPACE(proc->nspace, pmix_globals.myid.nspace)) { if (PMIX_INTERNAL != scope) { /* always maintain a copy of my own info here to simplify * later retrieval */ if (PMIX_CHECK_KEY(kv, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(&trk->internal, proc->rank, kv->value); } else { rc = pmix_hash_store(&trk->internal, proc->rank, kv, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } } /* if the number of procs for the nspace object is new, then update it */ if (0 == trk->nptr->nprocs && PMIX_CHECK_KEY(kv, PMIX_JOB_SIZE)) { trk->nptr->nprocs = kv->value->data.uint32; } /* store it in the corresponding hash table */ if (PMIX_INTERNAL == scope) { /* if this is proc data, then we have to expand it and * store the values on that rank */ if (PMIX_CHECK_KEY(kv, PMIX_PROC_DATA)) { /* an array of data pertaining to a specific proc */ if (PMIX_DATA_ARRAY != kv->value->type) { PMIX_ERROR_LOG(PMIX_ERR_TYPE_MISMATCH); return PMIX_ERR_TYPE_MISMATCH; } size = kv->value->data.darray->size; iptr = (pmix_info_t *) kv->value->data.darray->array; /* first element of the array must be the rank */ if (0 != strcmp(iptr[0].key, PMIX_RANK) || PMIX_PROC_RANK != iptr[0].value.type) { rc = PMIX_ERR_TYPE_MISMATCH; PMIX_ERROR_LOG(rc); return rc; } rank = iptr[0].value.data.rank; /* cycle thru the values for this rank and store them */ for (j = 1; j < size; j++) { if (PMIX_CHECK_KEY(&iptr[j], PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(&trk->internal, rank, &iptr[j].value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } continue; } kp.key = iptr[j].key; kp.value = &iptr[j].value; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "%s gds:hash:STORE data for nspace %s rank %u: key %s", PMIX_NAME_PRINT(&pmix_globals.myid), trk->ns, rank, kp.key); /* store it in the hash_table */ rc = pmix_hash_store(&trk->internal, rank, &kp, NULL, 0, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } return PMIX_SUCCESS; } /* if it isn't proc data, then store it */ if (PMIX_CHECK_KEY(kv, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(&trk->internal, proc->rank, kv->value); } else { rc = pmix_hash_store(&trk->internal, proc->rank, kv, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } else if (PMIX_REMOTE == scope) { if (PMIX_CHECK_KEY(kv, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(&trk->remote, proc->rank, kv->value); } else { rc = pmix_hash_store(&trk->remote, proc->rank, kv, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } else if (PMIX_LOCAL == scope) { if (PMIX_CHECK_KEY(kv, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(&trk->local, proc->rank, kv->value); } else { rc = pmix_hash_store(&trk->local, proc->rank, kv, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } else if (PMIX_GLOBAL == scope) { if (PMIX_CHECK_KEY(kv, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(&trk->remote, proc->rank, kv->value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } rc = pmix_gds_hash_store_qualified(&trk->local, proc->rank, kv->value); } else { rc = pmix_hash_store(&trk->remote, proc->rank, kv, NULL, 0, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } rc = pmix_hash_store(&trk->local, proc->rank, kv, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } else { return PMIX_ERR_BAD_PARAM; } return PMIX_SUCCESS; } /* this function is only called by the PMIx server when its * host has received data from some other peer. It therefore * always contains data solely from remote procs, and we * shall store it accordingly */ static pmix_status_t hash_store_modex(pmix_buffer_t *buf, void *cbdata) { return pmix_gds_base_store_modex(buf, _hash_store_modex, cbdata); } static pmix_status_t _hash_store_modex(pmix_proc_t *proc, pmix_buffer_t *pbkt) { pmix_job_t *trk; pmix_status_t rc = PMIX_SUCCESS; pmix_kval_t kv; int32_t cnt; if (NULL == pbkt) { return PMIX_SUCCESS; } pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "[%s:%d] gds:hash:store_modex for nspace %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, proc->nspace); /* find the hash table for this nspace */ trk = pmix_gds_hash_get_tracker(proc->nspace, true); if (NULL == trk) { return PMIX_ERR_NOMEM; } /* this is data returned via the PMIx_Fence call when * data collection was requested, so it only contains * REMOTE/GLOBAL data. The byte object contains * the pmix_kval_t's published by the given proc */ /* unpack the values until we hit the end of the buffer */ PMIX_CONSTRUCT(&kv, pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, pbkt, &kv, &cnt, PMIX_KVAL); while (PMIX_SUCCESS == rc) { if (PMIX_RANK_UNDEF == proc->rank) { /* if the rank is undefined, then we store it on the * remote table of rank=0 as we know that rank must * always exist */ if (PMIX_CHECK_KEY(&kv, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(&trk->remote, 0, kv.value); } else { rc = pmix_hash_store(&trk->remote, 0, &kv, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } else { /* store this in the hash table */ if (PMIX_CHECK_KEY(&kv, PMIX_QUALIFIED_VALUE)) { rc = pmix_gds_hash_store_qualified(&trk->remote, proc->rank, kv.value); } else { rc = pmix_hash_store(&trk->remote, proc->rank, &kv, NULL, 0, NULL); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } PMIX_DESTRUCT(&kv); /* continue along */ PMIX_CONSTRUCT(&kv, pmix_kval_t); PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, pbkt, &kv, &cnt, PMIX_KVAL); } PMIX_DESTRUCT(&kv); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); } else { rc = PMIX_SUCCESS; } return rc; } static pmix_status_t setup_fork(const pmix_proc_t *proc, char ***env) { PMIX_HIDE_UNUSED_PARAMS(proc, env); /* we don't need to add anything */ return PMIX_SUCCESS; } static pmix_status_t nspace_add(const char *nspace, uint32_t nlocalprocs, pmix_info_t info[], size_t ninfo) { PMIX_HIDE_UNUSED_PARAMS(nspace, nlocalprocs, info, ninfo); /* we don't need to do anything here */ return PMIX_SUCCESS; } static pmix_status_t nspace_del(const char *nspace) { pmix_job_t *t; /* find the hash table for this nspace */ PMIX_LIST_FOREACH (t, &pmix_mca_gds_hash_component.myjobs, pmix_job_t) { if (0 == strcmp(nspace, t->ns)) { /* release it */ pmix_list_remove_item(&pmix_mca_gds_hash_component.myjobs, &t->super); PMIX_RELEASE(t); break; } } return PMIX_SUCCESS; } static pmix_status_t assemb_kvs_req(const pmix_proc_t *proc, pmix_list_t *kvs, pmix_buffer_t *buf, void *cbdata) { pmix_status_t rc = PMIX_SUCCESS; pmix_server_caddy_t *cd = (pmix_server_caddy_t *) cbdata; pmix_kval_t *kv; if (!PMIX_PEER_IS_V1(cd->peer)) { PMIX_BFROPS_PACK(rc, cd->peer, buf, proc, 1, PMIX_PROC); if (PMIX_SUCCESS != rc) { return rc; } } PMIX_LIST_FOREACH (kv, kvs, pmix_kval_t) { PMIX_BFROPS_PACK(rc, cd->peer, buf, kv, 1, PMIX_KVAL); if (PMIX_SUCCESS != rc) { return rc; } } return rc; } static pmix_status_t store_session_info(pmix_nspace_t nspace, pmix_kval_t *kv) { pmix_job_t *trk; pmix_status_t rc; /* find the hash table for this nspace */ trk = pmix_gds_hash_get_tracker(nspace, true); if (NULL == trk) { return PMIX_ERR_NOMEM; } rc = pmix_gds_hash_process_session_array(kv->value, trk); return rc; } static pmix_status_t store_node_info(pmix_nspace_t nspace, pmix_kval_t *kv) { pmix_job_t *trk; pmix_status_t rc; /* find the hash table for this nspace */ trk = pmix_gds_hash_get_tracker(nspace, true); if (NULL == trk) { return PMIX_ERR_NOMEM; } rc = pmix_gds_hash_process_node_array(kv->value, &trk->nodeinfo); return rc; } static pmix_status_t store_app_info(pmix_nspace_t nspace, pmix_kval_t *kv) { pmix_job_t *trk; pmix_status_t rc; /* find the hash table for this nspace */ trk = pmix_gds_hash_get_tracker(nspace, true); if (NULL == trk) { return PMIX_ERR_NOMEM; } rc = pmix_gds_hash_process_app_array(kv->value, trk); return rc; } static pmix_status_t accept_kvs_resp(pmix_buffer_t *buf) { pmix_status_t rc = PMIX_SUCCESS; int32_t cnt; pmix_byte_object_t bo; pmix_buffer_t pbkt; pmix_kval_t kv; pmix_proc_t proct; /* the incoming payload is provided as a set of packed * byte objects, one for each rank. A pmix_proc_t is the first * entry in the byte object. If the rank=PMIX_RANK_WILDCARD, * then that byte object contains job level info * for the provided nspace. Otherwise, the byte * object contains the pmix_kval_t's that were "put" by the * referenced process */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &bo, &cnt, PMIX_BYTE_OBJECT); while (PMIX_SUCCESS == rc) { /* setup the byte object for unpacking */ PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); PMIX_LOAD_BUFFER(pmix_client_globals.myserver, &pbkt, bo.bytes, bo.size); /* unpack the id of the providing process */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, &pbkt, &proct, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* if the rank is UNDEF, then we store this on our own * rank tables */ if (PMIX_RANK_UNDEF == proct.rank) { proct.rank = pmix_globals.myid.rank; } cnt = 1; PMIX_CONSTRUCT(&kv, pmix_kval_t); PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, &pbkt, &kv, &cnt, PMIX_KVAL); while (PMIX_SUCCESS == rc) { /* if this is an info array, then store it here as dstore * doesn't know how to handle it */ if (PMIX_CHECK_KEY(&kv, PMIX_SESSION_INFO_ARRAY)) { rc = store_session_info(proct.nspace, &kv); } else if (PMIX_CHECK_KEY(&kv, PMIX_NODE_INFO_ARRAY)) { rc = store_node_info(proct.nspace, &kv); } else if (PMIX_CHECK_KEY(&kv, PMIX_APP_INFO_ARRAY)) { rc = store_app_info(proct.nspace, &kv); } else { rc = pmix_gds_hash_store(&proct, PMIX_INTERNAL, &kv); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&kv); PMIX_DESTRUCT(&pbkt); return rc; } /* get the next one */ PMIX_DESTRUCT(&kv); PMIX_CONSTRUCT(&kv, pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, &pbkt, &kv, &cnt, PMIX_KVAL); } PMIX_DESTRUCT(&kv); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); return rc; } PMIX_DESTRUCT(&pbkt); /* get the next one */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &bo, &cnt, PMIX_BYTE_OBJECT); } if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); return rc; } return rc; } static pmix_status_t mark_modex_complete(struct pmix_peer_t *peer, pmix_list_t *nslist, pmix_buffer_t *buff) { PMIX_HIDE_UNUSED_PARAMS(peer, nslist, buff); /* nothing to do. */ return PMIX_SUCCESS; } static pmix_status_t recv_modex_complete(pmix_buffer_t *buff) { PMIX_HIDE_UNUSED_PARAMS(buff); /* nothing to do. */ return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/gds/hash/Makefile.am0000664000175000017500000000422215203536752020560 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(gds_hash_CPPFLAGS) headers = gds_hash.h sources = \ gds_hash_component.c \ gds_hash.c \ process_arrays.c \ gds_utils.c \ gds_fetch.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_gds_hash_DSO lib = lib_sources = component = pmix_mca_gds_hash.la component_sources = $(headers) $(sources) else lib = libpmix_mca_gds_hash.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_gds_hash_la_SOURCES = $(component_sources) pmix_mca_gds_hash_la_LIBADD = $(gds_hash_LIBS) pmix_mca_gds_hash_la_LDFLAGS = -module -avoid-version $(gds_hash_LDFLAGS) if NEED_LIBPMIX pmix_mca_gds_hash_la_LIBADD += $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_gds_hash_la_SOURCES = $(lib_sources) libpmix_mca_gds_hash_la_LIBADD = $(gds_hash_LIBS) libpmix_mca_gds_hash_la_LDFLAGS = -module -avoid-version $(gds_hash_LDFLAGS) pmix-6.1.1~rc2/src/mca/gds/hash/gds_fetch.c0000664000175000017500000007542415203536752020632 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2018 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/pcompress/base/base.h" #include "src/mca/pmdl/pmdl.h" #include "src/mca/preg/preg.h" #include "src/mca/ptl/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_hash.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "gds_hash.h" #include "src/mca/gds/base/base.h" pmix_status_t pmix_gds_hash_xfer_sessioninfo(pmix_peer_t *peer, pmix_session_t *sptr, const char *key, pmix_list_t *kvs) { size_t n; pmix_kval_t *kv, *kp2; pmix_info_t *iptr; pmix_list_t *sessionlist = &sptr->sessioninfo; uint32_t sid = sptr->session; pmix_status_t rc; if (NULL == key) { if (PMIX_PEER_IS_EARLIER(peer, 4, 2, 0)) { /* we can only transfer the data as independent values */ PMIX_LIST_FOREACH(kv, sessionlist, pmix_kval_t) { kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(kv->key); PMIX_VALUE_XFER(rc, kp2->value, kv->value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kp2); return rc; } pmix_list_append(kvs, &kp2->super); } } else { /* we return it as an info array */ PMIX_KVAL_NEW(kp2, PMIX_SESSION_INFO_ARRAY); kp2->value->type = PMIX_DATA_ARRAY; n = pmix_list_get_size(sessionlist) + 1; PMIX_DATA_ARRAY_CREATE(kp2->value->data.darray, n, PMIX_INFO); iptr = (pmix_info_t*)kp2->value->data.darray->array; /* first element will be the session id */ PMIX_INFO_LOAD(&iptr[0], PMIX_SESSION_ID, &sid, PMIX_UINT32); /* populate the rest of the array */ n = 1; PMIX_LIST_FOREACH(kv, sessionlist, pmix_kval_t) { PMIX_LOAD_KEY(iptr[n].key, kv->key); rc = PMIx_Value_xfer(&iptr[n].value, kv->value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kp2); return rc; } ++n; } pmix_list_append(kvs, &kp2->super); } return PMIX_SUCCESS; } /* we were given a specific key */ PMIX_LIST_FOREACH(kv, sessionlist, pmix_kval_t) { if (PMIX_CHECK_KEY(kv, key)) { kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(kv->key); PMIX_VALUE_XFER(rc, kp2->value, kv->value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kp2); return rc; } pmix_list_append(kvs, &kp2->super); return PMIX_SUCCESS; } } return PMIX_ERR_NOT_FOUND; } pmix_status_t pmix_gds_hash_fetch_sessioninfo(pmix_peer_t *peer, const char *key, pmix_job_t *trk, pmix_info_t *info, size_t ninfo, pmix_list_t *kvs) { size_t n; pmix_status_t rc; uint32_t sid = UINT32_MAX; pmix_session_t *sptr; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "FETCHING SESSION INFO"); /* scan for the session ID to identify * which session they are asking about */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SESSION_ID)) { rc = PMIx_Value_get_number(&info[n].value, &sid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { return rc; } break; } } sptr = pmix_gds_hash_check_session(trk, sid, false); if (NULL == sptr) { return PMIX_ERR_NOT_FOUND; } /* capture the info */ rc = pmix_gds_hash_xfer_sessioninfo(peer, sptr, key, kvs); return rc; } pmix_status_t pmix_gds_hash_fetch_nodeinfo(pmix_peer_t *peer, const char *key, pmix_list_t *tgt, pmix_info_t *info, size_t ninfo, pmix_list_t *kvs) { size_t n, nds; pmix_status_t rc; uint32_t nid = UINT32_MAX; char *hostname = NULL; bool found = false; pmix_nodeinfo_t *nd, *ndptr; pmix_kval_t *kv, *kp2; pmix_data_array_t *darray; pmix_info_t *iptr; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "FETCHING NODE INFO WITH KEY %s", (NULL == key) ? "NULL" : key); /* scan for the nodeID or hostname to identify * which node they are asking about */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_NODEID)) { rc = PMIx_Value_get_number(&info[n].value, &nid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { return rc; } found = true; break; } else if (PMIX_CHECK_KEY(&info[n], PMIX_HOSTNAME)) { hostname = info[n].value.data.string; found = true; break; } } if (!found) { /* if the key is NULL, then they want all the info from * all nodes */ if (NULL == key) { PMIX_LIST_FOREACH (nd, tgt, pmix_nodeinfo_t) { kv = PMIX_NEW(pmix_kval_t); /* if the peer's version is earlier than v3.1, then the * info must be provided as a data_array with a key * of the node's name as earlier versions don't understand * node_info arrays */ if (PMIX_PEER_IS_EARLIER(peer, 3, 1, 0)) { if (NULL == nd->hostname) { /* skip this one */ continue; } kv->key = strdup(nd->hostname); } else { /* everyone else uses a node_info array */ kv->key = strdup(PMIX_NODE_INFO_ARRAY); } kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } nds = pmix_list_get_size(&nd->info); if (NULL != nd->hostname) { ++nds; } if (UINT32_MAX != nd->nodeid) { ++nds; } PMIX_DATA_ARRAY_CREATE(darray, nds, PMIX_INFO); if (NULL == darray) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } iptr = (pmix_info_t *) darray->array; n = 0; if (NULL != nd->hostname) { PMIX_INFO_LOAD(&iptr[n], PMIX_HOSTNAME, nd->hostname, PMIX_STRING); ++n; } if (UINT32_MAX != nd->nodeid) { PMIX_INFO_LOAD(&iptr[n], PMIX_NODEID, &nd->nodeid, PMIX_UINT32); ++n; } PMIX_LIST_FOREACH (kp2, &nd->info, pmix_kval_t) { pmix_output_verbose(12, pmix_gds_base_framework.framework_output, "%s gds:hash:fetch_nodearray adding key %s", PMIX_NAME_PRINT(&pmix_globals.myid), kp2->key); PMIX_LOAD_KEY(iptr[n].key, kp2->key); rc = PMIx_Value_xfer(&iptr[n].value, kp2->value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DATA_ARRAY_FREE(darray); PMIX_RELEASE(kv); return rc; } ++n; } kv->value->data.darray = darray; kv->value->type = PMIX_DATA_ARRAY; pmix_list_append(kvs, &kv->super); } return PMIX_SUCCESS; } /* assume they want it from this node */ hostname = pmix_globals.hostname; } /* scan the list of nodes to find the matching entry */ nd = NULL; if (UINT32_MAX!= nid) { PMIX_LIST_FOREACH (ndptr, tgt, pmix_nodeinfo_t) { if (UINT32_MAX != ndptr->nodeid && nid == ndptr->nodeid) { nd = ndptr; break; } } } else if (NULL != hostname) { nd = pmix_gds_hash_check_nodename(tgt, hostname); } if (NULL == nd) { // the node is not present in the job, which means // there were no procs on that node - or the node // is unknown, which would indicate an error in // specifying it return PMIX_ERR_NOT_FOUND; } /* if they want it all, give it to them */ if (NULL == key) { kv = PMIX_NEW(pmix_kval_t); /* if the proc's version is earlier than v3.1, then the * info must be provided as a data_array with a key * of the node's name as earlier versions don't understand * node_info arrays */ if (PMIX_PEER_IS_EARLIER(peer, 3, 1, 0)) { if (NULL == nd->hostname) { kv->key = strdup(pmix_globals.hostname); } else { kv->key = strdup(nd->hostname); } } else { /* everyone else uses a node_info array */ kv->key = strdup(PMIX_NODE_INFO_ARRAY); } kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } nds = pmix_list_get_size(&nd->info); if (NULL != nd->hostname) { ++nds; } if (UINT32_MAX != nd->nodeid) { ++nds; } PMIX_DATA_ARRAY_CREATE(darray, nds, PMIX_INFO); if (NULL == darray) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } iptr = (pmix_info_t *) darray->array; n = 0; if (NULL != nd->hostname) { PMIX_INFO_LOAD(&iptr[n], PMIX_HOSTNAME, nd->hostname, PMIX_STRING); ++n; } if (UINT32_MAX != nd->nodeid) { PMIX_INFO_LOAD(&iptr[n], PMIX_NODEID, &nd->nodeid, PMIX_UINT32); ++n; } PMIX_LIST_FOREACH (kp2, &nd->info, pmix_kval_t) { pmix_output_verbose(12, pmix_gds_base_framework.framework_output, "%s gds:hash:fetch_nodearray adding key %s", PMIX_NAME_PRINT(&pmix_globals.myid), kp2->key); PMIX_LOAD_KEY(iptr[n].key, kp2->key); rc = PMIx_Value_xfer(&iptr[n].value, kp2->value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DATA_ARRAY_FREE(darray); PMIX_RELEASE(kv); return rc; } ++n; } kv->value->data.darray = darray; kv->value->type = PMIX_DATA_ARRAY; pmix_list_append(kvs, &kv->super); return PMIX_SUCCESS; } /* scan the info list of this node to find the key they want */ rc = PMIX_ERR_DATA_VALUE_NOT_FOUND; PMIX_LIST_FOREACH (kp2, &nd->info, pmix_kval_t) { if (PMIX_CHECK_KEY(kp2, key)) { pmix_output_verbose(12, pmix_gds_base_framework.framework_output, "%s gds:hash:fetch_nodearray adding key %s", PMIX_NAME_PRINT(&pmix_globals.myid), kp2->key); /* since they only asked for one key, return just that value */ kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(kp2->key); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } rc = PMIx_Value_xfer(kv->value, kp2->value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kv); return rc; } pmix_list_append(kvs, &kv->super); break; } } return rc; } pmix_status_t pmix_gds_hash_fetch_appinfo(pmix_peer_t *peer, const char *key, pmix_list_t *tgt, pmix_info_t *info, size_t ninfo, pmix_list_t *kvs) { size_t n, nds; pmix_status_t rc; uint32_t appnum; bool found = false; pmix_apptrkr_t *app, *apptr; pmix_kval_t *kv, *kp2; pmix_data_array_t *darray; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "FETCHING APP INFO WITH %d APPS", (int) pmix_list_get_size(tgt)); /* scan for the appnum to identify * which app they are asking about */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_APPNUM)) { rc = PMIx_Value_get_number(&info[n].value, &appnum, PMIX_UINT32); if (PMIX_SUCCESS != rc) { return rc; } found = true; break; } } if (!found) { /* if the key is NULL, then they want all the info from * all apps */ if (NULL == key) { PMIX_LIST_FOREACH (apptr, tgt, pmix_apptrkr_t) { kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(PMIX_APP_INFO_ARRAY); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } nds = pmix_list_get_size(&apptr->appinfo) + 1; PMIX_DATA_ARRAY_CREATE(darray, nds, PMIX_INFO); if (NULL == darray) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } info = (pmix_info_t *) darray->array; n = 0; /* put in the appnum */ PMIX_INFO_LOAD(&info[n], PMIX_APPNUM, &apptr->appnum, PMIX_UINT32); ++n; PMIX_LIST_FOREACH (kp2, &apptr->appinfo, pmix_kval_t) { PMIX_LOAD_KEY(info[n].key, kp2->key); rc = PMIx_Value_xfer(&info[n].value, kp2->value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DATA_ARRAY_FREE(darray); PMIX_RELEASE(kv); return rc; } ++n; } kv->value->data.darray = darray; kv->value->type = PMIX_DATA_ARRAY; pmix_list_append(kvs, &kv->super); } return PMIX_SUCCESS; } /* assume they are asking for our app */ appnum = pmix_globals.appnum; } /* scan the list of apps to find the matching entry */ app = NULL; PMIX_LIST_FOREACH (apptr, tgt, pmix_apptrkr_t) { if (appnum == apptr->appnum) { app = apptr; break; } } if (NULL == app) { return PMIX_ERR_NOT_FOUND; } /* see if they wanted to know something about a node that * is associated with this app */ rc = pmix_gds_hash_fetch_nodeinfo(peer, key, &app->nodeinfo, info, ninfo, kvs); if (PMIX_ERR_DATA_VALUE_NOT_FOUND != rc && PMIX_ERR_NOT_FOUND != rc) { return rc; } /* scan the info list of this app to generate the results */ rc = PMIX_ERR_NOT_FOUND; PMIX_LIST_FOREACH (kv, &app->appinfo, pmix_kval_t) { if (NULL == key || PMIX_CHECK_KEY(kv, key)) { kp2 = PMIX_NEW(pmix_kval_t); kp2->key = strdup(kv->key); kp2->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); rc = PMIx_Value_xfer(kp2->value, kv->value); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(kp2); return rc; } pmix_list_append(kvs, &kp2->super); rc = PMIX_SUCCESS; if (NULL != key) { break; } } } return rc; } pmix_status_t pmix_gds_hash_fetch(struct pmix_peer_t *pr, const pmix_proc_t *proc, pmix_scope_t scope, bool copy, const char *key, pmix_info_t qualifiers[], size_t nqual, pmix_list_t *kvs) { pmix_peer_t *peer = (pmix_peer_t*)pr; pmix_job_t *trk; pmix_status_t rc; pmix_kval_t *kv, *kvptr; pmix_info_t *iptr; size_t n, ninfo, niptr; pmix_hash_table_t *ht; pmix_rank_t rnk; pmix_list_t rkvs; bool sessioninfo = false; bool nodeinfo = false; bool appinfo = false; bool sidgiven = false; bool nigiven = false; bool apigiven = false; pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "%s pmix:gds:hash fetch %s for proc %s on scope %s on behalf of %s", PMIX_NAME_PRINT(&pmix_globals.myid), (NULL == key) ? "NULL" : key, PMIX_NAME_PRINT(proc), PMIx_Scope_string(scope), PMIX_PEER_PRINT(peer)); PMIX_HIDE_UNUSED_PARAMS(copy); /* see if we have a tracker for this nspace - we will * if we already cached the job info for it. If we * didn't then we'll have no idea how to answer any * questions */ trk = pmix_gds_hash_get_tracker(proc->nspace, false); if (NULL == trk) { /* let the caller know */ return PMIX_ERR_INVALID_NAMESPACE; } /* if the rank is wildcard and the key is NULL, then * they are asking for a complete copy of the job-level * info for this nspace - retrieve it */ if (NULL == key && PMIX_RANK_WILDCARD == proc->rank) { /* fetch all values from the hash table tied to rank=wildcard */ rc = pmix_hash_fetch(&trk->internal, PMIX_RANK_WILDCARD, NULL, NULL, 0, kvs, NULL); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { return rc; } /* also need to add any job-level info */ PMIX_LIST_FOREACH (kvptr, &trk->jobinfo, pmix_kval_t) { kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(kvptr->key); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_XFER(rc, kv->value, kvptr->value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kv); return rc; } pmix_list_append(kvs, &kv->super); } /* collect all the relevant session-level info */ rc = pmix_gds_hash_fetch_sessioninfo(peer, NULL, trk, qualifiers, nqual, kvs); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { return rc; } /* collect the relevant node-level info */ rc = pmix_gds_hash_fetch_nodeinfo(peer, NULL, &trk->nodeinfo, qualifiers, nqual, kvs); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { return rc; } /* collect the relevant app-level info */ rc = pmix_gds_hash_fetch_appinfo(peer, NULL, &trk->apps, qualifiers, nqual, kvs); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { return rc; } /* finally, we need the job-level info for each rank in the job */ for (rnk = 0; rnk < trk->nptr->nprocs; rnk++) { PMIX_CONSTRUCT(&rkvs, pmix_list_t); rc = pmix_hash_fetch(&trk->internal, rnk, NULL, NULL, 0, &rkvs, NULL); if (PMIX_ERR_NOMEM == rc) { PMIX_LIST_DESTRUCT(&rkvs); return rc; } if (0 == pmix_list_get_size(&rkvs)) { PMIX_DESTRUCT(&rkvs); continue; } ninfo = pmix_list_get_size(&rkvs); /* setup to return the result */ PMIX_KVAL_NEW(kv, PMIX_PROC_DATA); kv->value->type = PMIX_DATA_ARRAY; niptr = ninfo + 1; // need space for the rank PMIX_DATA_ARRAY_CREATE(kv->value->data.darray, niptr, PMIX_INFO); iptr = (pmix_info_t*)kv->value->data.darray->array; /* start with the rank */ PMIX_INFO_LOAD(&iptr[0], PMIX_RANK, &rnk, PMIX_PROC_RANK); /* now transfer rest of data across */ n = 1; PMIX_LIST_FOREACH(kvptr, &rkvs, pmix_kval_t) { PMIX_LOAD_KEY(iptr[n].key, kvptr->key); PMIx_Value_xfer(&iptr[n].value, kvptr->value); ++n; } /* add to the results */ pmix_list_append(kvs, &kv->super); /* release the search result */ PMIX_LIST_DESTRUCT(&rkvs); } return PMIX_SUCCESS; } /* see if they are asking for session, node, or app-level info */ for (n = 0; n < nqual; n++) { if (PMIX_CHECK_KEY(&qualifiers[n], PMIX_SESSION_INFO)) { sessioninfo = PMIX_INFO_TRUE(&qualifiers[n]); sidgiven = true; } else if (PMIX_CHECK_KEY(&qualifiers[n], PMIX_NODE_INFO)) { nodeinfo = PMIX_INFO_TRUE(&qualifiers[n]); nigiven = true; } else if (PMIX_CHECK_KEY(&qualifiers[n], PMIX_APP_INFO)) { appinfo = PMIX_INFO_TRUE(&qualifiers[n]); apigiven = true; } } /* check for session/node/app keys in the absence of corresponding qualifier */ if (NULL != key && !sidgiven && !nigiven && !apigiven) { if (pmix_check_session_info(key)) { sessioninfo = true; } else if (pmix_check_node_info(key)) { nodeinfo = true; } else if (pmix_check_app_info(key)) { appinfo = true; } } if (sessioninfo) { rc = pmix_gds_hash_fetch_sessioninfo(peer, key, trk, qualifiers, nqual, kvs); return rc; } if (!PMIX_RANK_IS_VALID(proc->rank)) { if (nodeinfo) { rc = pmix_gds_hash_fetch_nodeinfo(peer, key, &trk->nodeinfo, qualifiers, nqual, kvs); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc && PMIX_RANK_WILDCARD == proc->rank) { /* need to check internal as we might have an older peer */ ht = &trk->internal; goto doover; } return rc; } else if (appinfo) { rc = pmix_gds_hash_fetch_appinfo(peer, key, &trk->apps, qualifiers, nqual, kvs); if (PMIX_SUCCESS != rc && PMIX_RANK_WILDCARD == proc->rank) { /* need to check internal as we might have an older peer */ ht = &trk->internal; goto doover; } return rc; } } /* fetch from the corresponding hash table - note that * we always provide a copy as we don't support * shared memory */ if (PMIX_INTERNAL == scope || PMIX_SCOPE_UNDEF == scope || PMIX_GLOBAL == scope || PMIX_RANK_WILDCARD == proc->rank) { ht = &trk->internal; } else if (PMIX_LOCAL == scope || PMIX_GLOBAL == scope) { ht = &trk->local; } else if (PMIX_REMOTE == scope) { ht = &trk->remote; } else { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } doover: /* if rank=PMIX_RANK_UNDEF, then we need to search all * known ranks for this nspace as any one of them could * be the source */ if (PMIX_RANK_UNDEF == proc->rank) { for (rnk = 0; rnk < trk->nptr->nprocs; rnk++) { rc = pmix_hash_fetch(ht, rnk, key, qualifiers, nqual, kvs, NULL); if (PMIX_ERR_NOMEM == rc) { return rc; } if (PMIX_SUCCESS == rc && NULL != key) { return rc; } } /* also need to check any job-level info */ PMIX_LIST_FOREACH (kvptr, &trk->jobinfo, pmix_kval_t) { if (NULL == key || PMIX_CHECK_KEY(kvptr, key)) { kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(kvptr->key); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); PMIX_VALUE_XFER(rc, kv->value, kvptr->value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kv); return rc; } pmix_list_append(kvs, &kv->super); if (NULL != key) { break; } } } if (NULL == key) { /* and need to add all job info just in case that was * passed via a different GDS component */ rc = pmix_hash_fetch(&trk->internal, PMIX_RANK_WILDCARD, NULL, NULL, 0, kvs, NULL); } else { rc = PMIX_ERR_NOT_FOUND; } } else { rc = pmix_hash_fetch(ht, proc->rank, key, qualifiers, nqual, kvs, NULL); } if (PMIX_SUCCESS == rc) { if (NULL != key && PMIX_CHECK_RESERVED_KEY(key)) { // there is no need to check other scopes for // reserved keys return PMIX_SUCCESS; } if (PMIX_GLOBAL == scope) { if (ht == &trk->local) { /* need to do this again for the remote data */ ht = &trk->remote; goto doover; } else if (ht == &trk->internal) { /* check local */ ht = &trk->local; goto doover; } } } else { if (PMIX_GLOBAL == scope || PMIX_SCOPE_UNDEF == scope) { if (ht == &trk->internal) { /* need to also try the local data */ ht = &trk->local; goto doover; } else if (ht == &trk->local) { /* need to also try the remote data */ ht = &trk->remote; goto doover; } } } if (0 == pmix_list_get_size(kvs)) { /* if we didn't find it and the rank was valid, then * check to see if the data exists in a different scope. * This is done to avoid having the process go into a * timeout wait when the data will never appear within * the specified scope */ if (PMIX_RANK_IS_VALID(proc->rank)) { if (PMIX_LOCAL == scope) { /* check the remote scope */ rc = pmix_hash_fetch(&trk->remote, proc->rank, key, qualifiers, nqual, kvs, NULL); if (PMIX_SUCCESS == rc || 0 < pmix_list_get_size(kvs)) { while (NULL != (kv = (pmix_kval_t *) pmix_list_remove_first(kvs))) { PMIX_RELEASE(kv); } rc = PMIX_ERR_EXISTS_OUTSIDE_SCOPE; } else { rc = PMIX_ERR_NOT_FOUND; } } else if (PMIX_REMOTE == scope) { /* check the local scope */ rc = pmix_hash_fetch(&trk->local, proc->rank, key, qualifiers, nqual, kvs, NULL); if (PMIX_SUCCESS == rc || 0 < pmix_list_get_size(kvs)) { while (NULL != (kv = (pmix_kval_t *) pmix_list_remove_first(kvs))) { PMIX_RELEASE(kv); } rc = PMIX_ERR_EXISTS_OUTSIDE_SCOPE; } else { rc = PMIX_ERR_NOT_FOUND; } } } else { rc = PMIX_ERR_NOT_FOUND; } } else { // since we found something, the fetch is a success. // We need to set the status here because the fetch on the // last scope we tried might not have succeeded, but // we found things in an earlier scope we tried rc = PMIX_SUCCESS; } return rc; } pmix_status_t pmix_gds_hash_fetch_arrays(struct pmix_peer_t *pr, pmix_buffer_t *reply) { pmix_peer_t *peer = (pmix_peer_t *) pr; pmix_namespace_t *ns = peer->nptr; pmix_job_t *trk; pmix_list_t kvs; pmix_kval_t *kv; pmix_status_t rc; if (!PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { /* this function is only available on servers */ PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_SUPPORTED; } pmix_output_verbose(2, pmix_gds_base_framework.framework_output, "%s pmix:gds:hash fetch arrays for proc [%s:%u]", PMIX_NAME_PRINT(&pmix_globals.myid), peer->info->pname.nspace, peer->info->pname.rank); /* see if we have a tracker for this nspace - we will * if we already cached the job info for it. If we * didn't then we'll have no idea how to answer any * questions */ trk = pmix_gds_hash_get_tracker(ns->nspace, false); if (NULL == trk) { /* let the caller know */ return PMIX_ERR_INVALID_NAMESPACE; } PMIX_CONSTRUCT(&kvs, pmix_list_t); rc = pmix_gds_hash_fetch_sessioninfo(peer, NULL, trk, NULL, 0, &kvs); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { PMIX_ERROR_LOG(rc); PMIX_LIST_DESTRUCT(&kvs); return rc; } rc = pmix_gds_hash_fetch_nodeinfo(peer, NULL, &trk->nodeinfo, NULL, 0, &kvs); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { PMIX_ERROR_LOG(rc); PMIX_LIST_DESTRUCT(&kvs); return rc; } rc = pmix_gds_hash_fetch_appinfo(peer, NULL, &trk->apps, NULL, 0, &kvs); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { PMIX_ERROR_LOG(rc); PMIX_LIST_DESTRUCT(&kvs); return rc; } /* pack the results */ while (NULL != (kv = (pmix_kval_t*)pmix_list_remove_first(&kvs))) { PMIX_BFROPS_PACK(rc, peer, reply, kv, 1, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); break; } } PMIX_LIST_DESTRUCT(&kvs); return rc; } pmix-6.1.1~rc2/src/mca/gds/hash/gds_hash.h0000664000175000017500000001236115203536752020460 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_GDS_HASH_H #define PMIX_GDS_HASH_H #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_hash.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/mca/gds/gds.h" BEGIN_C_DECLS typedef struct { pmix_gds_base_component_t super; pmix_list_t mysessions; pmix_list_t myjobs; } pmix_gds_hash_component_t; /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_gds_hash_component_t pmix_mca_gds_hash_component; extern pmix_gds_base_module_t pmix_hash_module; /* Define a bitmask to track what information may not have * been provided but is computable from other info */ #define PMIX_HASH_PROC_DATA 0x00000001 #define PMIX_HASH_JOB_SIZE 0x00000002 #define PMIX_HASH_MAX_PROCS 0x00000004 #define PMIX_HASH_NUM_NODES 0x00000008 #define PMIX_HASH_PROC_MAP 0x00000010 #define PMIX_HASH_NODE_MAP 0x00000020 /* struct definitions */ typedef struct { pmix_list_item_t super; uint32_t session; pmix_list_t sessioninfo; pmix_list_t nodeinfo; } pmix_session_t; PMIX_CLASS_DECLARATION(pmix_session_t); typedef struct { pmix_list_item_t super; char *ns; pmix_namespace_t *nptr; pmix_hash_table_t internal; pmix_hash_table_t remote; pmix_hash_table_t local; bool gdata_added; pmix_list_t jobinfo; pmix_list_t apps; pmix_list_t nodeinfo; pmix_session_t *session; } pmix_job_t; PMIX_CLASS_DECLARATION(pmix_job_t); typedef struct { pmix_list_item_t super; uint32_t appnum; pmix_list_t appinfo; pmix_list_t nodeinfo; pmix_job_t *job; } pmix_apptrkr_t; PMIX_CLASS_DECLARATION(pmix_apptrkr_t); typedef struct { pmix_list_item_t super; uint32_t nodeid; char *hostname; char **aliases; pmix_list_t info; } pmix_nodeinfo_t; PMIX_CLASS_DECLARATION(pmix_nodeinfo_t); extern pmix_status_t pmix_gds_hash_process_node_array(pmix_value_t *val, pmix_list_t *tgt); extern pmix_status_t pmix_gds_hash_process_app_array(pmix_value_t *val, pmix_job_t *trk); extern pmix_status_t pmix_gds_hash_process_job_array(pmix_info_t *info, pmix_job_t *trk, uint32_t *flags, char ***procs, char ***nodes); extern pmix_status_t pmix_gds_hash_process_session_array(pmix_value_t *val, pmix_job_t *trk); extern pmix_job_t *pmix_gds_hash_get_tracker(const pmix_nspace_t nspace, bool create); extern pmix_session_t* pmix_gds_hash_check_session(pmix_job_t *trk, uint32_t sid, bool create); extern pmix_status_t pmix_gds_hash_xfer_sessioninfo(pmix_peer_t *peer, pmix_session_t *sptr, const char *key, pmix_list_t *kvs); extern bool pmix_gds_hash_check_hostname(char *h1, char *h2); extern bool pmix_gds_hash_check_node(pmix_nodeinfo_t *n1, pmix_nodeinfo_t *n2); extern pmix_nodeinfo_t* pmix_gds_hash_check_nodename(pmix_list_t *nodes, char *hostname); extern pmix_status_t pmix_gds_hash_store_map(pmix_job_t *trk, char **nodes, char **ppn, uint32_t flags); extern pmix_status_t pmix_gds_hash_fetch(struct pmix_peer_t *peer, const pmix_proc_t *proc, pmix_scope_t scope, bool copy, const char *key, pmix_info_t qualifiers[], size_t nqual, pmix_list_t *kvs); extern pmix_status_t pmix_gds_hash_fetch_sessioninfo(pmix_peer_t *peer, const char *key, pmix_job_t *trk, pmix_info_t *info, size_t ninfo, pmix_list_t *kvs); extern pmix_status_t pmix_gds_hash_fetch_nodeinfo(pmix_peer_t *peer, const char *key, pmix_list_t *tgt, pmix_info_t *info, size_t ninfo, pmix_list_t *kvs); extern pmix_status_t pmix_gds_hash_fetch_appinfo(pmix_peer_t *peer, const char *key, pmix_list_t *tgt, pmix_info_t *info, size_t ninfo, pmix_list_t *kvs); extern pmix_status_t pmix_gds_hash_store(const pmix_proc_t *proc, pmix_scope_t scope, pmix_kval_t *kv); extern pmix_status_t pmix_gds_hash_store_qualified(pmix_hash_table_t *ht, pmix_rank_t rank, pmix_value_t *value); extern pmix_status_t pmix_gds_hash_fetch_arrays(struct pmix_peer_t *pr, pmix_buffer_t *reply); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/gds/Makefile.am0000664000175000017500000000254315203536752017641 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2017 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(LTDLINCL) # main library setup noinst_LTLIBRARIES = libmca_gds.la libmca_gds_la_SOURCES = # local files headers = gds.h sources = # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.include libmca_gds_la_SOURCES += $(headers) $(sources) distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/gds/gds.h0000664000175000017500000006375415203536752016546 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2016-2020 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2018 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_GDS_H #define PMIX_GDS_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/bfrops/bfrops_types.h" #include "src/mca/mca.h" /* The client dictates the GDS module that will be used to interact * with the server - this module is stored in pmix_globals.mypeer->compat.gds * Because that is a long address to keep typing out, convenience macros * are provided for when that module is to be used in an operation. * * However, an application can open any number of GDS modules for * purposes other than exchanging info with the server. For example, * an application may wish to utilize a DHT module for its own * peer-to-peer data sharing. Thus, the public and private interfaces * are deliberately designed to be generic. The macros should make * things easier for the typical internal operations * * NOTE: ALTHOUGH SOME GDS COMPONENTS MAY UTILIZE THEIR OWN INTERNAL * PROGRESS THREADS, THE GDS IS NOT GUARANTEED TO BE THREAD-SAFE. * GDS FUNCTIONS SHOULD THEREFORE ALWAYS BE CALLED IN A THREAD-SAFE * CONDITION - E.G., FROM WITHIN AN EVENT */ BEGIN_C_DECLS /* forward declaration */ struct pmix_peer_t; struct pmix_namespace_t; /* backdoor to base verbosity */ PMIX_EXPORT extern int pmix_gds_base_output; /** * Initialize the module. Returns an error if the module cannot * run, success if it can. */ typedef pmix_status_t (*pmix_gds_base_module_init_fn_t)(pmix_info_t info[], size_t ninfo); /** * Finalize the module. Tear down any allocated storage, disconnect * from any system support. */ typedef void (*pmix_gds_base_module_fini_fn_t)(void); /** * Assign a module per the requested directives. Modules should * review the provided directives to determine if they can support * the request. Modules are "scanned" in component priority order * and given an opportunity to respond. If a module offers itself, * it will provide a priority (which can be based on the directives * and therefore different from the component priority). The highest * returned priority received from a responder will be selected * and a pointer to its module returned */ typedef pmix_status_t (*pmix_gds_base_assign_module_fn_t)(pmix_info_t *info, size_t ninfo, int *priority); #define PMIX_GDS_CHECK_COMPONENT(p, s) (0 == strcmp((p)->nptr->compat.gds->name, (s))) #define PMIX_GDS_CHECK_PEER_COMPONENT(p1, p2) \ (0 == strcmp((p1)->nptr->compat.gds->name, (p2)->nptr->compat.gds->name)) /* SERVER FN: assemble the keys buffer for server answer */ typedef pmix_status_t (*pmix_gds_base_module_assemb_kvs_req_fn_t)(const pmix_proc_t *proc, pmix_list_t *kvs, pmix_buffer_t *buf, void *cbdata); /* define a macro for server keys answer based on peer */ #define PMIX_GDS_ASSEMB_KVS_REQ(s, p, r, k, b, c) \ do { \ pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \ (s) = PMIX_SUCCESS; \ if (NULL == _g->assemb_kvs_req) { \ if (0 == strcmp(_g->name, "hash")) { \ (s) = PMIX_ERR_NOT_SUPPORTED; \ } else { \ _g = pmix_globals.mypeer->nptr->compat.gds; \ } \ } \ if (NULL != _g->assemb_kvs_req) { \ pmix_output_verbose(1, pmix_gds_base_output, \ "[%s:%d] GDS ASSEMBLE REQ WITH %s", \ __FILE__, __LINE__, _g->name); \ (s) = _g->assemb_kvs_req(r, k, b, (void *) c); \ } \ } while (0) /* CLIENT FN: unpack buffer and key processing */ typedef pmix_status_t (*pmix_gds_base_module_accept_kvs_resp_fn_t)(pmix_buffer_t *buf); /* define a macro for client key processing from a server response based on peer */ #define PMIX_GDS_ACCEPT_KVS_RESP(s, p, b) \ do { \ pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \ (s) = PMIX_SUCCESS; \ if (NULL == _g->accept_kvs_resp) { \ if (0 == strcmp(_g->name, "hash")) { \ (s) = PMIX_ERR_NOT_SUPPORTED; \ } else { \ _g = pmix_globals.mypeer->nptr->compat.gds; \ } \ } \ if (NULL != _g->accept_kvs_resp) { \ pmix_output_verbose(1, pmix_gds_base_output, \ "[%s:%d] GDS ACCEPT RESP WITH %s", \ __FILE__, __LINE__, _g->name); \ (s) = _g->accept_kvs_resp(b); \ } \ } while (0) /* SERVER FN: cache job-level info in the server's GDS until client * procs connect and we discover which GDS module to use for them. * Note that this is essentially the same function as store_job_info, * only we don't have packed data on the server side, and don't want * to incur the overhead of packing it just to unpack it in the function. */ typedef pmix_status_t (*pmix_gds_base_module_cache_job_info_fn_t)(struct pmix_namespace_t *ns, pmix_info_t info[], size_t ninfo); /* define a convenience macro for caching job info */ #define PMIX_GDS_CACHE_JOB_INFO(s, p, n, i, ni) \ do { \ pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \ pmix_output_verbose(1, pmix_gds_base_output, "[%s:%d] GDS CACHE JOB INFO WITH %s", \ __FILE__, __LINE__, _g->name); \ (s) = _g->cache_job_info((struct pmix_namespace_t *) (n), (i), (ni)); \ } while (0) /* register job-level info - this is provided as a special function * to allow for optimization. Called solely by the server. We cannot * prepare the job-level info provided at PMIx_Register_nspace, because * we don't know the GDS component to use for that application until * a local client contacts us. Thus, the module is required to process * the job-level info cached in the pmix_namespace_t for this job and * do whatever is necessary to support the client, packing any required * return message into the provided buffer. * * This function will be called once for each local client of * a given nspace. PMIx assumes that all peers of a given nspace * will use the same GDS module. Thus, the module is free to perform * any relevant optimizations (e.g., packing the data only once and * then releasing the cached buffer once all local clients have * been serviced, or storing it once in shared memory and simply * returning the shared memory rendezvous information for subsequent * calls). * * Info provided in the reply buffer will be given to the "store_job_info" * API of the GDS module on the client. Since this should match the * module used by the server, each module has full knowledge and control * over what is in the reply buffer. * * The pmix_peer_t of the requesting client is provided here so that * the module can access the job-level info cached on the corresponding * pmix_namespace_t pointed to by the pmix_peer_t */ typedef pmix_status_t (*pmix_gds_base_module_register_job_info_fn_t)(struct pmix_peer_t *pr, pmix_buffer_t *reply); /* define a convenience macro for registering job info for * a given peer */ #define PMIX_GDS_REGISTER_JOB_INFO(s, p, b) \ do { \ pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \ pmix_output_verbose(1, pmix_gds_base_output, "[%s:%d] GDS REG JOB INFO WITH %s", __FILE__, \ __LINE__, _g->name); \ (s) = _g->register_job_info((struct pmix_peer_t *) (p), b); \ } while (0) /* update job-level info - this is provided as a special function * to allow for optimization. Called solely by the client. The buffer * provided to this API is the same one given to the server by the * corresponding "register_job_info" function */ typedef pmix_status_t (*pmix_gds_base_module_store_job_info_fn_t)(const char *nspace, pmix_buffer_t *buf); /* define a convenience macro for storing job info based on peer */ #define PMIX_GDS_STORE_JOB_INFO(s, p, n, b) \ do { \ pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \ pmix_output_verbose(1, pmix_gds_base_output, "[%s:%d] GDS STORE JOB INFO WITH %s", \ __FILE__, __LINE__, _g->name); \ (s) = _g->store_job_info(n, b); \ } while (0) /** * store key/value pair - these will either be values committed by the peer * and transmitted to the server, or values stored locally by the peer. * The format of the data depends on the GDS module. Note that data stored * with PMIX_INTERNAL scope should be stored solely within the process and * is never shared. * * @param peer pointer to pmix_peer_t object of the peer that * provided the data * * @param proc the proc that the data describes * * @param scope scope of the data * * @param kv key/value pair. * * @return PMIX_SUCCESS on success. */ typedef pmix_status_t (*pmix_gds_base_module_store_fn_t)(const pmix_proc_t *proc, pmix_scope_t scope, pmix_kval_t *kv); /* define a convenience macro for storing key-val pairs based on peer */ #define PMIX_GDS_STORE_KV(s, p, pc, sc, k) \ do { \ pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \ (s) = PMIX_SUCCESS; \ if (NULL == _g->store) { \ if (0 == strcmp(_g->name, "hash")) { \ (s) = PMIX_ERR_NOT_SUPPORTED; \ } else { \ _g = pmix_globals.mypeer->nptr->compat.gds; \ } \ } \ if (NULL != _g->store) { \ pmix_output_verbose(1, pmix_gds_base_output, \ "[%s:%d] GDS STORE KV WITH %s", \ __FILE__, __LINE__, _g->name); \ (s) = _g->store(pc, sc, k); \ } \ } while (0) /** * unpack and store a data "blob" from a peer so that the individual * elements can later be retrieved. This is an optimization path to * avoid repeatedly storing pmix_kval_t's for multiple local procs * from the same nspace. * * buff - packed modex data collected across the operation * * cbdata - pointer to modex callback data * */ typedef pmix_status_t (*pmix_gds_base_module_store_modex_fn_t)(pmix_buffer_t *buff, void *cbdata); /** * define a convenience macro for storing modex byte objects * * r - return status code * * b - pointer to pmix_buffer_t containing the data * * t - pointer to the modex server tracker */ #define PMIX_GDS_STORE_MODEX(r, b, t) \ do { \ pmix_gds_base_module_t *_g = pmix_globals.mypeer->nptr->compat.gds; \ pmix_output_verbose(1, pmix_gds_base_output, \ "[%s:%d] GDS STORE MODEX WITH %s", __FILE__, \ __LINE__, _g->name); \ (r) = _g->store_modex(b, t); \ } while (0) typedef pmix_status_t (*pmix_gds_base_module_mark_modex_complete_fn_t)(struct pmix_peer_t *peer, pmix_list_t *nslist, pmix_buffer_t *buff); #define PMIX_GDS_MARK_MODEX_COMPLETE(r, p, l, b) \ do { \ pmix_gds_base_module_t *_g = pmix_globals.mypeer->nptr->compat.gds; \ pmix_output_verbose(1, pmix_gds_base_output, \ "[%s:%d] GDS MARK MODEX COMPLETE WITH %s", \ __FILE__, __LINE__, _g->name); \ (r) = _g->mark_modex_complete(p, l, b); \ } while (0) typedef pmix_status_t (*pmix_gds_base_module_recv_modex_complete_fn_t)(pmix_buffer_t *buff); #define PMIX_GDS_RECV_MODEX_COMPLETE(r, p, b) \ do { \ pmix_gds_base_module_t *_g = pmix_globals.mypeer->nptr->compat.gds; \ pmix_output_verbose(1, pmix_gds_base_output, \ "[%s:%d] GDS RECV MODEX COMPLETE WITH %s", \ __FILE__, __LINE__, _g->name); \ (r) = _g->recv_modex_complete(b); \ } while (0) /** * fetch value corresponding to provided key from within the defined * scope. A NULL key returns all values committed by the given peer * for that scope. * * @param peer peer object of the proc requesting the info - needed * because the server can request info on behalf of another * process, and the fetch response has to be formatted * to match the _requesting_ process * * @param proc namespace and rank whose info is being requested * * @param key key. * * @param scope scope of the data to be considered * * @param copy true if the caller _requires_ a copy of the data. This * is used when the requestor is off-node. If * set to false, then the GDS component can provide * either a copy of the data, or shmem contact info * to the location of the data * * @param info array of pmix_info_t the caller provided as * qualifiers to guide the request * * @param ninfo number of elements in the info array * * @param kvs pointer to a list that will be populated with the * returned pmix_kval_t data * * @return PMIX_SUCCESS on success. * * Note: all available job-level data for a given nspace can be fetched * by passing a proc with rank=PMIX_RANK_WILDCARD and a NULL key. Similarly, * passing a NULL key for a non-wildcard rank will return all data "put" * by that rank. Scope is ignored for job-level data requests. * * When a specific rank if provided with a NULL key, then data for only * that rank is returned. If the scope is PMIX_LOCAL, then the returned * data shall include only data that was specifically "put" to local scope, * plus any data that was put to PMIX_GLOBAL scope. Similarly, a scope of * PMIX_REMOTE will return data that was "put" to remote scope, plus * any data that was put to PMIX_GLOBAL scope. A scope of PMIX_GLOBAL * will return LOCAL, REMOTE, and GLOBAL data. * * Data stored with PMIX_INTERNAL scope can be retrieved with that scope. */ typedef pmix_status_t (*pmix_gds_base_module_fetch_fn_t)(struct pmix_peer_t *peer, const pmix_proc_t *proc, pmix_scope_t scope, bool copy, const char *key, pmix_info_t info[], size_t ninfo, pmix_list_t *kvs); /* define a convenience macro for fetch key-val pairs based on peer, * passing a pmix_cb_t containing all the required info */ #define PMIX_GDS_FETCH_KV(s, p, c) \ do { \ pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \ pmix_output_verbose(1, pmix_gds_base_output, \ "[%s:%d] GDS FETCH KV WITH %s", \ __FILE__, __LINE__, _g->name); \ (s) = _g->fetch((p), (c)->proc, (c)->scope, (c)->copy, (c)->key, \ (c)->info, (c)->ninfo, &(c)->kvs); \ } while (0) /** * Add any envars to a peer's environment that the module needs * to communicate. The API stub will rotate across all active modules, giving * each a chance to contribute * * @return PMIX_SUCCESS on success. */ typedef pmix_status_t (*pmix_gds_base_module_setup_fork_fn_t)(const pmix_proc_t *proc, char ***env); /** * Define a new nspace in the GDS * * @param nspace namespace string * * @return PMIX_SUCCESS on success. */ typedef pmix_status_t (*pmix_gds_base_module_add_nspace_fn_t)(const char *nspace, uint32_t nlocalprocs, pmix_info_t info[], size_t ninfo); /* define a convenience macro for add_nspace based on peer */ #define PMIX_GDS_ADD_NSPACE(s, n, ls, i, ni) \ do { \ pmix_gds_base_active_module_t *_g; \ pmix_status_t _s = PMIX_SUCCESS; \ (s) = PMIX_SUCCESS; \ pmix_output_verbose(1, pmix_gds_base_output, "[%s:%d] GDS ADD NSPACE %s", __FILE__, \ __LINE__, (n)); \ PMIX_LIST_FOREACH (_g, &pmix_gds_globals.actives, pmix_gds_base_active_module_t) { \ if (NULL != _g->module->add_nspace) { \ _s = _g->module->add_nspace(n, ls, i, ni); \ } \ if (PMIX_SUCCESS != _s) { \ (s) = PMIX_ERROR; \ } \ } \ } while (0) /** * Delete nspace and its associated data * * @param nspace namespace string * * @return PMIX_SUCCESS on success. */ typedef pmix_status_t (*pmix_gds_base_module_del_nspace_fn_t)(const char *nspace); /* define a convenience macro for del_nspace based on peer */ #define PMIX_GDS_DEL_NSPACE(s, n) \ do { \ pmix_gds_base_active_module_t *_g; \ pmix_status_t _s = PMIX_SUCCESS; \ (s) = PMIX_SUCCESS; \ pmix_output_verbose(1, pmix_gds_base_output, "[%s:%d] GDS DEL NSPACE %s", __FILE__, \ __LINE__, (n)); \ PMIX_LIST_FOREACH (_g, &pmix_gds_globals.actives, pmix_gds_base_active_module_t) { \ if (NULL != _g->module->del_nspace) { \ _s = _g->module->del_nspace(n); \ } \ if (PMIX_SUCCESS != _s) { \ (s) = PMIX_ERROR; \ } \ } \ } while (0) /* define a convenience macro for is_tsafe for fetch operation */ #define PMIX_GDS_FETCH_IS_TSAFE(s, p) \ do { \ pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \ pmix_output_verbose(1, pmix_gds_base_output, \ "[%s:%d] GDS FETCH IS THREAD SAFE WITH %s", \ __FILE__, __LINE__, _g->name); \ if (true == _g->is_tsafe) { \ (s) = PMIX_SUCCESS; \ } else { \ (s) = PMIX_ERR_NOT_SUPPORTED; \ } \ } while(0) typedef pmix_status_t (*pmix_gds_base_module_fetch_array_fn_t)(struct pmix_peer_t *pr, pmix_buffer_t *reply); /* define a convenience macro for fetching array info for * a given peer */ #define PMIX_GDS_FETCH_INFO_ARRAYS(s, p, b) \ do { \ pmix_gds_base_module_t *_g = pmix_globals.mypeer->nptr->compat.gds; \ pmix_output_verbose(1, pmix_gds_base_output, \ "[%s:%d] GDS FETCH ARRAYS WITH %s", \ __FILE__, __LINE__, _g->name); \ (s) = _g->fetch_arrays((struct pmix_peer_t*)(p), b); \ } while(0) /* structure for gds modules */ typedef struct { const char *name; const bool is_tsafe; pmix_gds_base_module_init_fn_t init; pmix_gds_base_module_fini_fn_t finalize; pmix_gds_base_assign_module_fn_t assign_module; pmix_gds_base_module_cache_job_info_fn_t cache_job_info; pmix_gds_base_module_register_job_info_fn_t register_job_info; pmix_gds_base_module_store_job_info_fn_t store_job_info; pmix_gds_base_module_store_fn_t store; pmix_gds_base_module_store_modex_fn_t store_modex; pmix_gds_base_module_fetch_fn_t fetch; pmix_gds_base_module_setup_fork_fn_t setup_fork; pmix_gds_base_module_add_nspace_fn_t add_nspace; pmix_gds_base_module_del_nspace_fn_t del_nspace; pmix_gds_base_module_assemb_kvs_req_fn_t assemb_kvs_req; pmix_gds_base_module_accept_kvs_resp_fn_t accept_kvs_resp; pmix_gds_base_module_fetch_array_fn_t fetch_arrays; pmix_gds_base_module_mark_modex_complete_fn_t mark_modex_complete; pmix_gds_base_module_recv_modex_complete_fn_t recv_modex_complete; } pmix_gds_base_module_t; /* NOTE: there is no public GDS interface structure - all access is * done directly to/from an assigned module */ /* define the component structure */ typedef pmix_mca_base_component_t pmix_gds_base_component_t; /* * Macro for use in components that are of type gds */ #define PMIX_GDS_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("gds", 1, 0, 0) END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/bfrops/0000775000175000017500000000000015203536752016317 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/bfrops/v20/0000775000175000017500000000000015203536752016726 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/bfrops/v20/unpack.c0000664000175000017500000015542215203536752020364 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "bfrop_pmix20.h" #include "internal.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" pmix_status_t pmix20_bfrop_unpack(pmix_buffer_t *buffer, void *dst, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t rc, ret; int32_t local_num, n = 1; pmix_data_type_t local_type; pmix_pointer_array_t *regtypes = &pmix_mca_bfrops_v20_component.types; /* check for error */ if (NULL == buffer || NULL == dst || NULL == num_vals) { return PMIX_ERR_BAD_PARAM; } /* if user provides a zero for num_vals, then there is no storage allocated * so return an appropriate error */ if (0 == *num_vals) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: inadequate space ( %p, %p, %lu, %d )\n", (void *) buffer, dst, (long unsigned int) *num_vals, (int) type); return PMIX_ERR_UNPACK_INADEQUATE_SPACE; } /** Unpack the declared number of values * REMINDER: it is possible that the buffer is corrupted and that * the BFROP will *think* there is a proper int32_t variable at the * beginning of the unpack region - but that the value is bogus (e.g., just * a byte field in a string array that so happens to have a value that * matches the int32_t data type flag). Therefore, this error check is * NOT completely safe. This is true for ALL unpack functions, not just * int32_t as used here. */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix20_bfrop_get_data_type(regtypes, buffer, &local_type))) { *num_vals = 0; /* don't error log here as the user may be unpacking past * the end of the buffer, which isn't necessarily an error */ return rc; } if (PMIX_INT32 != local_type) { /* if the length wasn't first, then error */ *num_vals = 0; return PMIX_ERR_UNPACK_FAILURE; } } n = 1; PMIX_BFROPS_UNPACK_TYPE(rc, buffer, &local_num, &n, PMIX_INT32, regtypes); if (PMIX_SUCCESS != rc) { *num_vals = 0; /* don't error log here as the user may be unpacking past * the end of the buffer, which isn't necessarily an error */ return rc; } pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: found %d values for %d provided storage", local_num, *num_vals); /** if the storage provided is inadequate, set things up * to unpack as much as we can and to return an error code * indicating that everything was not unpacked - the buffer * is left in a state where it can not be further unpacked. */ if (local_num > *num_vals) { local_num = *num_vals; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: inadequate space ( %p, %p, %lu, %d )\n", (void *) buffer, dst, (long unsigned int) *num_vals, (int) type); ret = PMIX_ERR_UNPACK_INADEQUATE_SPACE; } else { /** enough or more than enough storage */ *num_vals = local_num; /** let the user know how many we actually unpacked */ ret = PMIX_SUCCESS; } /** Unpack the value(s) */ if (PMIX_SUCCESS != (rc = pmix20_bfrop_unpack_buffer(regtypes, buffer, dst, &local_num, type))) { *num_vals = 0; ret = rc; } return ret; } pmix_status_t pmix20_bfrop_unpack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dst, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t rc; pmix_data_type_t local_type, v20type; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_buffer( %p, %p, %lu, %d )\n", (void *) buffer, dst, (long unsigned int) *num_vals, (int) type); /* some v20 types are simply declared differently */ switch (type) { case PMIX_COMMAND: v20type = PMIX_UINT32; break; default: v20type = type; } /** Unpack the declared data type */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix20_bfrop_get_data_type(regtypes, buffer, &local_type))) { return rc; } /* if the data types don't match, then return an error */ if (v20type != local_type) { pmix_output(0, "PMIX bfrop:unpack: got type %d when expecting type %d", local_type, v20type); return PMIX_ERR_PACK_MISMATCH; } } PMIX_BFROPS_UNPACK_TYPE(rc, buffer, dst, num_vals, v20type, regtypes); return rc; } /* UNPACK GENERIC SYSTEM TYPES */ /* * BOOL */ pmix_status_t pmix20_bfrop_unpack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint8_t *src; bool *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_bool * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, *num_vals)) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ src = (uint8_t *) buffer->unpack_ptr; dst = (bool *) dest; for (i = 0; i < *num_vals; i++) { if (src[i]) { dst[i] = true; } else { dst[i] = false; } } /* update buffer pointer */ buffer->unpack_ptr += *num_vals; return PMIX_SUCCESS; } /* * INT */ pmix_status_t pmix20_bfrop_unpack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix20_bfrop_get_data_type(regtypes, buffer, &remote_type))) { return ret; } if (remote_type == BFROP_TYPE_INT) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, dest, num_vals, BFROP_TYPE_INT))) { } } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, int, remote_type, ret); } return ret; } /* * SIZE_T */ pmix_status_t pmix20_bfrop_unpack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix20_bfrop_get_data_type(regtypes, buffer, &remote_type))) { return ret; } if (remote_type == BFROP_TYPE_SIZE_T) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, dest, num_vals, BFROP_TYPE_SIZE_T))) { } } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, size_t, remote_type, ret); } return ret; } /* * PID_T */ pmix_status_t pmix20_bfrop_unpack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix20_bfrop_get_data_type(regtypes, buffer, &remote_type))) { return ret; } if (remote_type == BFROP_TYPE_PID_T) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, dest, num_vals, BFROP_TYPE_PID_T))) { } } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, pid_t, remote_type, ret); } return ret; } /* UNPACK FUNCTIONS FOR NON-GENERIC SYSTEM TYPES */ /* * BYTE, CHAR, INT8 */ pmix_status_t pmix20_bfrop_unpack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_byte * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, *num_vals)) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ memcpy(dest, buffer->unpack_ptr, *num_vals); /* update buffer pointer */ buffer->unpack_ptr += *num_vals; return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint16_t tmp, *desttmp = (uint16_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_int16 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = pmix_ntohs(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint32_t tmp, *desttmp = (uint32_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_int32 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = ntohl(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_INT16, regtypes); return ret; } pmix_status_t pmix20_bfrop_unpack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint64_t tmp, *desttmp = (uint64_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_int64 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = pmix_ntoh64(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; int32_t i, len, n = 1; char **sdest = (char **) dest; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < (*num_vals); ++i) { PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &len, &n, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 == len) { /* zero-length string - unpack the NULL */ sdest[i] = NULL; } else { sdest[i] = (char *) malloc(len); if (NULL == sdest[i]) { return PMIX_ERR_OUT_OF_RESOURCE; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, sdest[i], &len, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; float *desttmp = (float *) dest, tmp; pmix_status_t ret; char *convert; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_float * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(float))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 1; convert = NULL; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &convert, &n, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (NULL != convert) { tmp = strtof(convert, NULL); memcpy(&desttmp[i], &tmp, sizeof(tmp)); free(convert); } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; double *desttmp = (double *) dest, tmp; pmix_status_t ret; char *convert; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_double * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(double))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 1; convert = NULL; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &convert, &n, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (NULL != convert) { tmp = strtod(convert, NULL); memcpy(&desttmp[i], &tmp, sizeof(tmp)); free(convert); } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; int64_t tmp[2]; struct timeval *desttmp = (struct timeval *) dest, tt; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_timeval * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(struct timeval))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 2; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, tmp, &n, PMIX_INT64, regtypes); if (PMIX_SUCCESS != ret) { return ret; } tt.tv_sec = tmp[0]; tt.tv_usec = tmp[1]; memcpy(&desttmp[i], &tt, sizeof(tt)); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; time_t *desttmp = (time_t *) dest, tmp; pmix_status_t ret; uint64_t ui64; /* time_t is a system-dependent size, so cast it * to uint64_t as a generic safe size */ pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_time * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ui64, &n, PMIX_UINT64, regtypes); if (PMIX_SUCCESS != ret) { return ret; } tmp = (time_t) ui64; memcpy(&desttmp[i], &tmp, sizeof(tmp)); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack_status * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * (sizeof(pmix_status_t)))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_INT32, regtypes); return ret; } /* UNPACK FUNCTIONS FOR GENERIC PMIX TYPES */ /* * PMIX_VALUE */ static pmix_status_t unpack_val(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_value_t *val) { int32_t m; pmix_status_t ret; m = 1; switch (val->type) { case PMIX_UNDEF: break; case PMIX_BOOL: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.flag, &m, PMIX_BOOL))) { return ret; } break; case PMIX_BYTE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.byte, &m, PMIX_BYTE))) { return ret; } break; case PMIX_STRING: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.string, &m, PMIX_STRING))) { return ret; } break; case PMIX_SIZE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.size, &m, PMIX_SIZE))) { return ret; } break; case PMIX_PID: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.pid, &m, PMIX_PID))) { return ret; } break; case PMIX_INT: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.integer, &m, PMIX_INT))) { return ret; } break; case PMIX_INT8: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.int8, &m, PMIX_INT8))) { return ret; } break; case PMIX_INT16: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.int16, &m, PMIX_INT16))) { return ret; } break; case PMIX_INT32: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.int32, &m, PMIX_INT32))) { return ret; } break; case PMIX_INT64: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.int64, &m, PMIX_INT64))) { return ret; } break; case PMIX_UINT: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.uint, &m, PMIX_UINT))) { return ret; } break; case PMIX_UINT8: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.uint8, &m, PMIX_UINT8))) { return ret; } break; case PMIX_UINT16: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.uint16, &m, PMIX_UINT16))) { return ret; } break; case PMIX_UINT32: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.uint32, &m, PMIX_UINT32))) { return ret; } break; case PMIX_UINT64: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.uint64, &m, PMIX_UINT64))) { return ret; } break; case PMIX_FLOAT: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.fval, &m, PMIX_FLOAT))) { return ret; } break; case PMIX_DOUBLE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.dval, &m, PMIX_DOUBLE))) { return ret; } break; case PMIX_TIMEVAL: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.tv, &m, PMIX_TIMEVAL))) { return ret; } break; case PMIX_TIME: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.time, &m, PMIX_TIME))) { return ret; } break; case PMIX_STATUS: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.status, &m, PMIX_STATUS))) { return ret; } break; case PMIX_PROC: /* this field is now a pointer, so we must allocate storage for it */ PMIX_PROC_CREATE(val->data.proc, m); if (NULL == val->data.proc) { return PMIX_ERR_NOMEM; } if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, val->data.proc, &m, PMIX_PROC))) { return ret; } break; case PMIX_PROC_RANK: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.rank, &m, PMIX_PROC_RANK))) { return ret; } break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.bo, &m, PMIX_BYTE_OBJECT))) { return ret; } break; case PMIX_PERSIST: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.proc, &m, PMIX_PROC))) { return ret; } break; case PMIX_POINTER: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.ptr, &m, PMIX_POINTER))) { return ret; } break; case PMIX_SCOPE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.scope, &m, PMIX_SCOPE))) { return ret; } break; case PMIX_DATA_RANGE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.range, &m, PMIX_DATA_RANGE))) { return ret; } break; case PMIX_PROC_STATE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.state, &m, PMIX_PROC_STATE))) { return ret; } break; case PMIX_PROC_INFO: /* this is now a pointer, so allocate storage for it */ PMIX_PROC_INFO_CREATE(val->data.pinfo, 1); if (NULL == val->data.pinfo) { return PMIX_ERR_NOMEM; } if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, val->data.pinfo, &m, PMIX_PROC_INFO))) { return ret; } break; case PMIX_DATA_ARRAY: /* this is now a pointer, so allocate storage for it */ val->data.darray = (pmix_data_array_t *) malloc(sizeof(pmix_data_array_t)); if (NULL == val->data.darray) { return PMIX_ERR_NOMEM; } if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, val->data.darray, &m, PMIX_DATA_ARRAY))) { return ret; } break; case PMIX_QUERY: if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, val->data.darray, &m, PMIX_QUERY))) { return ret; } break; /**** DEPRECATED ****/ case PMIX_INFO_ARRAY: /* we don't know anything about info array's so we * have to convert this to a data array */ val->data.darray = (pmix_data_array_t *) calloc(1, sizeof(pmix_data_array_t)); val->data.darray->type = PMIX_INFO_ARRAY; val->data.darray->size = m; /* unpack into it */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, &val->data.darray->array, &m, PMIX_INFO_ARRAY))) { return ret; } break; /********************/ default: pmix_output(0, "UNPACK-PMIX-VALUE: UNSUPPORTED TYPE %d", (int) val->type); return PMIX_ERROR; } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_value_t *ptr; int32_t i, n; pmix_status_t ret; ptr = (pmix_value_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { /* unpack the type */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_get_data_type(regtypes, buffer, &ptr[i].type))) { return ret; } /* unpack value */ if (PMIX_SUCCESS != (ret = unpack_val(regtypes, buffer, &ptr[i]))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_info_t *ptr; int32_t i, n, m; pmix_status_t ret; char *tmp; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d info", *num_vals); ptr = (pmix_info_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { memset(ptr[i].key, 0, sizeof(ptr[i].key)); memset(&ptr[i].value, 0, sizeof(pmix_value_t)); /* unpack key */ m = 1; tmp = NULL; ret = pmix20_bfrop_unpack_string(regtypes, buffer, &tmp, &m, PMIX_STRING); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); if (NULL != tmp) { free(tmp); } return ret; } if (NULL == tmp) { PMIX_ERROR_LOG(PMIX_ERROR); return PMIX_ERROR; } pmix_strncpy(ptr[i].key, tmp, PMIX_MAX_KEYLEN); free(tmp); /* unpack the flags */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_infodirs(regtypes, buffer, &ptr[i].flags, &m, PMIX_INFO_DIRECTIVES))) { PMIX_ERROR_LOG(ret); return ret; } /* unpack value - since the value structure is statically-defined * instead of a pointer in this struct, we directly unpack it to * avoid the malloc */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_int(regtypes, buffer, &ptr[i].value.type, &m, PMIX_INT))) { PMIX_ERROR_LOG(ret); return ret; } pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: info type %d", ptr[i].value.type); m = 1; if (PMIX_SUCCESS != (ret = unpack_val(regtypes, buffer, &ptr[i].value))) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_pdata_t *ptr; int32_t i, n, m; pmix_status_t ret; char *tmp; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d pdata", *num_vals); ptr = (pmix_pdata_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { PMIX_PDATA_CONSTRUCT(&ptr[i]); /* unpack the proc */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_proc(regtypes, buffer, &ptr[i].proc, &m, PMIX_PROC))) { return ret; } /* unpack key */ m = 1; tmp = NULL; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_string(regtypes, buffer, &tmp, &m, PMIX_STRING))) { return ret; } if (NULL == tmp) { return PMIX_ERROR; } pmix_strncpy(ptr[i].key, tmp, PMIX_MAX_KEYLEN); free(tmp); /* unpack value - since the value structure is statically-defined * instead of a pointer in this struct, we directly unpack it to * avoid the malloc */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_int(regtypes, buffer, &ptr[i].value.type, &m, PMIX_INT))) { return ret; } pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: pdata type %d", ptr[i].value.type); m = 1; if (PMIX_SUCCESS != (ret = unpack_val(regtypes, buffer, &ptr[i].value))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_buffer_t *ptr; int32_t i, n, m; pmix_status_t ret; size_t nbytes; ptr = (pmix_buffer_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { /* unpack the number of bytes */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_sizet(regtypes, buffer, &nbytes, &m, PMIX_SIZE))) { return ret; } m = nbytes; /* setup the buffer's data region */ if (0 < nbytes) { ptr[i].base_ptr = (char *) malloc(nbytes); /* unpack the bytes */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_byte(regtypes, buffer, ptr[i].base_ptr, &m, PMIX_BYTE))) { return ret; } } ptr[i].pack_ptr = ptr[i].base_ptr + m; ptr[i].unpack_ptr = ptr[i].base_ptr; ptr[i].bytes_allocated = nbytes; ptr[i].bytes_used = m; } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_proc_t *ptr; int32_t i, n, m; pmix_status_t ret; char *tmp; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d procs", *num_vals); ptr = (pmix_proc_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: init proc[%d]", i); memset(&ptr[i], 0, sizeof(pmix_proc_t)); /* unpack nspace */ m = 1; tmp = NULL; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_string(regtypes, buffer, &tmp, &m, PMIX_STRING))) { if (NULL != tmp) { free(tmp); } return ret; } if (NULL == tmp) { return PMIX_ERROR; } pmix_strncpy(ptr[i].nspace, tmp, PMIX_MAX_NSLEN); free(tmp); /* unpack the rank */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_rank(regtypes, buffer, &ptr[i].rank, &m, PMIX_PROC_RANK))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_app_t *ptr; int32_t i, k, n, m; pmix_status_t ret; int32_t nval; char *tmp; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d apps", *num_vals); ptr = (pmix_app_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { /* initialize the fields */ PMIX_APP_CONSTRUCT(&ptr[i]); /* unpack cmd */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_string(regtypes, buffer, &ptr[i].cmd, &m, PMIX_STRING))) { return ret; } /* unpack argc */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_int(regtypes, buffer, &nval, &m, PMIX_INT32))) { return ret; } /* unpack argv */ for (k = 0; k < nval; k++) { m = 1; tmp = NULL; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_string(regtypes, buffer, &tmp, &m, PMIX_STRING))) { if (NULL != tmp) { free(tmp); } return ret; } if (NULL == tmp) { return PMIX_ERROR; } PMIx_Argv_append_nosize(&ptr[i].argv, tmp); free(tmp); } /* unpack env */ m = 1; ret = pmix20_bfrop_unpack_int32(regtypes, buffer, &nval, &m, PMIX_INT32); if (PMIX_SUCCESS != ret) { return ret; } if (PMIX_TAINT_INT_LIMIT < nval) { // arbitrary value to guard against tainted input return PMIX_ERR_BAD_PARAM; } for (k = 0; k < nval; k++) { m = 1; tmp = NULL; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_string(regtypes, buffer, &tmp, &m, PMIX_STRING))) { if (NULL != tmp) { free(tmp); } return ret; } if (NULL == tmp) { return PMIX_ERROR; } PMIx_Argv_append_nosize(&ptr[i].env, tmp); free(tmp); } /* unpack cwd */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_string(regtypes, buffer, &ptr[i].cwd, &m, PMIX_STRING))) { return ret; } /* unpack maxprocs */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_int(regtypes, buffer, &ptr[i].maxprocs, &m, PMIX_INT))) { return ret; } /* unpack info array */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_sizet(regtypes, buffer, &ptr[i].ninfo, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].ninfo) { PMIX_INFO_CREATE(ptr[i].info, ptr[i].ninfo); m = ptr[i].ninfo; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_info(regtypes, buffer, ptr[i].info, &m, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_kval_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d kvals", *num_vals); ptr = (pmix_kval_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { PMIX_CONSTRUCT(&ptr[i], pmix_kval_t); /* unpack the key */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_string(regtypes, buffer, &ptr[i].key, &m, PMIX_STRING))) { PMIX_ERROR_LOG(ret); return ret; } /* allocate the space */ ptr[i].value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); /* unpack the value */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_value(regtypes, buffer, ptr[i].value, &m, PMIX_VALUE))) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_modex_data_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d modex", *num_vals); ptr = (pmix_modex_data_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { memset(&ptr[i], 0, sizeof(pmix_modex_data_t)); /* unpack the number of bytes */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { ptr[i].blob = (uint8_t *) malloc(ptr[i].size * sizeof(uint8_t)); m = ptr[i].size; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_byte(regtypes, buffer, ptr[i].blob, &m, PMIX_UINT8))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_unpack_byte(regtypes, buffer, dest, num_vals, PMIX_UINT8); } pmix_status_t pmix20_bfrop_unpack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_unpack_byte(regtypes, buffer, dest, num_vals, PMIX_UINT8); } pmix_status_t pmix20_bfrop_unpack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_unpack_byte(regtypes, buffer, dest, num_vals, PMIX_UINT8); } pmix_status_t pmix20_bfrop_unpack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_unpack_byte(regtypes, buffer, dest, num_vals, PMIX_UINT8); } pmix_status_t pmix20_bfrop_unpack_infodirs(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_unpack_int32(regtypes, buffer, dest, num_vals, PMIX_UINT32); } pmix_status_t pmix20_bfrop_unpack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_byte_object_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d byte_object", *num_vals); ptr = (pmix_byte_object_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { memset(&ptr[i], 0, sizeof(pmix_byte_object_t)); /* unpack the number of bytes */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { ptr[i].bytes = (char *) malloc(ptr[i].size * sizeof(char)); m = ptr[i].size; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_byte(regtypes, buffer, ptr[i].bytes, &m, PMIX_BYTE))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { uint8_t foo = 1; int32_t cnt = 1; PMIX_HIDE_UNUSED_PARAMS(dest, num_vals, type); /* it obviously makes no sense to pack a pointer and * send it somewhere else, so we just unpack the sentinel */ return pmix20_bfrop_unpack_byte(regtypes, buffer, &foo, &cnt, PMIX_UINT8); } pmix_status_t pmix20_bfrop_unpack_pstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_unpack_byte(regtypes, buffer, dest, num_vals, PMIX_UINT8); } pmix_status_t pmix20_bfrop_unpack_pinfo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_proc_info_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d pinfo", *num_vals); ptr = (pmix_proc_info_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { PMIX_PROC_INFO_CONSTRUCT(&ptr[i]); /* unpack the proc */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_proc(regtypes, buffer, &ptr[i].proc, &m, PMIX_PROC))) { return ret; } /* unpack the hostname */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_string(regtypes, buffer, &ptr[i].hostname, &m, PMIX_STRING))) { return ret; } /* unpack the executable */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_string(regtypes, buffer, &ptr[i].executable_name, &m, PMIX_STRING))) { return ret; } /* unpack pid */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_pid(regtypes, buffer, &ptr[i].pid, &m, PMIX_PID))) { return ret; } /* unpack state */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_pstate(regtypes, buffer, &ptr[i].state, &m, PMIX_PROC_STATE))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_data_array_t *ptr; int32_t i, n, m; pmix_status_t ret; size_t nbytes; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d data arrays", *num_vals); ptr = (pmix_data_array_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { memset(&ptr[i], 0, sizeof(pmix_data_array_t)); /* unpack the type */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_datatype(regtypes, buffer, &ptr[i].type, &m, PMIX_DATA_TYPE))) { return ret; } /* unpack the number of array elements */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 == ptr[i].size || PMIX_UNDEF == ptr[i].type) { /* nothing else to do */ continue; } /* allocate storage for the array and unpack the array elements */ m = ptr[i].size; switch (ptr[i].type) { case PMIX_BOOL: nbytes = sizeof(bool); break; case PMIX_BYTE: case PMIX_INT8: case PMIX_UINT8: nbytes = sizeof(int8_t); break; case PMIX_INT16: case PMIX_UINT16: nbytes = sizeof(int16_t); break; case PMIX_INT32: case PMIX_UINT32: nbytes = sizeof(int32_t); break; case PMIX_INT64: case PMIX_UINT64: nbytes = sizeof(int64_t); break; case PMIX_STRING: nbytes = sizeof(char *); break; case PMIX_SIZE: nbytes = sizeof(size_t); break; case PMIX_PID: nbytes = sizeof(pid_t); break; case PMIX_INT: case PMIX_UINT: nbytes = sizeof(int); break; case PMIX_FLOAT: nbytes = sizeof(float); break; case PMIX_DOUBLE: nbytes = sizeof(double); break; case PMIX_TIMEVAL: nbytes = sizeof(struct timeval); break; case PMIX_TIME: nbytes = sizeof(time_t); break; case PMIX_STATUS: nbytes = sizeof(pmix_status_t); break; case PMIX_INFO: nbytes = sizeof(pmix_info_t); break; case PMIX_PROC: nbytes = sizeof(pmix_proc_t); break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: nbytes = sizeof(pmix_byte_object_t); break; case PMIX_PERSIST: nbytes = sizeof(pmix_persistence_t); break; case PMIX_SCOPE: nbytes = sizeof(pmix_scope_t); break; case PMIX_DATA_RANGE: nbytes = sizeof(pmix_data_range_t); break; case PMIX_PROC_STATE: nbytes = sizeof(pmix_proc_state_t); break; case PMIX_PROC_INFO: nbytes = sizeof(pmix_proc_info_t); break; case PMIX_QUERY: nbytes = sizeof(pmix_query_t); break; default: return PMIX_ERR_NOT_SUPPORTED; } if (NULL == (ptr[i].array = malloc(m * nbytes))) { return PMIX_ERR_NOMEM; } if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_buffer(regtypes, buffer, ptr[i].array, &m, ptr[i].type))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_unpack_int32(regtypes, buffer, dest, num_vals, PMIX_UINT32); } pmix_status_t pmix20_bfrop_unpack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_query_t *ptr; int32_t i, n, m; pmix_status_t ret; int32_t nkeys; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d queries", *num_vals); ptr = (pmix_query_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { PMIX_QUERY_CONSTRUCT(&ptr[i]); /* unpack the number of keys */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_int32(regtypes, buffer, &nkeys, &m, PMIX_INT32))) { return ret; } if (PMIX_TAINT_INT_LIMIT < nkeys) { // arbitrary value to guard against tainted input return PMIX_ERR_BAD_PARAM; } if (0 < nkeys) { /* unpack the keys */ if (NULL == (ptr[i].keys = (char **) calloc(nkeys + 1, sizeof(char *)))) { return PMIX_ERR_NOMEM; } /* unpack keys */ m = nkeys; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_string(regtypes, buffer, ptr[i].keys, &m, PMIX_STRING))) { return ret; } } /* unpack the number of qualifiers */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_sizet(regtypes, buffer, &ptr[i].nqual, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].nqual) { /* unpack the qualifiers */ PMIX_INFO_CREATE(ptr[i].qualifiers, ptr[i].nqual); m = ptr[i].nqual; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_info(regtypes, buffer, ptr[i].qualifiers, &m, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_unpack_alloc_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_unpack_byte(regtypes, buffer, dest, num_vals, PMIX_UINT8); } /**** DEPRECATED ****/ pmix_status_t pmix20_bfrop_unpack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_info_array_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d info arrays", *num_vals); ptr = (pmix_info_array_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: init array[%d]", i); memset(&ptr[i], 0, sizeof(pmix_info_array_t)); /* unpack the size of this array */ m = 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { ptr[i].array = (pmix_info_t *) malloc(ptr[i].size * sizeof(pmix_info_t)); m = ptr[i].size; if (PMIX_SUCCESS != (ret = pmix20_bfrop_unpack_value(regtypes, buffer, ptr[i].array, &m, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } /********************/ pmix-6.1.1~rc2/src/mca/bfrops/v20/copy.c0000664000175000017500000015223015203536752020047 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "bfrop_pmix20.h" #include "internal.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" pmix_status_t pmix20_bfrop_copy(void **dest, void *src, pmix_data_type_t type) { pmix_bfrop_type_info_t *info; /* check for error */ if (NULL == dest) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } if (NULL == src) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* Lookup the copy function for this type and call it */ if (NULL == (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v20_component.types, type))) { PMIX_ERROR_LOG(PMIX_ERR_UNKNOWN_DATA_TYPE); return PMIX_ERR_UNKNOWN_DATA_TYPE; } return info->odti_copy_fn(dest, src, type); } pmix_status_t pmix20_bfrop_copy_payload(pmix_buffer_t *dest, pmix_buffer_t *src) { size_t to_copy = 0; char *ptr; /* deal with buffer type */ if (NULL == dest->base_ptr) { /* destination buffer is empty - derive src buffer type */ dest->type = src->type; } else if (dest->type != src->type) { /* buffer types mismatch */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } to_copy = src->pack_ptr - src->unpack_ptr; if (NULL == (ptr = pmix_bfrop_buffer_extend(dest, to_copy))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return PMIX_ERR_OUT_OF_RESOURCE; } memcpy(ptr, src->unpack_ptr, to_copy); dest->bytes_used += to_copy; dest->pack_ptr += to_copy; return PMIX_SUCCESS; } /* * STANDARD COPY FUNCTION - WORKS FOR EVERYTHING NON-STRUCTURED */ pmix_status_t pmix20_bfrop_std_copy(void **dest, void *src, pmix_data_type_t type) { size_t datasize; uint8_t *val = NULL; switch (type) { case PMIX_BOOL: datasize = sizeof(bool); break; case PMIX_INT: case PMIX_UINT: datasize = sizeof(int); break; case PMIX_SIZE: datasize = sizeof(size_t); break; case PMIX_PID: datasize = sizeof(pid_t); break; case PMIX_BYTE: case PMIX_INT8: case PMIX_UINT8: datasize = 1; break; case PMIX_INT16: case PMIX_UINT16: datasize = 2; break; case PMIX_INT32: case PMIX_UINT32: datasize = 4; break; case PMIX_INT64: case PMIX_UINT64: datasize = 8; break; case PMIX_FLOAT: datasize = sizeof(float); break; case PMIX_TIMEVAL: datasize = sizeof(struct timeval); break; case PMIX_TIME: datasize = sizeof(time_t); break; case PMIX_STATUS: datasize = sizeof(pmix_status_t); break; case PMIX_PROC_RANK: datasize = sizeof(pmix_rank_t); break; case PMIX_PERSIST: datasize = sizeof(pmix_persistence_t); break; case PMIX_POINTER: datasize = sizeof(char *); break; case PMIX_SCOPE: datasize = sizeof(pmix_scope_t); break; case PMIX_DATA_RANGE: datasize = sizeof(pmix_data_range_t); break; case PMIX_COMMAND: datasize = sizeof(pmix_cmd_t); break; case PMIX_INFO_DIRECTIVES: datasize = sizeof(pmix_info_directives_t); break; case PMIX_PROC_STATE: datasize = sizeof(pmix_proc_state_t); break; case PMIX_ALLOC_DIRECTIVE: datasize = sizeof(pmix_alloc_directive_t); break; default: return PMIX_ERR_UNKNOWN_DATA_TYPE; } val = (uint8_t *) malloc(datasize); if (NULL == val) { return PMIX_ERR_OUT_OF_RESOURCE; } memcpy(val, src, datasize); *dest = val; return PMIX_SUCCESS; } /* compare function for pmix_value_t*/ pmix_value_cmp_t pmix20_bfrop_value_cmp(pmix_value_t *p, pmix_value_t *p1) { bool rc = false; switch (p->type) { case PMIX_BOOL: rc = (p->data.flag == p1->data.flag); break; case PMIX_BYTE: rc = (p->data.byte == p1->data.byte); break; case PMIX_SIZE: rc = (p->data.size == p1->data.size); break; case PMIX_INT: rc = (p->data.integer == p1->data.integer); break; case PMIX_INT8: rc = (p->data.int8 == p1->data.int8); break; case PMIX_INT16: rc = (p->data.int16 == p1->data.int16); break; case PMIX_INT32: rc = (p->data.int32 == p1->data.int32); break; case PMIX_INT64: rc = (p->data.int64 == p1->data.int64); break; case PMIX_UINT: rc = (p->data.uint == p1->data.uint); break; case PMIX_UINT8: rc = (p->data.uint8 == p1->data.int8); break; case PMIX_UINT16: rc = (p->data.uint16 == p1->data.uint16); break; case PMIX_UINT32: rc = (p->data.uint32 == p1->data.uint32); break; case PMIX_UINT64: rc = (p->data.uint64 == p1->data.uint64); break; case PMIX_STRING: rc = strcmp(p->data.string, p1->data.string); break; default: pmix_output(0, "COMPARE-PMIX-VALUE: UNSUPPORTED TYPE %d", (int) p->type); } if (rc) { return PMIX_EQUAL; } return PMIX_VALUE1_GREATER; } /* COPY FUNCTIONS FOR NON-STANDARD SYSTEM TYPES */ /* * STRING */ pmix_status_t pmix20_bfrop_copy_string(char **dest, char *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); if (NULL == src) { /* got zero-length string/NULL pointer - store NULL */ *dest = NULL; } else { *dest = strdup(src); } return PMIX_SUCCESS; } /* compare function for pmix_value_t */ bool pmix_value_cmp(pmix_value_t *p, pmix_value_t *p1) { bool rc = false; if (p->type != p1->type) { return rc; } switch (p->type) { case PMIX_UNDEF: rc = true; break; case PMIX_BOOL: rc = (p->data.flag == p1->data.flag); break; case PMIX_BYTE: rc = (p->data.byte == p1->data.byte); break; case PMIX_SIZE: rc = (p->data.size == p1->data.size); break; case PMIX_INT: rc = (p->data.integer == p1->data.integer); break; case PMIX_INT8: rc = (p->data.int8 == p1->data.int8); break; case PMIX_INT16: rc = (p->data.int16 == p1->data.int16); break; case PMIX_INT32: rc = (p->data.int32 == p1->data.int32); break; case PMIX_INT64: rc = (p->data.int64 == p1->data.int64); break; case PMIX_UINT: rc = (p->data.uint == p1->data.uint); break; case PMIX_UINT8: rc = (p->data.uint8 == p1->data.int8); break; case PMIX_UINT16: rc = (p->data.uint16 == p1->data.uint16); break; case PMIX_UINT32: rc = (p->data.uint32 == p1->data.uint32); break; case PMIX_UINT64: rc = (p->data.uint64 == p1->data.uint64); break; case PMIX_STRING: rc = strcmp(p->data.string, p1->data.string); break; case PMIX_COMPRESSED_STRING: if (p->data.bo.size != p1->data.bo.size) { return false; } else { return true; } case PMIX_STATUS: rc = (p->data.status == p1->data.status); break; default: pmix_output(0, "COMPARE-PMIX-VALUE: UNSUPPORTED TYPE %d", (int) p->type); } return rc; } /* COPY FUNCTIONS FOR GENERIC PMIX TYPES - we * are not allocating memory and so we cannot * use the regular copy functions */ pmix_status_t pmix20_bfrop_value_xfer(pmix_value_t *p, const pmix_value_t *src) { size_t n, m; pmix_status_t rc; char **prarray, **strarray; pmix_value_t *pv, *sv; pmix_info_t *p1, *s1; pmix_app_t *pa, *sa; pmix_pdata_t *pd, *sd; pmix_buffer_t *pb, *sb; pmix_byte_object_t *pbo, *sbo; pmix_kval_t *pk, *sk; pmix_modex_data_t *pm, *sm; pmix_proc_info_t *pi, *si; pmix_query_t *pq, *sq; /* copy the right field */ p->type = src->type; switch (src->type) { case PMIX_UNDEF: break; case PMIX_BOOL: p->data.flag = src->data.flag; break; case PMIX_BYTE: p->data.byte = src->data.byte; break; case PMIX_STRING: if (NULL != src->data.string) { p->data.string = strdup(src->data.string); } else { p->data.string = NULL; } break; case PMIX_SIZE: p->data.size = src->data.size; break; case PMIX_PID: p->data.pid = src->data.pid; break; case PMIX_INT: /* to avoid alignment issues */ memcpy(&p->data.integer, &src->data.integer, sizeof(int)); break; case PMIX_INT8: p->data.int8 = src->data.int8; break; case PMIX_INT16: /* to avoid alignment issues */ memcpy(&p->data.int16, &src->data.int16, 2); break; case PMIX_INT32: /* to avoid alignment issues */ memcpy(&p->data.int32, &src->data.int32, 4); break; case PMIX_INT64: /* to avoid alignment issues */ memcpy(&p->data.int64, &src->data.int64, 8); break; case PMIX_UINT: /* to avoid alignment issues */ memcpy(&p->data.uint, &src->data.uint, sizeof(unsigned int)); break; case PMIX_UINT8: p->data.uint8 = src->data.uint8; break; case PMIX_UINT16: /* to avoid alignment issues */ memcpy(&p->data.uint16, &src->data.uint16, 2); break; case PMIX_UINT32: /* to avoid alignment issues */ memcpy(&p->data.uint32, &src->data.uint32, 4); break; case PMIX_UINT64: /* to avoid alignment issues */ memcpy(&p->data.uint64, &src->data.uint64, 8); break; case PMIX_FLOAT: p->data.fval = src->data.fval; break; case PMIX_DOUBLE: p->data.dval = src->data.dval; break; case PMIX_TIMEVAL: memcpy(&p->data.tv, &src->data.tv, sizeof(struct timeval)); break; case PMIX_TIME: memcpy(&p->data.time, &src->data.time, sizeof(time_t)); break; case PMIX_STATUS: memcpy(&p->data.status, &src->data.status, sizeof(pmix_status_t)); break; case PMIX_PROC: /* create the storage */ p->data.proc = (pmix_proc_t *) malloc(sizeof(pmix_proc_t)); if (NULL == p->data.proc) { return PMIX_ERR_NOMEM; } memcpy(p->data.proc, src->data.proc, sizeof(pmix_proc_t)); break; case PMIX_PROC_RANK: memcpy(&p->data.rank, &src->data.rank, sizeof(pmix_rank_t)); break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: memset(&p->data.bo, 0, sizeof(pmix_byte_object_t)); if (NULL != src->data.bo.bytes && 0 < src->data.bo.size) { p->data.bo.bytes = malloc(src->data.bo.size); memcpy(p->data.bo.bytes, src->data.bo.bytes, src->data.bo.size); p->data.bo.size = src->data.bo.size; } else { p->data.bo.bytes = NULL; p->data.bo.size = 0; } break; case PMIX_PERSIST: memcpy(&p->data.persist, &src->data.persist, sizeof(pmix_persistence_t)); break; case PMIX_SCOPE: memcpy(&p->data.scope, &src->data.scope, sizeof(pmix_scope_t)); break; case PMIX_DATA_RANGE: memcpy(&p->data.range, &src->data.range, sizeof(pmix_data_range_t)); break; case PMIX_PROC_STATE: memcpy(&p->data.state, &src->data.state, sizeof(pmix_proc_state_t)); break; case PMIX_PROC_INFO: PMIX_PROC_INFO_CREATE(p->data.pinfo, 1); if (NULL != src->data.pinfo->hostname) { p->data.pinfo->hostname = strdup(src->data.pinfo->hostname); } if (NULL != src->data.pinfo->executable_name) { p->data.pinfo->executable_name = strdup(src->data.pinfo->executable_name); } memcpy(&p->data.pinfo->pid, &src->data.pinfo->pid, sizeof(pid_t)); memcpy(&p->data.pinfo->exit_code, &src->data.pinfo->exit_code, sizeof(int)); memcpy(&p->data.pinfo->state, &src->data.pinfo->state, sizeof(pmix_proc_state_t)); break; case PMIX_DATA_ARRAY: p->data.darray = (pmix_data_array_t *) calloc(1, sizeof(pmix_data_array_t)); p->data.darray->type = src->data.darray->type; p->data.darray->size = src->data.darray->size; if (0 == p->data.darray->size || NULL == src->data.darray->array) { p->data.darray->array = NULL; p->data.darray->size = 0; break; } /* allocate space and do the copy */ switch (src->data.darray->type) { case PMIX_UINT8: case PMIX_INT8: case PMIX_BYTE: p->data.darray->array = (char *) malloc(src->data.darray->size); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size); break; case PMIX_UINT16: case PMIX_INT16: p->data.darray->array = (char *) malloc(src->data.darray->size * sizeof(uint16_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(uint16_t)); break; case PMIX_UINT32: case PMIX_INT32: p->data.darray->array = (char *) malloc(src->data.darray->size * sizeof(uint32_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(uint32_t)); break; case PMIX_UINT64: case PMIX_INT64: p->data.darray->array = (char *) malloc(src->data.darray->size * sizeof(uint64_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(uint64_t)); break; case PMIX_BOOL: p->data.darray->array = (char *) malloc(src->data.darray->size * sizeof(bool)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(bool)); break; case PMIX_SIZE: p->data.darray->array = (char *) malloc(src->data.darray->size * sizeof(size_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(size_t)); break; case PMIX_PID: p->data.darray->array = (char *) malloc(src->data.darray->size * sizeof(pid_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(pid_t)); break; case PMIX_STRING: p->data.darray->array = (char **) malloc(src->data.darray->size * sizeof(char *)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } prarray = (char **) p->data.darray->array; strarray = (char **) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { if (NULL != strarray[n]) { prarray[n] = strdup(strarray[n]); } } break; case PMIX_INT: case PMIX_UINT: p->data.darray->array = (char *) malloc(src->data.darray->size * sizeof(int)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(int)); break; case PMIX_FLOAT: p->data.darray->array = (char *) malloc(src->data.darray->size * sizeof(float)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(float)); break; case PMIX_DOUBLE: p->data.darray->array = (char *) malloc(src->data.darray->size * sizeof(double)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(double)); break; case PMIX_TIMEVAL: p->data.darray->array = (struct timeval *) malloc(src->data.darray->size * sizeof(struct timeval)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(struct timeval)); break; case PMIX_TIME: p->data.darray->array = (time_t *) malloc(src->data.darray->size * sizeof(time_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(time_t)); break; case PMIX_STATUS: p->data.darray->array = (pmix_status_t *) malloc(src->data.darray->size * sizeof(pmix_status_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(pmix_status_t)); break; case PMIX_VALUE: PMIX_VALUE_CREATE(p->data.darray->array, src->data.darray->size); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } pv = (pmix_value_t *) p->data.darray->array; sv = (pmix_value_t *) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { if (PMIX_SUCCESS != (rc = pmix20_bfrop_value_xfer(&pv[n], &sv[n]))) { PMIX_VALUE_FREE(pv, src->data.darray->size); return rc; } } break; case PMIX_PROC: PMIX_PROC_CREATE(p->data.darray->array, src->data.darray->size); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(pmix_proc_t)); break; case PMIX_APP: PMIX_APP_CREATE(p->data.darray->array, src->data.darray->size); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } pa = (pmix_app_t *) p->data.darray->array; sa = (pmix_app_t *) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { if (NULL != sa[n].cmd) { pa[n].cmd = strdup(sa[n].cmd); } if (NULL != sa[n].argv) { pa[n].argv = PMIx_Argv_copy(sa[n].argv); } if (NULL != sa[n].env) { pa[n].env = PMIx_Argv_copy(sa[n].env); } if (NULL != sa[n].cwd) { pa[n].cwd = strdup(sa[n].cwd); } pa[n].maxprocs = sa[n].maxprocs; if (0 < sa[n].ninfo && NULL != sa[n].info) { PMIX_INFO_CREATE(pa[n].info, sa[n].ninfo); if (NULL == pa[n].info) { PMIX_APP_FREE(pa, src->data.darray->size); return PMIX_ERR_NOMEM; } pa[n].ninfo = sa[n].ninfo; for (m = 0; m < pa[n].ninfo; m++) { PMIX_INFO_XFER(&pa[n].info[m], &sa[n].info[m]); } } } break; case PMIX_INFO: PMIX_INFO_CREATE(p->data.darray->array, src->data.darray->size); p1 = (pmix_info_t *) p->data.darray->array; s1 = (pmix_info_t *) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { PMIX_LOAD_KEY(p1[n].key, s1[n].key); rc = PMIx_Value_xfer(&p1[n].value, &s1[n].value); if (PMIX_SUCCESS != rc) { PMIX_INFO_FREE(p1, src->data.darray->size); return rc; } } break; case PMIX_PDATA: PMIX_PDATA_CREATE(p->data.darray->array, src->data.darray->size); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } pd = (pmix_pdata_t *) p->data.darray->array; sd = (pmix_pdata_t *) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { memcpy(&pd[n].proc, &sd[n].proc, sizeof(pmix_proc_t)); PMIX_LOAD_KEY(pd[n].key, sd[n].key); rc = PMIx_Value_xfer(&pd[n].value, &sd[n].value); if (PMIX_SUCCESS != rc) { PMIX_PDATA_FREE(pd, src->data.darray->size); return rc; } } break; case PMIX_BUFFER: p->data.darray->array = (pmix_buffer_t *) malloc(src->data.darray->size * sizeof(pmix_buffer_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } pb = (pmix_buffer_t *) p->data.darray->array; sb = (pmix_buffer_t *) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { PMIX_CONSTRUCT(&pb[n], pmix_buffer_t); pmix20_bfrop_copy_payload(&pb[n], &sb[n]); } break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: p->data.darray->array = (pmix_byte_object_t *) malloc(src->data.darray->size * sizeof(pmix_byte_object_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } pbo = (pmix_byte_object_t *) p->data.darray->array; sbo = (pmix_byte_object_t *) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { if (NULL != sbo[n].bytes && 0 < sbo[n].size) { pbo[n].size = sbo[n].size; pbo[n].bytes = (char *) malloc(pbo[n].size); memcpy(pbo[n].bytes, sbo[n].bytes, pbo[n].size); } else { pbo[n].bytes = NULL; pbo[n].size = 0; } } break; case PMIX_KVAL: p->data.darray->array = (pmix_kval_t *) calloc(src->data.darray->size, sizeof(pmix_kval_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } pk = (pmix_kval_t *) p->data.darray->array; sk = (pmix_kval_t *) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { if (NULL != sk[n].key) { pk[n].key = strdup(sk[n].key); } if (NULL != sk[n].value) { PMIX_VALUE_CREATE(pk[n].value, 1); if (NULL == pk[n].value) { free(p->data.darray->array); return PMIX_ERR_NOMEM; } if (PMIX_SUCCESS != (rc = pmix20_bfrop_value_xfer(pk[n].value, sk[n].value))) { return rc; } } } break; case PMIX_MODEX: PMIX_MODEX_CREATE(p->data.darray->array, src->data.darray->size); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } pm = (pmix_modex_data_t *) p->data.darray->array; sm = (pmix_modex_data_t *) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { memcpy(&pm[n], &sm[n], sizeof(pmix_modex_data_t)); if (NULL != sm[n].blob && 0 < sm[n].size) { pm[n].blob = (uint8_t *) malloc(sm[n].size); if (NULL == pm[n].blob) { return PMIX_ERR_NOMEM; } memcpy(pm[n].blob, sm[n].blob, sm[n].size); pm[n].size = sm[n].size; } else { pm[n].blob = NULL; pm[n].size = 0; } } break; case PMIX_PERSIST: p->data.darray->array = (pmix_persistence_t *) malloc(src->data.darray->size * sizeof(pmix_persistence_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(pmix_persistence_t)); break; case PMIX_POINTER: p->data.darray->array = (char **) malloc(src->data.darray->size * sizeof(char *)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } prarray = (char **) p->data.darray->array; strarray = (char **) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { prarray[n] = strarray[n]; } break; case PMIX_SCOPE: p->data.darray->array = (pmix_scope_t *) malloc(src->data.darray->size * sizeof(pmix_scope_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(pmix_scope_t)); break; case PMIX_DATA_RANGE: p->data.darray->array = (pmix_data_range_t *) malloc(src->data.darray->size * sizeof(pmix_data_range_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(pmix_data_range_t)); break; case PMIX_COMMAND: p->data.darray->array = (pmix_cmd_t *) malloc(src->data.darray->size * sizeof(pmix_cmd_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(pmix_cmd_t)); break; case PMIX_INFO_DIRECTIVES: p->data.darray->array = (pmix_info_directives_t *) malloc( src->data.darray->size * sizeof(pmix_info_directives_t)); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } memcpy(p->data.darray->array, src->data.darray->array, src->data.darray->size * sizeof(pmix_info_directives_t)); break; case PMIX_PROC_INFO: PMIX_PROC_INFO_CREATE(p->data.darray->array, src->data.darray->size); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } pi = (pmix_proc_info_t *) p->data.darray->array; si = (pmix_proc_info_t *) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { memcpy(&pi[n].proc, &si[n].proc, sizeof(pmix_proc_t)); if (NULL != si[n].hostname) { pi[n].hostname = strdup(si[n].hostname); } else { pi[n].hostname = NULL; } if (NULL != si[n].executable_name) { pi[n].executable_name = strdup(si[n].executable_name); } else { pi[n].executable_name = NULL; } pi[n].pid = si[n].pid; pi[n].exit_code = si[n].exit_code; pi[n].state = si[n].state; } break; case PMIX_DATA_ARRAY: return PMIX_ERR_NOT_SUPPORTED; // don't support iterative arrays case PMIX_QUERY: PMIX_QUERY_CREATE(p->data.darray->array, src->data.darray->size); if (NULL == p->data.darray->array) { return PMIX_ERR_NOMEM; } pq = (pmix_query_t *) p->data.darray->array; sq = (pmix_query_t *) src->data.darray->array; for (n = 0; n < src->data.darray->size; n++) { if (NULL != sq[n].keys) { pq[n].keys = PMIx_Argv_copy(sq[n].keys); } if (NULL != sq[n].qualifiers && 0 < sq[n].nqual) { PMIX_INFO_CREATE(pq[n].qualifiers, sq[n].nqual); if (NULL == pq[n].qualifiers) { PMIX_QUERY_FREE(pq, src->data.darray->size); return PMIX_ERR_NOMEM; } for (m = 0; m < sq[n].nqual; m++) { PMIX_INFO_XFER(&pq[n].qualifiers[m], &sq[n].qualifiers[m]); } pq[n].nqual = sq[n].nqual; } else { pq[n].qualifiers = NULL; pq[n].nqual = 0; } } break; default: return PMIX_ERR_UNKNOWN_DATA_TYPE; } break; case PMIX_POINTER: memcpy(&p->data.ptr, &src->data.ptr, sizeof(void *)); break; /**** DEPRECATED ****/ case PMIX_INFO_ARRAY: return PMIX_ERR_NOT_SUPPORTED; /********************/ default: pmix_output(0, "COPY-PMIX-VALUE: UNSUPPORTED TYPE %d", (int) src->type); return PMIX_ERROR; } return PMIX_SUCCESS; } /* PMIX_VALUE */ pmix_status_t pmix20_bfrop_copy_value(pmix_value_t **dest, pmix_value_t *src, pmix_data_type_t type) { pmix_value_t *p; PMIX_HIDE_UNUSED_PARAMS(type); /* create the new object */ *dest = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } p = *dest; /* copy the type */ p->type = src->type; /* copy the data */ return pmix20_bfrop_value_xfer(p, src); } pmix_status_t pmix20_bfrop_copy_info(pmix_info_t **dest, pmix_info_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_info_t *) malloc(sizeof(pmix_info_t)); pmix_strncpy((*dest)->key, src->key, PMIX_MAX_KEYLEN); (*dest)->flags = src->flags; return pmix20_bfrop_value_xfer(&(*dest)->value, &src->value); } pmix_status_t pmix20_bfrop_copy_buf(pmix_buffer_t **dest, pmix_buffer_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = PMIX_NEW(pmix_buffer_t); pmix20_bfrop_copy_payload(*dest, src); return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_copy_app(pmix_app_t **dest, pmix_app_t *src, pmix_data_type_t type) { size_t j; PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_app_t *) malloc(sizeof(pmix_app_t)); (*dest)->cmd = strdup(src->cmd); (*dest)->argv = PMIx_Argv_copy(src->argv); (*dest)->env = PMIx_Argv_copy(src->env); if (NULL != src->cwd) { (*dest)->cwd = strdup(src->cwd); } (*dest)->maxprocs = src->maxprocs; (*dest)->ninfo = src->ninfo; (*dest)->info = (pmix_info_t *) malloc(src->ninfo * sizeof(pmix_info_t)); for (j = 0; j < src->ninfo; j++) { pmix_strncpy((*dest)->info[j].key, src->info[j].key, PMIX_MAX_KEYLEN); pmix20_bfrop_value_xfer(&(*dest)->info[j].value, &src->info[j].value); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_copy_kval(pmix_kval_t **dest, pmix_kval_t *src, pmix_data_type_t type) { pmix_kval_t *p; PMIX_HIDE_UNUSED_PARAMS(type); /* create the new object */ *dest = PMIX_NEW(pmix_kval_t); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } p = *dest; /* copy the type */ p->value->type = src->value->type; /* copy the data */ return pmix20_bfrop_value_xfer(p->value, src->value); } pmix_status_t pmix20_bfrop_copy_proc(pmix_proc_t **dest, pmix_proc_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_proc_t *) malloc(sizeof(pmix_proc_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } pmix_strncpy((*dest)->nspace, src->nspace, PMIX_MAX_NSLEN); (*dest)->rank = src->rank; return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_copy_modex(pmix_modex_data_t **dest, pmix_modex_data_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_modex_data_t *) malloc(sizeof(pmix_modex_data_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } (*dest)->blob = NULL; (*dest)->size = 0; if (NULL != src->blob) { (*dest)->blob = (uint8_t *) malloc(src->size * sizeof(uint8_t)); if (NULL == (*dest)->blob) { return PMIX_ERR_OUT_OF_RESOURCE; } memcpy((*dest)->blob, src->blob, src->size * sizeof(uint8_t)); (*dest)->size = src->size; } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_copy_persist(pmix_persistence_t **dest, pmix_persistence_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_persistence_t *) malloc(sizeof(pmix_persistence_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } memcpy(*dest, src, sizeof(pmix_persistence_t)); return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_copy_bo(pmix_byte_object_t **dest, pmix_byte_object_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_byte_object_t *) malloc(sizeof(pmix_byte_object_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } (*dest)->bytes = (char *) malloc(src->size); memcpy((*dest)->bytes, src->bytes, src->size); (*dest)->size = src->size; return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_copy_pdata(pmix_pdata_t **dest, pmix_pdata_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_pdata_t *) malloc(sizeof(pmix_pdata_t)); pmix_strncpy((*dest)->proc.nspace, src->proc.nspace, PMIX_MAX_NSLEN); (*dest)->proc.rank = src->proc.rank; pmix_strncpy((*dest)->key, src->key, PMIX_MAX_KEYLEN); return pmix20_bfrop_value_xfer(&(*dest)->value, &src->value); } pmix_status_t pmix20_bfrop_copy_pinfo(pmix_proc_info_t **dest, pmix_proc_info_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_proc_info_t *) malloc(sizeof(pmix_proc_info_t)); pmix_strncpy((*dest)->proc.nspace, src->proc.nspace, PMIX_MAX_NSLEN); (*dest)->proc.rank = src->proc.rank; if (NULL != src->hostname) { (*dest)->hostname = strdup(src->hostname); } if (NULL != src->executable_name) { (*dest)->executable_name = strdup(src->executable_name); } (*dest)->pid = src->pid; (*dest)->exit_code = src->exit_code; (*dest)->state = src->state; return PMIX_SUCCESS; } /* the pmix_data_array_t is a little different in that it * is an array of values, and so we cannot just copy one * value at a time. So handle all value types here */ pmix_status_t pmix20_bfrop_copy_darray(pmix_data_array_t **dest, pmix_data_array_t *src, pmix_data_type_t type) { pmix_data_array_t *p; size_t n, m; pmix_status_t rc; char **prarray, **strarray; pmix_value_t *pv, *sv; pmix_app_t *pa, *sa; pmix_info_t *p1, *s1; pmix_pdata_t *pd, *sd; pmix_buffer_t *pb, *sb; pmix_byte_object_t *pbo, *sbo; pmix_kval_t *pk, *sk; pmix_modex_data_t *pm, *sm; pmix_proc_info_t *pi, *si; pmix_query_t *pq, *sq; PMIX_HIDE_UNUSED_PARAMS(type); p = (pmix_data_array_t *) calloc(1, sizeof(pmix_data_array_t)); if (NULL == p) { return PMIX_ERR_NOMEM; } p->type = src->type; p->size = src->size; if (0 == p->size || NULL == src->array) { *dest = p; return PMIX_SUCCESS; } /* process based on type of array element */ switch (src->type) { case PMIX_UINT8: case PMIX_INT8: case PMIX_BYTE: p->array = (char *) malloc(src->size); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size); break; case PMIX_UINT16: case PMIX_INT16: p->array = (char *) malloc(src->size * sizeof(uint16_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(uint16_t)); break; case PMIX_UINT32: case PMIX_INT32: p->array = (char *) malloc(src->size * sizeof(uint32_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(uint32_t)); break; case PMIX_UINT64: case PMIX_INT64: p->array = (char *) malloc(src->size * sizeof(uint64_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(uint64_t)); break; case PMIX_BOOL: p->array = (char *) malloc(src->size * sizeof(bool)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(bool)); break; case PMIX_SIZE: p->array = (char *) malloc(src->size * sizeof(size_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(size_t)); break; case PMIX_PID: p->array = (char *) malloc(src->size * sizeof(pid_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(pid_t)); break; case PMIX_STRING: p->array = (char **) malloc(src->size * sizeof(char *)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } prarray = (char **) p->array; strarray = (char **) src->array; for (n = 0; n < src->size; n++) { if (NULL != strarray[n]) { prarray[n] = strdup(strarray[n]); } } break; case PMIX_INT: case PMIX_UINT: p->array = (char *) malloc(src->size * sizeof(int)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(int)); break; case PMIX_FLOAT: p->array = (char *) malloc(src->size * sizeof(float)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(float)); break; case PMIX_DOUBLE: p->array = (char *) malloc(src->size * sizeof(double)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(double)); break; case PMIX_TIMEVAL: p->array = (struct timeval *) malloc(src->size * sizeof(struct timeval)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(struct timeval)); break; case PMIX_TIME: p->array = (time_t *) malloc(src->size * sizeof(time_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(time_t)); break; case PMIX_STATUS: p->array = (pmix_status_t *) malloc(src->size * sizeof(pmix_status_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(pmix_status_t)); break; case PMIX_VALUE: PMIX_VALUE_CREATE(p->array, src->size); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } pv = (pmix_value_t *) p->array; sv = (pmix_value_t *) src->array; for (n = 0; n < src->size; n++) { if (PMIX_SUCCESS != (rc = pmix20_bfrop_value_xfer(&pv[n], &sv[n]))) { PMIX_VALUE_FREE(pv, src->size); free(p); return rc; } } break; case PMIX_PROC: PMIX_PROC_CREATE(p->array, src->size); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(pmix_proc_t)); break; case PMIX_PROC_RANK: p->array = (char *) malloc(src->size * sizeof(pmix_rank_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(pmix_proc_t)); break; case PMIX_APP: PMIX_APP_CREATE(p->array, src->size); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } pa = (pmix_app_t *) p->array; sa = (pmix_app_t *) src->array; for (n = 0; n < src->size; n++) { if (NULL != sa[n].cmd) { pa[n].cmd = strdup(sa[n].cmd); } if (NULL != sa[n].argv) { pa[n].argv = PMIx_Argv_copy(sa[n].argv); } if (NULL != sa[n].env) { pa[n].env = PMIx_Argv_copy(sa[n].env); } if (NULL != sa[n].cwd) { pa[n].cwd = strdup(sa[n].cwd); } pa[n].maxprocs = sa[n].maxprocs; if (0 < sa[n].ninfo && NULL != sa[n].info) { PMIX_INFO_CREATE(pa[n].info, sa[n].ninfo); if (NULL == pa[n].info) { PMIX_APP_FREE(pa, p->size); free(p); return PMIX_ERR_NOMEM; } pa[n].ninfo = sa[n].ninfo; for (m = 0; m < pa[n].ninfo; m++) { PMIX_INFO_XFER(&pa[n].info[m], &sa[n].info[m]); } } } break; case PMIX_INFO: PMIX_INFO_CREATE(p->array, src->size); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } p1 = (pmix_info_t *) p->array; s1 = (pmix_info_t *) src->array; for (n = 0; n < src->size; n++) { PMIX_INFO_XFER(&p1[n], &s1[n]); } break; case PMIX_PDATA: PMIX_PDATA_CREATE(p->array, src->size); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } pd = (pmix_pdata_t *) p->array; sd = (pmix_pdata_t *) src->array; for (n = 0; n < src->size; n++) { PMIX_PDATA_XFER(&pd[n], &sd[n]); } break; case PMIX_BUFFER: p->array = (pmix_buffer_t *) malloc(src->size * sizeof(pmix_buffer_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } pb = (pmix_buffer_t *) p->array; sb = (pmix_buffer_t *) src->array; for (n = 0; n < src->size; n++) { PMIX_CONSTRUCT(&pb[n], pmix_buffer_t); pmix20_bfrop_copy_payload(&pb[n], &sb[n]); } break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: p->array = (pmix_byte_object_t *) malloc(src->size * sizeof(pmix_byte_object_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } pbo = (pmix_byte_object_t *) p->array; sbo = (pmix_byte_object_t *) src->array; for (n = 0; n < src->size; n++) { if (NULL != sbo[n].bytes && 0 < sbo[n].size) { pbo[n].size = sbo[n].size; pbo[n].bytes = (char *) malloc(pbo[n].size); memcpy(pbo[n].bytes, sbo[n].bytes, pbo[n].size); } else { pbo[n].bytes = NULL; pbo[n].size = 0; } } break; case PMIX_KVAL: p->array = (pmix_kval_t *) calloc(src->size, sizeof(pmix_kval_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } pk = (pmix_kval_t *) p->array; sk = (pmix_kval_t *) src->array; for (n = 0; n < src->size; n++) { if (NULL != sk[n].key) { pk[n].key = strdup(sk[n].key); } if (NULL != sk[n].value) { PMIX_VALUE_CREATE(pk[n].value, 1); if (NULL == pk[n].value) { for (m=0; m < n; m++) { PMIX_DESTRUCT(&pk[m]); } free(pk); free(p); return PMIX_ERR_NOMEM; } if (PMIX_SUCCESS != (rc = pmix20_bfrop_value_xfer(pk[n].value, sk[n].value))) { for (m=0; m < n; m++) { PMIX_DESTRUCT(&pk[m]); } free(pk); free(p); return rc; } } } break; case PMIX_MODEX: PMIX_MODEX_CREATE(p->array, src->size); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } pm = (pmix_modex_data_t *) p->array; sm = (pmix_modex_data_t *) src->array; for (n = 0; n < src->size; n++) { memcpy(&pm[n], &sm[n], sizeof(pmix_modex_data_t)); if (NULL != sm[n].blob && 0 < sm[n].size) { pm[n].blob = (uint8_t *) malloc(sm[n].size); if (NULL == pm[n].blob) { PMIX_MODEX_FREE(pm, src->size); free(p); return PMIX_ERR_NOMEM; } memcpy(pm[n].blob, sm[n].blob, sm[n].size); pm[n].size = sm[n].size; } else { pm[n].blob = NULL; pm[n].size = 0; } } break; case PMIX_PERSIST: p->array = (pmix_persistence_t *) malloc(src->size * sizeof(pmix_persistence_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(pmix_persistence_t)); break; case PMIX_POINTER: p->array = (char **) malloc(src->size * sizeof(char *)); prarray = (char **) p->array; strarray = (char **) src->array; for (n = 0; n < src->size; n++) { prarray[n] = strarray[n]; } break; case PMIX_SCOPE: p->array = (pmix_scope_t *) malloc(src->size * sizeof(pmix_scope_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(pmix_scope_t)); break; case PMIX_DATA_RANGE: p->array = (pmix_data_range_t *) malloc(src->size * sizeof(pmix_data_range_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(pmix_data_range_t)); break; case PMIX_COMMAND: p->array = (pmix_cmd_t *) malloc(src->size * sizeof(pmix_cmd_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(pmix_cmd_t)); break; case PMIX_INFO_DIRECTIVES: p->array = (pmix_info_directives_t *) malloc(src->size * sizeof(pmix_info_directives_t)); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } memcpy(p->array, src->array, src->size * sizeof(pmix_info_directives_t)); break; case PMIX_PROC_INFO: PMIX_PROC_INFO_CREATE(p->array, src->size); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } pi = (pmix_proc_info_t *) p->array; si = (pmix_proc_info_t *) src->array; for (n = 0; n < src->size; n++) { memcpy(&pi[n].proc, &si[n].proc, sizeof(pmix_proc_t)); if (NULL != si[n].hostname) { pi[n].hostname = strdup(si[n].hostname); } else { pi[n].hostname = NULL; } if (NULL != si[n].executable_name) { pi[n].executable_name = strdup(si[n].executable_name); } else { pi[n].executable_name = NULL; } pi[n].pid = si[n].pid; pi[n].exit_code = si[n].exit_code; pi[n].state = si[n].state; } break; case PMIX_DATA_ARRAY: free(p); return PMIX_ERR_NOT_SUPPORTED; // don't support iterative arrays case PMIX_QUERY: PMIX_QUERY_CREATE(p->array, src->size); if (NULL == p->array) { free(p); return PMIX_ERR_NOMEM; } pq = (pmix_query_t *) p->array; sq = (pmix_query_t *) src->array; for (n = 0; n < src->size; n++) { if (NULL != sq[n].keys) { pq[n].keys = PMIx_Argv_copy(sq[n].keys); } if (NULL != sq[n].qualifiers && 0 < sq[n].nqual) { PMIX_INFO_CREATE(pq[n].qualifiers, sq[n].nqual); if (NULL == pq[n].qualifiers) { PMIX_INFO_FREE(pq[n].qualifiers, sq[n].nqual); free(p); return PMIX_ERR_NOMEM; } for (m = 0; m < sq[n].nqual; m++) { PMIX_INFO_XFER(&pq[n].qualifiers[m], &sq[n].qualifiers[m]); } pq[n].nqual = sq[n].nqual; } else { pq[n].qualifiers = NULL; pq[n].nqual = 0; } } break; default: free(p); return PMIX_ERR_UNKNOWN_DATA_TYPE; } (*dest) = p; return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_copy_query(pmix_query_t **dest, pmix_query_t *src, pmix_data_type_t type) { pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_query_t *) malloc(sizeof(pmix_query_t)); if (NULL != src->keys) { (*dest)->keys = PMIx_Argv_copy(src->keys); } (*dest)->nqual = src->nqual; if (NULL != src->qualifiers) { if (PMIX_SUCCESS != (rc = pmix20_bfrop_copy_info(&((*dest)->qualifiers), src->qualifiers, PMIX_INFO))) { free(*dest); return rc; } } return PMIX_SUCCESS; } /**** DEPRECATED ****/ pmix_status_t pmix20_bfrop_copy_array(pmix_info_array_t **dest, pmix_info_array_t *src, pmix_data_type_t type) { pmix_info_t *d1, *s1; PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_info_array_t *) malloc(sizeof(pmix_info_array_t)); (*dest)->size = src->size; (*dest)->array = (pmix_info_t *) malloc(src->size * sizeof(pmix_info_t)); d1 = (pmix_info_t *) (*dest)->array; s1 = (pmix_info_t *) src->array; memcpy(d1, s1, src->size * sizeof(pmix_info_t)); return PMIX_SUCCESS; } /*******************/ pmix-6.1.1~rc2/src/mca/bfrops/v20/internal.h0000664000175000017500000006664415203536752020733 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX20_BFROP_INTERNAL_H_ #define PMIX20_BFROP_INTERNAL_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #include "src/class/pmix_pointer_array.h" #include "src/mca/bfrops/base/base.h" #ifdef HAVE_STRING_H # include #endif BEGIN_C_DECLS /* DEPRECATED data type values */ #define PMIX_MODEX 29 #define PMIX_INFO_ARRAY 44 /**** PMIX MODEX STRUCT - DEPRECATED ****/ typedef struct pmix_modex_data { char nspace[PMIX_MAX_NSLEN + 1]; int rank; uint8_t *blob; size_t size; } pmix_modex_data_t; /* utility macros for working with pmix_modex_t structs */ #define PMIX_MODEX_CREATE(m, n) \ do { \ (m) = (pmix_modex_data_t *) calloc((n), sizeof(pmix_modex_data_t)); \ } while (0) #define PMIX_MODEX_RELEASE(m) \ do { \ PMIX_MODEX_DESTRUCT((m)); \ free((m)); \ (m) = NULL; \ } while (0) #define PMIX_MODEX_CONSTRUCT(m) \ do { \ memset((m), 0, sizeof(pmix_modex_data_t)); \ } while (0) #define PMIX_MODEX_DESTRUCT(m) \ do { \ if (NULL != (m)->blob) { \ free((m)->blob); \ (m)->blob = NULL; \ } \ } while (0) #define PMIX_MODEX_FREE(m, n) \ do { \ size_t _s; \ if (NULL != (m)) { \ for (_s = 0; _s < (n); _s++) { \ PMIX_MODEX_DESTRUCT(&((m)[_s])); \ } \ free((m)); \ (m) = NULL; \ } \ } while (0) /* * Implementations of API functions */ pmix_status_t pmix20_bfrop_pack(pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack(pmix_buffer_t *buffer, void *dest, int32_t *max_num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy(void **dest, void *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print(char **output, char *prefix, void *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_payload(pmix_buffer_t *dest, pmix_buffer_t *src); pmix_status_t pmix20_bfrop_value_xfer(pmix_value_t *p, const pmix_value_t *src); void pmix20_bfrop_value_load(pmix_value_t *v, const void *data, pmix_data_type_t type); pmix_status_t pmix20_bfrop_value_unload(pmix_value_t *kv, void **data, size_t *sz); pmix_value_cmp_t pmix20_bfrop_value_cmp(pmix_value_t *p, pmix_value_t *p1); /* * Specialized functions */ pmix_status_t pmix20_bfrop_pack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dst, int32_t *num_vals, pmix_data_type_t type); /* * Internal pack functions */ pmix_status_t pmix20_bfrop_pack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_infodirs(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_pstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_pinfo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_pack_alloc_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); /**** DEPRECATED ****/ pmix_status_t pmix20_bfrop_pack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); /********************/ /* * Internal unpack functions */ pmix_status_t pmix20_bfrop_unpack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_infodirs(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_pstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_pinfo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix20_bfrop_unpack_alloc_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); /**** DEPRECATED ****/ pmix_status_t pmix20_bfrop_unpack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); /********************/ /* * Internal copy functions */ pmix_status_t pmix20_bfrop_std_copy(void **dest, void *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_string(char **dest, char *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_value(pmix_value_t **dest, pmix_value_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_proc(pmix_proc_t **dest, pmix_proc_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_app(pmix_app_t **dest, pmix_app_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_info(pmix_info_t **dest, pmix_info_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_buf(pmix_buffer_t **dest, pmix_buffer_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_kval(pmix_kval_t **dest, pmix_kval_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_modex(pmix_modex_data_t **dest, pmix_modex_data_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_persist(pmix_persistence_t **dest, pmix_persistence_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_bo(pmix_byte_object_t **dest, pmix_byte_object_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_pdata(pmix_pdata_t **dest, pmix_pdata_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_pinfo(pmix_proc_info_t **dest, pmix_proc_info_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_darray(pmix_data_array_t **dest, pmix_data_array_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_copy_query(pmix_query_t **dest, pmix_query_t *src, pmix_data_type_t type); /**** DEPRECATED ****/ pmix_status_t pmix20_bfrop_copy_array(pmix_info_array_t **dest, pmix_info_array_t *src, pmix_data_type_t type); /********************/ /* * Internal print functions */ pmix_status_t pmix20_bfrop_print_bool(char **output, char *prefix, bool *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_byte(char **output, char *prefix, uint8_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_string(char **output, char *prefix, char *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_size(char **output, char *prefix, size_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_pid(char **output, char *prefix, pid_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_int(char **output, char *prefix, int *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_int8(char **output, char *prefix, int8_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_int16(char **output, char *prefix, int16_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_int32(char **output, char *prefix, int32_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_int64(char **output, char *prefix, int64_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_uint(char **output, char *prefix, uint *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_uint8(char **output, char *prefix, uint8_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_uint16(char **output, char *prefix, uint16_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_uint32(char **output, char *prefix, uint32_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_uint64(char **output, char *prefix, uint64_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_float(char **output, char *prefix, float *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_double(char **output, char *prefix, double *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_timeval(char **output, char *prefix, struct timeval *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_time(char **output, char *prefix, time_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_status(char **output, char *prefix, pmix_status_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_value(char **output, char *prefix, pmix_value_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_proc(char **output, char *prefix, pmix_proc_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_app(char **output, char *prefix, pmix_app_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_info(char **output, char *prefix, pmix_info_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_buf(char **output, char *prefix, pmix_buffer_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_kval(char **output, char *prefix, pmix_kval_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_modex(char **output, char *prefix, pmix_modex_data_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_persist(char **output, char *prefix, pmix_persistence_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_scope(char **output, char *prefix, pmix_scope_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_range(char **output, char *prefix, pmix_data_range_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_cmd(char **output, char *prefix, pmix_cmd_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_infodirs(char **output, char *prefix, pmix_info_directives_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_bo(char **output, char *prefix, pmix_byte_object_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_pdata(char **output, char *prefix, pmix_pdata_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_ptr(char **output, char *prefix, void *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_pstate(char **output, char *prefix, pmix_proc_state_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_pinfo(char **output, char *prefix, pmix_proc_info_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_darray(char **output, char *prefix, pmix_data_array_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_query(char **output, char *prefix, pmix_query_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_rank(char **output, char *prefix, pmix_rank_t *src, pmix_data_type_t type); pmix_status_t pmix20_bfrop_print_alloc_directive(char **output, char *prefix, pmix_alloc_directive_t *src, pmix_data_type_t type); /**** DEPRECATED ****/ pmix_status_t pmix20_bfrop_print_array(char **output, char *prefix, pmix_info_array_t *src, pmix_data_type_t type); /********************/ /* * Internal helper functions */ pmix_status_t pmix20_bfrop_store_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t type); pmix_status_t pmix20_bfrop_get_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t *type); pmix_data_type_t pmix20_v21_to_v20_datatype(pmix_data_type_t v21type); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/bfrops/v20/bfrop_pmix20.h0000664000175000017500000000225615203536752021413 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2017 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX20_BFROPS_H #define PMIX20_BFROPS_H #include "src/mca/bfrops/bfrops.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_bfrops_base_component_t pmix_mca_bfrops_v20_component; extern pmix_bfrops_module_t pmix_bfrops_pmix20_module; END_C_DECLS #endif /* PMIX20_BFROPS_H */ pmix-6.1.1~rc2/src/mca/bfrops/v20/pack.c0000664000175000017500000011532215203536752020014 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2011-2013 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_ARPA_INET_H # include #endif #include "bfrop_pmix20.h" #include "internal.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" pmix_status_t pmix20_bfrop_pack(pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t rc; pmix_pointer_array_t *regtypes = &pmix_mca_bfrops_v20_component.types; /* check for error */ if (NULL == buffer) { return PMIX_ERR_BAD_PARAM; } /* Pack the number of values */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix20_bfrop_store_data_type(regtypes, buffer, PMIX_INT32))) { return rc; } } if (PMIX_SUCCESS != (rc = pmix20_bfrop_pack_int32(regtypes, buffer, &num_vals, 1, PMIX_INT32))) { return rc; } /* Pack the value(s) */ return pmix20_bfrop_pack_buffer(regtypes, buffer, src, num_vals, type); } pmix_status_t pmix20_bfrop_pack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_data_type_t v20type; pmix_status_t rc; pmix_bfrop_type_info_t *info; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_pack_buffer( %p, %p, %lu, %d )\n", (void *) buffer, src, (long unsigned int) num_vals, (int) type); /* some v20 types are simply declared differently */ switch (type) { case PMIX_COMMAND: v20type = PMIX_UINT32; break; default: v20type = type; } /* Pack the declared data type */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix20_bfrop_store_data_type(regtypes, buffer, v20type))) { return rc; } } /* Lookup the pack function for this type and call it */ if (NULL == (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v20_component.types, v20type))) { return PMIX_ERR_PACK_FAILURE; } return info->odti_pack_fn(regtypes, buffer, src, num_vals, v20type); } /* PACK FUNCTIONS FOR GENERIC SYSTEM TYPES */ /* * BOOL */ pmix_status_t pmix20_bfrop_pack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { uint8_t *dst; int32_t i; bool *s = (bool *) src; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_pack_bool * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = (uint8_t *) pmix_bfrop_buffer_extend(buffer, num_vals))) { return PMIX_ERR_OUT_OF_RESOURCE; } /* store the data */ for (i = 0; i < num_vals; i++) { if (s[i]) { dst[i] = 1; } else { dst[i] = 0; } } /* update buffer pointers */ buffer->pack_ptr += num_vals; buffer->bytes_used += num_vals; return PMIX_SUCCESS; } /* * INT */ pmix_status_t pmix20_bfrop_pack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_INT))) { return ret; } /* Turn around and pack the real type */ return pmix20_bfrop_pack_buffer(regtypes, buffer, src, num_vals, BFROP_TYPE_INT); } /* * SIZE_T */ pmix_status_t pmix20_bfrop_pack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them. */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_SIZE_T))) { return ret; } return pmix20_bfrop_pack_buffer(regtypes, buffer, src, num_vals, BFROP_TYPE_SIZE_T); } /* * PID_T */ pmix_status_t pmix20_bfrop_pack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them. */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_PID_T))) { return ret; } /* Turn around and pack the real type */ return pmix20_bfrop_pack_buffer(regtypes, buffer, src, num_vals, BFROP_TYPE_PID_T); } /* PACK FUNCTIONS FOR NON-GENERIC SYSTEM TYPES */ /* * BYTE, CHAR, INT8 */ pmix_status_t pmix20_bfrop_pack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { char *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_pack_byte * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals))) { return PMIX_ERR_OUT_OF_RESOURCE; } /* store the data */ memcpy(dst, src, num_vals); /* update buffer pointers */ buffer->pack_ptr += num_vals; buffer->bytes_used += num_vals; return PMIX_SUCCESS; } /* * INT16 */ pmix_status_t pmix20_bfrop_pack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint16_t tmp, *srctmp = (uint16_t *) src; char *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_pack_int16 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals * sizeof(tmp)))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { tmp = pmix_htons(srctmp[i]); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += num_vals * sizeof(tmp); buffer->bytes_used += num_vals * sizeof(tmp); return PMIX_SUCCESS; } /* * INT32 */ pmix_status_t pmix20_bfrop_pack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint32_t tmp, *srctmp = (uint32_t *) src; char *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_pack_int32 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals * sizeof(tmp)))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { tmp = htonl(srctmp[i]); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += num_vals * sizeof(tmp); buffer->bytes_used += num_vals * sizeof(tmp); return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_INT16, regtypes); return ret; } /* * INT64 */ pmix_status_t pmix20_bfrop_pack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint64_t tmp, tmp2; char *dst; size_t bytes_packed = num_vals * sizeof(tmp); pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_pack_int64 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, bytes_packed))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { memcpy(&tmp2, (char *) src + i * sizeof(uint64_t), sizeof(uint64_t)); tmp = pmix_hton64(tmp2); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += bytes_packed; buffer->bytes_used += bytes_packed; return PMIX_SUCCESS; } /* * STRING */ pmix_status_t pmix20_bfrop_pack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret = PMIX_SUCCESS; int32_t i, len; char **ssrc = (char **) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { if (NULL == ssrc[i]) { /* got zero-length string/NULL pointer - store NULL */ len = 0; if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int32(regtypes, buffer, &len, 1, PMIX_INT32))) { return ret; } } else { len = (int32_t) strlen(ssrc[i]) + 1; if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int32(regtypes, buffer, &len, 1, PMIX_INT32))) { return ret; } if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_byte(regtypes, buffer, ssrc[i], len, PMIX_BYTE))) { return ret; } } } return PMIX_SUCCESS; } /* FLOAT */ pmix_status_t pmix20_bfrop_pack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret = PMIX_SUCCESS; int32_t i; float *ssrc = (float *) src; char *convert; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { if (0 > asprintf(&convert, "%f", ssrc[i])) { return PMIX_ERR_NOMEM; } if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &convert, 1, PMIX_STRING))) { free(convert); return ret; } free(convert); } return PMIX_SUCCESS; } /* DOUBLE */ pmix_status_t pmix20_bfrop_pack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret = PMIX_SUCCESS; int32_t i; double *ssrc = (double *) src; char *convert; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { if (0 > asprintf(&convert, "%f", ssrc[i])) { return PMIX_ERR_NOMEM; } if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &convert, 1, PMIX_STRING))) { free(convert); return ret; } free(convert); } return PMIX_SUCCESS; } /* TIMEVAL */ pmix_status_t pmix20_bfrop_pack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int64_t tmp[2]; pmix_status_t ret = PMIX_SUCCESS; int32_t i; struct timeval *ssrc = (struct timeval *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { tmp[0] = (int64_t) ssrc[i].tv_sec; tmp[1] = (int64_t) ssrc[i].tv_usec; if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int64(regtypes, buffer, tmp, 2, PMIX_INT64))) { return ret; } } return PMIX_SUCCESS; } /* TIME */ pmix_status_t pmix20_bfrop_pack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret = PMIX_SUCCESS; int32_t i; time_t *ssrc = (time_t *) src; uint64_t ui64; PMIX_HIDE_UNUSED_PARAMS(type); /* time_t is a system-dependent size, so cast it * to uint64_t as a generic safe size */ for (i = 0; i < num_vals; ++i) { ui64 = (uint64_t) ssrc[i]; if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int64(regtypes, buffer, &ui64, 1, PMIX_UINT64))) { return ret; } } return PMIX_SUCCESS; } /* STATUS */ pmix_status_t pmix20_bfrop_pack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret = PMIX_SUCCESS; int32_t i; pmix_status_t *ssrc = (pmix_status_t *) src; int32_t status; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { status = (int32_t) ssrc[i]; if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int32(regtypes, buffer, &status, 1, PMIX_INT32))) { return ret; } } return PMIX_SUCCESS; } /* PACK FUNCTIONS FOR GENERIC PMIX TYPES */ static pmix_status_t pack_val(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_value_t *p) { pmix_status_t ret; switch (p->type) { case PMIX_UNDEF: break; case PMIX_BOOL: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.flag, 1, PMIX_BOOL))) { return ret; } break; case PMIX_BYTE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.byte, 1, PMIX_BYTE))) { return ret; } break; case PMIX_STRING: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.string, 1, PMIX_STRING))) { return ret; } break; case PMIX_SIZE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.size, 1, PMIX_SIZE))) { return ret; } break; case PMIX_PID: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.pid, 1, PMIX_PID))) { return ret; } break; case PMIX_INT: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.integer, 1, PMIX_INT))) { return ret; } break; case PMIX_INT8: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.int8, 1, PMIX_INT8))) { return ret; } break; case PMIX_INT16: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.int16, 1, PMIX_INT16))) { return ret; } break; case PMIX_INT32: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.int32, 1, PMIX_INT32))) { return ret; } break; case PMIX_INT64: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.int64, 1, PMIX_INT64))) { return ret; } break; case PMIX_UINT: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.uint, 1, PMIX_UINT))) { return ret; } break; case PMIX_UINT8: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.uint8, 1, PMIX_UINT8))) { return ret; } break; case PMIX_UINT16: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.uint16, 1, PMIX_UINT16))) { return ret; } break; case PMIX_UINT32: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.uint32, 1, PMIX_UINT32))) { return ret; } break; case PMIX_UINT64: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.uint64, 1, PMIX_UINT64))) { return ret; } break; case PMIX_FLOAT: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.fval, 1, PMIX_FLOAT))) { return ret; } break; case PMIX_DOUBLE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.dval, 1, PMIX_DOUBLE))) { return ret; } break; case PMIX_TIMEVAL: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.tv, 1, PMIX_TIMEVAL))) { return ret; } break; case PMIX_TIME: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.time, 1, PMIX_TIME))) { return ret; } break; case PMIX_STATUS: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.status, 1, PMIX_STATUS))) { return ret; } break; case PMIX_PROC: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, p->data.proc, 1, PMIX_PROC))) { return ret; } break; case PMIX_PROC_RANK: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.rank, 1, PMIX_PROC_RANK))) { return ret; } break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.bo, 1, PMIX_BYTE_OBJECT))) { return ret; } break; case PMIX_PERSIST: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.persist, 1, PMIX_PERSIST))) { return ret; } break; case PMIX_POINTER: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.ptr, 1, PMIX_POINTER))) { return ret; } break; case PMIX_SCOPE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.scope, 1, PMIX_SCOPE))) { return ret; } break; case PMIX_DATA_RANGE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.range, 1, PMIX_DATA_RANGE))) { return ret; } break; case PMIX_PROC_STATE: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, &p->data.state, 1, PMIX_PROC_STATE))) { return ret; } break; case PMIX_PROC_INFO: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, p->data.pinfo, 1, PMIX_PROC_INFO))) { return ret; } break; case PMIX_DATA_ARRAY: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, p->data.darray, 1, PMIX_DATA_ARRAY))) { return ret; } break; case PMIX_QUERY: if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, p->data.darray, 1, PMIX_QUERY))) { return ret; } break; default: pmix_output(0, "PACK-PMIX-VALUE: UNSUPPORTED TYPE %d", (int) p->type); return PMIX_ERROR; } return PMIX_SUCCESS; } /* * PMIX_VALUE */ pmix_status_t pmix20_bfrop_pack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_value_t *ptr; int32_t i; pmix_status_t ret; ptr = (pmix_value_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack the type */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_store_data_type(regtypes, buffer, ptr[i].type))) { return ret; } /* now pack the right field */ if (PMIX_SUCCESS != (ret = pack_val(regtypes, buffer, &ptr[i]))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_info_t *info; int32_t i; pmix_status_t ret; char *foo; info = (pmix_info_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack key */ foo = info[i].key; if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &foo, 1, PMIX_STRING))) { return ret; } /* pack info directives flag */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_infodirs(regtypes, buffer, &info[i].flags, 1, PMIX_INFO_DIRECTIVES))) { return ret; } /* pack the type */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int(regtypes, buffer, &info[i].value.type, 1, PMIX_INT))) { return ret; } /* pack value */ if (PMIX_SUCCESS != (ret = pack_val(regtypes, buffer, &info[i].value))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_pdata_t *pdata; int32_t i; pmix_status_t ret; char *foo; pdata = (pmix_pdata_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack the proc */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_proc(regtypes, buffer, &pdata[i].proc, 1, PMIX_PROC))) { return ret; } /* pack key */ foo = pdata[i].key; if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &foo, 1, PMIX_STRING))) { return ret; } /* pack the type */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int(regtypes, buffer, &pdata[i].value.type, 1, PMIX_INT))) { return ret; } /* pack value */ if (PMIX_SUCCESS != (ret = pack_val(regtypes, buffer, &pdata[i].value))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_buffer_t *ptr; int32_t i; pmix_status_t ret; ptr = (pmix_buffer_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack the number of bytes */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_sizet(regtypes, buffer, &ptr[i].bytes_used, 1, PMIX_SIZE))) { return ret; } /* pack the bytes */ if (0 < ptr[i].bytes_used) { if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_byte(regtypes, buffer, ptr[i].base_ptr, ptr[i].bytes_used, PMIX_BYTE))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_proc_t *proc; int32_t i; pmix_status_t ret; proc = (pmix_proc_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { char *ptr = proc[i].nspace; if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &ptr, 1, PMIX_STRING))) { return ret; } if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_rank(regtypes, buffer, &proc[i].rank, 1, PMIX_PROC_RANK))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_app_t *app; int32_t i, j, nvals; pmix_status_t ret; app = (pmix_app_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &app[i].cmd, 1, PMIX_STRING))) { return ret; } /* argv */ nvals = PMIx_Argv_count(app[i].argv); if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int(regtypes, buffer, &nvals, 1, PMIX_INT32))) { return ret; } for (j = 0; j < nvals; j++) { if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &app[i].argv[j], 1, PMIX_STRING))) { return ret; } } /* env */ nvals = PMIx_Argv_count(app[i].env); if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int32(regtypes, buffer, &nvals, 1, PMIX_INT32))) { return ret; } for (j = 0; j < nvals; j++) { if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &app[i].env[j], 1, PMIX_STRING))) { return ret; } } /* cwd */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &app[i].cwd, 1, PMIX_STRING))) { return ret; } /* maxprocs */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int(regtypes, buffer, &app[i].maxprocs, 1, PMIX_INT))) { return ret; } /* info array */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_sizet(regtypes, buffer, &app[i].ninfo, 1, PMIX_SIZE))) { return ret; } if (0 < app[i].ninfo) { if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_info(regtypes, buffer, app[i].info, app[i].ninfo, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_kval_t *ptr; int32_t i; pmix_status_t ret; char *st; ptr = (pmix_kval_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack the key */ st = ptr[i].key; if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &st, 1, PMIX_STRING))) { return ret; } /* pack the value */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_value(regtypes, buffer, ptr[i].value, 1, PMIX_VALUE))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_modex_data_t *ptr; int32_t i; pmix_status_t ret; ptr = (pmix_modex_data_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_sizet(regtypes, buffer, &ptr[i].size, 1, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_byte(regtypes, buffer, ptr[i].blob, ptr[i].size, PMIX_UINT8))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_pack_byte(regtypes, buffer, src, num_vals, PMIX_UINT8); } pmix_status_t pmix20_bfrop_pack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_pack_byte(regtypes, buffer, src, num_vals, PMIX_UINT8); } pmix_status_t pmix20_bfrop_pack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_pack_byte(regtypes, buffer, src, num_vals, PMIX_UINT8); } pmix_status_t pmix20_bfrop_pack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_pack_byte(regtypes, buffer, src, num_vals, PMIX_UINT8); } pmix_status_t pmix20_bfrop_pack_infodirs(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_pack_int32(regtypes, buffer, src, num_vals, PMIX_UINT32); } pmix_status_t pmix20_bfrop_pack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; int i; pmix_byte_object_t *bo; PMIX_HIDE_UNUSED_PARAMS(type); bo = (pmix_byte_object_t *) src; for (i = 0; i < num_vals; i++) { if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_sizet(regtypes, buffer, &bo[i].size, 1, PMIX_SIZE))) { return ret; } if (0 < bo[i].size) { if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_byte(regtypes, buffer, bo[i].bytes, bo[i].size, PMIX_BYTE))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { uint8_t foo = 1; PMIX_HIDE_UNUSED_PARAMS(src, num_vals, type); /* it obviously makes no sense to pack a pointer and * send it somewhere else, so we just pack a sentinel */ return pmix20_bfrop_pack_byte(regtypes, buffer, &foo, 1, PMIX_UINT8); } pmix_status_t pmix20_bfrop_pack_pstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_pack_byte(regtypes, buffer, src, num_vals, PMIX_UINT8); } pmix_status_t pmix20_bfrop_pack_pinfo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_proc_info_t *pinfo = (pmix_proc_info_t *) src; pmix_status_t ret; int32_t i; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; i++) { /* pack the proc identifier */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_proc(regtypes, buffer, &pinfo[i].proc, 1, PMIX_PROC))) { return ret; } /* pack the hostname and exec */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &pinfo[i].hostname, 1, PMIX_STRING))) { return ret; } if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, &pinfo[i].executable_name, 1, PMIX_STRING))) { return ret; } /* pack the pid and state */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_pid(regtypes, buffer, &pinfo[i].pid, 1, PMIX_PID))) { return ret; } if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_pstate(regtypes, buffer, &pinfo[i].state, 1, PMIX_PROC_STATE))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_data_array_t *p = (pmix_data_array_t *) src; pmix_status_t ret; int32_t i; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; i++) { /* pack the actual type in the array */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_datatype(regtypes, buffer, &p[i].type, 1, PMIX_DATA_TYPE))) { return ret; } /* pack the number of array elements */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_sizet(regtypes, buffer, &p[i].size, 1, PMIX_SIZE))) { return ret; } if (0 == p[i].size || PMIX_UNDEF == p[i].type) { /* nothing left to do */ continue; } /* pack the actual elements */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_buffer(regtypes, buffer, p[i].array, p[i].size, p[i].type))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_pack_int32(regtypes, buffer, src, num_vals, PMIX_UINT32); } pmix_status_t pmix20_bfrop_pack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_query_t *pq = (pmix_query_t *) src; pmix_status_t ret; int32_t i; int32_t nkeys; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; i++) { /* pack the number of keys */ nkeys = PMIx_Argv_count(pq[i].keys); if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_int32(regtypes, buffer, &nkeys, 1, PMIX_INT32))) { return ret; } if (0 < nkeys) { /* pack the keys */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_string(regtypes, buffer, pq[i].keys, nkeys, PMIX_STRING))) { return ret; } } /* pack the number of qualifiers */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_sizet(regtypes, buffer, &pq[i].nqual, 1, PMIX_SIZE))) { return ret; } if (0 < pq[i].nqual) { /* pack any provided qualifiers */ if (PMIX_SUCCESS != (ret = pmix20_bfrop_pack_info(regtypes, buffer, pq[i].qualifiers, pq[i].nqual, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_pack_alloc_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix20_bfrop_pack_byte(regtypes, buffer, src, num_vals, PMIX_UINT8); } /**** DEPRECATED ****/ pmix_status_t pmix20_bfrop_pack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_info_array_t *ptr; int32_t i; pmix_status_t ret; ptr = (pmix_info_array_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack the size */ if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_sizet(regtypes, buffer, &ptr[i].size, 1, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { /* pack the values */ if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_info(regtypes, buffer, ptr[i].array, ptr[i].size, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } /********************/ pmix-6.1.1~rc2/src/mca/bfrops/v20/bfrop_pmix20.c0000664000175000017500000005730315203536752021411 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "bfrop_pmix20.h" #include "internal.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_error.h" static pmix_status_t init(void); static void finalize(void); static const char *data_type_string(pmix_data_type_t type); pmix_bfrops_module_t pmix_bfrops_pmix20_module = { .version = "v20", .init = init, .finalize = finalize, .pack = pmix20_bfrop_pack, .unpack = pmix20_bfrop_unpack, .copy = pmix20_bfrop_copy, .print = pmix20_bfrop_print, .copy_payload = pmix20_bfrop_copy_payload, .value_xfer = pmix20_bfrop_value_xfer, .value_load = pmix20_bfrop_value_load, .value_unload = pmix20_bfrop_value_unload, .value_cmp = pmix20_bfrop_value_cmp, .data_type_string = data_type_string }; static pmix_status_t init(void) { /* some standard types don't require anything special */ PMIX_REGISTER_TYPE("PMIX_BOOL", PMIX_BOOL, pmix20_bfrop_pack_bool, pmix20_bfrop_unpack_bool, pmix20_bfrop_std_copy, pmix20_bfrop_print_bool, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE", PMIX_BYTE, pmix20_bfrop_pack_byte, pmix20_bfrop_unpack_byte, pmix20_bfrop_std_copy, pmix20_bfrop_print_byte, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_STRING", PMIX_STRING, pmix20_bfrop_pack_string, pmix20_bfrop_unpack_string, pmix20_bfrop_copy_string, pmix20_bfrop_print_string, &pmix_mca_bfrops_v20_component.types); /* Register the rest of the standard generic types to point to internal functions */ PMIX_REGISTER_TYPE("PMIX_SIZE", PMIX_SIZE, pmix20_bfrop_pack_sizet, pmix20_bfrop_unpack_sizet, pmix20_bfrop_std_copy, pmix20_bfrop_print_size, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_PID", PMIX_PID, pmix20_bfrop_pack_pid, pmix20_bfrop_unpack_pid, pmix20_bfrop_std_copy, pmix20_bfrop_print_pid, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_INT", PMIX_INT, pmix20_bfrop_pack_int, pmix20_bfrop_unpack_int, pmix20_bfrop_std_copy, pmix20_bfrop_print_int, &pmix_mca_bfrops_v20_component.types); /* Register all the standard fixed types to point to base functions */ PMIX_REGISTER_TYPE("PMIX_INT8", PMIX_INT8, pmix20_bfrop_pack_byte, pmix20_bfrop_unpack_byte, pmix20_bfrop_std_copy, pmix20_bfrop_print_int8, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_INT16", PMIX_INT16, pmix20_bfrop_pack_int16, pmix20_bfrop_unpack_int16, pmix20_bfrop_std_copy, pmix20_bfrop_print_int16, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_INT32", PMIX_INT32, pmix20_bfrop_pack_int32, pmix20_bfrop_unpack_int32, pmix20_bfrop_std_copy, pmix20_bfrop_print_int32, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_INT64", PMIX_INT64, pmix20_bfrop_pack_int64, pmix20_bfrop_unpack_int64, pmix20_bfrop_std_copy, pmix20_bfrop_print_int64, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_UINT", PMIX_UINT, pmix20_bfrop_pack_int, pmix20_bfrop_unpack_int, pmix20_bfrop_std_copy, pmix20_bfrop_print_uint, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_UINT8", PMIX_UINT8, pmix20_bfrop_pack_byte, pmix20_bfrop_unpack_byte, pmix20_bfrop_std_copy, pmix20_bfrop_print_uint8, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_UINT16", PMIX_UINT16, pmix20_bfrop_pack_int16, pmix20_bfrop_unpack_int16, pmix20_bfrop_std_copy, pmix20_bfrop_print_uint16, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_UINT32", PMIX_UINT32, pmix20_bfrop_pack_int32, pmix20_bfrop_unpack_int32, pmix20_bfrop_std_copy, pmix20_bfrop_print_uint32, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_UINT64", PMIX_UINT64, pmix20_bfrop_pack_int64, pmix20_bfrop_unpack_int64, pmix20_bfrop_std_copy, pmix20_bfrop_print_uint64, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_FLOAT", PMIX_FLOAT, pmix20_bfrop_pack_float, pmix20_bfrop_unpack_float, pmix20_bfrop_std_copy, pmix20_bfrop_print_float, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_DOUBLE", PMIX_DOUBLE, pmix20_bfrop_pack_double, pmix20_bfrop_unpack_double, pmix20_bfrop_std_copy, pmix20_bfrop_print_double, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_TIMEVAL", PMIX_TIMEVAL, pmix20_bfrop_pack_timeval, pmix20_bfrop_unpack_timeval, pmix20_bfrop_std_copy, pmix20_bfrop_print_timeval, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_TIME", PMIX_TIME, pmix20_bfrop_pack_time, pmix20_bfrop_unpack_time, pmix20_bfrop_std_copy, pmix20_bfrop_print_time, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_STATUS", PMIX_STATUS, pmix20_bfrop_pack_status, pmix20_bfrop_unpack_status, pmix20_bfrop_std_copy, pmix20_bfrop_print_status, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_VALUE", PMIX_VALUE, pmix20_bfrop_pack_value, pmix20_bfrop_unpack_value, pmix20_bfrop_copy_value, pmix20_bfrop_print_value, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_PROC", PMIX_PROC, pmix20_bfrop_pack_proc, pmix20_bfrop_unpack_proc, pmix20_bfrop_copy_proc, pmix20_bfrop_print_proc, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_APP", PMIX_APP, pmix20_bfrop_pack_app, pmix20_bfrop_unpack_app, pmix20_bfrop_copy_app, pmix20_bfrop_print_app, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_INFO", PMIX_INFO, pmix20_bfrop_pack_info, pmix20_bfrop_unpack_info, pmix20_bfrop_copy_info, pmix20_bfrop_print_info, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_PDATA", PMIX_PDATA, pmix20_bfrop_pack_pdata, pmix20_bfrop_unpack_pdata, pmix20_bfrop_copy_pdata, pmix20_bfrop_print_pdata, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_BUFFER", PMIX_BUFFER, pmix20_bfrop_pack_buf, pmix20_bfrop_unpack_buf, pmix20_bfrop_copy_buf, pmix20_bfrop_print_buf, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE_OBJECT", PMIX_BYTE_OBJECT, pmix20_bfrop_pack_bo, pmix20_bfrop_unpack_bo, pmix20_bfrop_copy_bo, pmix20_bfrop_print_bo, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_KVAL", PMIX_KVAL, pmix20_bfrop_pack_kval, pmix20_bfrop_unpack_kval, pmix20_bfrop_copy_kval, pmix20_bfrop_print_kval, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_MODEX", PMIX_MODEX, pmix20_bfrop_pack_modex, pmix20_bfrop_unpack_modex, pmix20_bfrop_copy_modex, pmix20_bfrop_print_modex, &pmix_mca_bfrops_v20_component.types); /* these are fixed-sized values and can be done by base */ PMIX_REGISTER_TYPE("PMIX_PERSIST", PMIX_PERSIST, pmix20_bfrop_pack_persist, pmix20_bfrop_unpack_persist, pmix20_bfrop_std_copy, pmix20_bfrop_print_persist, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_POINTER", PMIX_POINTER, pmix20_bfrop_pack_ptr, pmix20_bfrop_unpack_ptr, pmix20_bfrop_std_copy, pmix20_bfrop_print_ptr, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_SCOPE", PMIX_SCOPE, pmix20_bfrop_pack_scope, pmix20_bfrop_unpack_scope, pmix20_bfrop_std_copy, pmix20_bfrop_print_scope, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_RANGE", PMIX_DATA_RANGE, pmix20_bfrop_pack_range, pmix20_bfrop_unpack_range, pmix20_bfrop_std_copy, pmix20_bfrop_print_ptr, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_COMMAND", PMIX_COMMAND, pmix20_bfrop_pack_cmd, pmix20_bfrop_unpack_cmd, pmix20_bfrop_std_copy, pmix20_bfrop_print_cmd, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_INFO_DIRECTIVES", PMIX_INFO_DIRECTIVES, pmix20_bfrop_pack_infodirs, pmix20_bfrop_unpack_infodirs, pmix20_bfrop_std_copy, pmix20_bfrop_print_infodirs, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_TYPE", PMIX_DATA_TYPE, pmix20_bfrop_pack_datatype, pmix20_bfrop_unpack_datatype, pmix20_bfrop_std_copy, pmix_bfrops_base_print_datatype, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_STATE", PMIX_PROC_STATE, pmix20_bfrop_pack_pstate, pmix20_bfrop_unpack_pstate, pmix20_bfrop_std_copy, pmix20_bfrop_print_pstate, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_INFO", PMIX_PROC_INFO, pmix20_bfrop_pack_pinfo, pmix20_bfrop_unpack_pinfo, pmix20_bfrop_copy_pinfo, pmix20_bfrop_print_pinfo, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_ARRAY", PMIX_DATA_ARRAY, pmix20_bfrop_pack_darray, pmix20_bfrop_unpack_darray, pmix20_bfrop_copy_darray, pmix20_bfrop_print_darray, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_RANK", PMIX_PROC_RANK, pmix20_bfrop_pack_rank, pmix20_bfrop_unpack_rank, pmix20_bfrop_std_copy, pmix20_bfrop_print_rank, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_QUERY", PMIX_QUERY, pmix20_bfrop_pack_query, pmix20_bfrop_unpack_query, pmix20_bfrop_copy_query, pmix20_bfrop_print_query, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_STRING", PMIX_COMPRESSED_STRING, pmix20_bfrop_pack_bo, pmix20_bfrop_unpack_bo, pmix20_bfrop_copy_bo, pmix20_bfrop_print_bo, &pmix_mca_bfrops_v20_component.types); PMIX_REGISTER_TYPE("PMIX_ALLOC_DIRECTIVE", PMIX_ALLOC_DIRECTIVE, pmix20_bfrop_pack_alloc_directive, pmix20_bfrop_unpack_alloc_directive, pmix20_bfrop_std_copy, pmix20_bfrop_print_alloc_directive, &pmix_mca_bfrops_v20_component.types); /**** DEPRECATED ****/ PMIX_REGISTER_TYPE("PMIX_INFO_ARRAY", PMIX_INFO_ARRAY, pmix20_bfrop_pack_array, pmix20_bfrop_unpack_array, pmix20_bfrop_copy_array, pmix20_bfrop_print_array, &pmix_mca_bfrops_v20_component.types); /********************/ return PMIX_SUCCESS; } static void finalize(void) { int n; pmix_bfrop_type_info_t *info; for (n = 0; n < pmix_mca_bfrops_v20_component.types.size; n++) { if (NULL != (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v20_component.types, n))) { PMIX_RELEASE(info); pmix_pointer_array_set_item(&pmix_mca_bfrops_v20_component.types, n, NULL); } } } static const char *data_type_string(pmix_data_type_t type) { pmix_bfrop_type_info_t *info; info = (pmix_bfrop_type_info_t *)pmix_pointer_array_get_item(&pmix_mca_bfrops_v20_component.types, type); if (NULL == info) { return NULL; } return info->odti_name; } pmix_data_type_t pmix20_v21_to_v20_datatype(pmix_data_type_t v21type) { pmix_data_type_t v20type; /* iI'm passing the data type to * a PMIx v20 compatible client. The data type was redefined * in v21, and so we have to do some conversions here */ switch (v21type) { case PMIX_COMMAND: /* the peer unfortunately didn't separate these out, * but instead set them to PMIX_UINT32 */ v20type = PMIX_UINT32; break; default: v20type = v21type; } return v20type; } pmix_status_t pmix20_bfrop_store_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t type) { pmix_data_type_t v20type; v20type = pmix20_v21_to_v20_datatype(type); return pmix20_bfrop_pack_datatype(regtypes, buffer, &v20type, 1, PMIX_DATA_TYPE); } pmix_status_t pmix20_bfrop_get_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t *type) { int32_t n = 1; pmix_status_t rc; rc = pmix20_bfrop_unpack_datatype(regtypes, buffer, type, &n, PMIX_DATA_TYPE); return rc; } void pmix20_bfrop_value_load(pmix_value_t *v, const void *data, pmix_data_type_t type) { pmix_byte_object_t *bo; pmix_proc_info_t *pi; v->type = type; if (NULL == data) { /* just set the fields to zero */ memset(&v->data, 0, sizeof(v->data)); if (PMIX_BOOL == type) { v->data.flag = true; // existence of the attribute indicates true unless specified different } } else { switch (type) { case PMIX_UNDEF: break; case PMIX_BOOL: memcpy(&(v->data.flag), data, 1); break; case PMIX_BYTE: memcpy(&(v->data.byte), data, 1); break; case PMIX_STRING: v->data.string = strdup(data); break; case PMIX_SIZE: memcpy(&(v->data.size), data, sizeof(size_t)); break; case PMIX_PID: memcpy(&(v->data.pid), data, sizeof(pid_t)); break; case PMIX_INT: memcpy(&(v->data.integer), data, sizeof(int)); break; case PMIX_INT8: memcpy(&(v->data.int8), data, 1); break; case PMIX_INT16: memcpy(&(v->data.int16), data, 2); break; case PMIX_INT32: memcpy(&(v->data.int32), data, 4); break; case PMIX_INT64: memcpy(&(v->data.int64), data, 8); break; case PMIX_UINT: memcpy(&(v->data.uint), data, sizeof(int)); break; case PMIX_UINT8: memcpy(&(v->data.uint8), data, 1); break; case PMIX_UINT16: memcpy(&(v->data.uint16), data, 2); break; case PMIX_UINT32: memcpy(&(v->data.uint32), data, 4); break; case PMIX_UINT64: memcpy(&(v->data.uint64), data, 8); break; case PMIX_FLOAT: memcpy(&(v->data.fval), data, sizeof(float)); break; case PMIX_DOUBLE: memcpy(&(v->data.dval), data, sizeof(double)); break; case PMIX_TIMEVAL: memcpy(&(v->data.tv), data, sizeof(struct timeval)); break; case PMIX_TIME: memcpy(&(v->data.time), data, sizeof(time_t)); break; case PMIX_STATUS: memcpy(&(v->data.status), data, sizeof(pmix_status_t)); break; case PMIX_PROC_RANK: memcpy(&(v->data.rank), data, sizeof(pmix_rank_t)); break; case PMIX_PROC: PMIX_PROC_CREATE(v->data.proc, 1); if (NULL == v->data.proc) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } memcpy(v->data.proc, data, sizeof(pmix_proc_t)); break; case PMIX_BYTE_OBJECT: bo = (pmix_byte_object_t *) data; v->data.bo.bytes = bo->bytes; memcpy(&(v->data.bo.size), &bo->size, sizeof(size_t)); break; case PMIX_PERSIST: memcpy(&(v->data.persist), data, sizeof(pmix_persistence_t)); break; case PMIX_SCOPE: memcpy(&(v->data.scope), data, sizeof(pmix_scope_t)); break; case PMIX_DATA_RANGE: memcpy(&(v->data.range), data, sizeof(pmix_data_range_t)); break; case PMIX_PROC_STATE: memcpy(&(v->data.state), data, sizeof(pmix_proc_state_t)); break; case PMIX_PROC_INFO: PMIX_PROC_INFO_CREATE(v->data.pinfo, 1); if (NULL == v->data.pinfo) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } pi = (pmix_proc_info_t *) data; memcpy(&(v->data.pinfo->proc), &pi->proc, sizeof(pmix_proc_t)); if (NULL != pi->hostname) { v->data.pinfo->hostname = strdup(pi->hostname); } if (NULL != pi->executable_name) { v->data.pinfo->executable_name = strdup(pi->executable_name); } memcpy(&(v->data.pinfo->pid), &pi->pid, sizeof(pid_t)); memcpy(&(v->data.pinfo->exit_code), &pi->exit_code, sizeof(int)); break; case PMIX_POINTER: memcpy(&(v->data.ptr), data, sizeof(void *)); break; default: /* silence warnings */ PMIX_ERROR_LOG(PMIX_ERR_UNKNOWN_DATA_TYPE); break; } } } pmix_status_t pmix20_bfrop_value_unload(pmix_value_t *kv, void **data, size_t *sz) { pmix_status_t rc; pmix_proc_t *pc; rc = PMIX_SUCCESS; if (NULL == data || (NULL == *data && PMIX_STRING != kv->type && PMIX_BYTE_OBJECT != kv->type)) { rc = PMIX_ERR_BAD_PARAM; } else { switch (kv->type) { case PMIX_UNDEF: rc = PMIX_ERR_UNKNOWN_DATA_TYPE; break; case PMIX_BOOL: memcpy(*data, &(kv->data.flag), 1); *sz = 1; break; case PMIX_BYTE: memcpy(*data, &(kv->data.byte), 1); *sz = 1; break; case PMIX_STRING: if (NULL != kv->data.string) { *data = strdup(kv->data.string); *sz = strlen(kv->data.string); } break; case PMIX_SIZE: memcpy(*data, &(kv->data.size), sizeof(size_t)); *sz = sizeof(size_t); break; case PMIX_PID: memcpy(*data, &(kv->data.pid), sizeof(pid_t)); *sz = sizeof(pid_t); break; case PMIX_INT: memcpy(*data, &(kv->data.integer), sizeof(int)); *sz = sizeof(int); break; case PMIX_INT8: memcpy(*data, &(kv->data.int8), 1); *sz = 1; break; case PMIX_INT16: memcpy(*data, &(kv->data.int16), 2); *sz = 2; break; case PMIX_INT32: memcpy(*data, &(kv->data.int32), 4); *sz = 4; break; case PMIX_INT64: memcpy(*data, &(kv->data.int64), 8); *sz = 8; break; case PMIX_UINT: memcpy(*data, &(kv->data.uint), sizeof(int)); *sz = sizeof(int); break; case PMIX_UINT8: memcpy(*data, &(kv->data.uint8), 1); *sz = 1; break; case PMIX_UINT16: memcpy(*data, &(kv->data.uint16), 2); *sz = 2; break; case PMIX_UINT32: memcpy(*data, &(kv->data.uint32), 4); *sz = 4; break; case PMIX_UINT64: memcpy(*data, &(kv->data.uint64), 8); *sz = 8; break; case PMIX_FLOAT: memcpy(*data, &(kv->data.fval), sizeof(float)); *sz = sizeof(float); break; case PMIX_DOUBLE: memcpy(*data, &(kv->data.dval), sizeof(double)); *sz = sizeof(double); break; case PMIX_TIMEVAL: memcpy(*data, &(kv->data.tv), sizeof(struct timeval)); *sz = sizeof(struct timeval); break; case PMIX_TIME: memcpy(*data, &(kv->data.time), sizeof(time_t)); *sz = sizeof(time_t); break; case PMIX_STATUS: memcpy(*data, &(kv->data.status), sizeof(pmix_status_t)); *sz = sizeof(pmix_status_t); break; case PMIX_PROC_RANK: memcpy(*data, &(kv->data.rank), sizeof(pmix_rank_t)); *sz = sizeof(pmix_rank_t); break; case PMIX_PROC: PMIX_PROC_CREATE(pc, 1); if (NULL == pc) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); rc = PMIX_ERR_NOMEM; break; } memcpy(pc, kv->data.proc, sizeof(pmix_proc_t)); *sz = sizeof(pmix_proc_t); *data = pc; break; case PMIX_BYTE_OBJECT: if (NULL != kv->data.bo.bytes && 0 < kv->data.bo.size) { *data = kv->data.bo.bytes; *sz = kv->data.bo.size; } else { *data = NULL; *sz = 0; } break; case PMIX_PERSIST: memcpy(*data, &(kv->data.persist), sizeof(pmix_persistence_t)); *sz = sizeof(pmix_persistence_t); break; case PMIX_SCOPE: memcpy(*data, &(kv->data.scope), sizeof(pmix_scope_t)); *sz = sizeof(pmix_scope_t); break; case PMIX_DATA_RANGE: memcpy(*data, &(kv->data.range), sizeof(pmix_data_range_t)); *sz = sizeof(pmix_data_range_t); break; case PMIX_PROC_STATE: memcpy(*data, &(kv->data.state), sizeof(pmix_proc_state_t)); *sz = sizeof(pmix_proc_state_t); break; case PMIX_POINTER: memcpy(*data, &(kv->data.ptr), sizeof(void *)); *sz = sizeof(void *); break; default: /* silence warnings */ rc = PMIX_ERROR; break; } } return rc; } pmix-6.1.1~rc2/src/mca/bfrops/v20/Makefile.am0000664000175000017500000000360615203536752020767 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = \ bfrop_pmix20.h \ internal.h sources = \ bfrop_pmix20_component.c \ bfrop_pmix20.c \ copy.c \ pack.c \ print.c \ unpack.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_bfrops_v20_DSO lib = lib_sources = component = pmix_mca_bfrops_v20.la component_sources = $(headers) $(sources) else lib = libpmix_mca_bfrops_v20.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_bfrops_v20_la_SOURCES = $(component_sources) pmix_mca_bfrops_v20_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_bfrops_v20_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_bfrops_v20_la_SOURCES = $(lib_sources) libpmix_mca_bfrops_v20_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/bfrops/v20/print.c0000664000175000017500000013165515203536752020241 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_stdint.h" #include #ifdef HAVE_TIME_H # include #endif #include "bfrop_pmix20.h" #include "internal.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_error.h" pmix_status_t pmix20_bfrop_print(char **output, char *prefix, void *src, pmix_data_type_t type) { pmix_bfrop_type_info_t *info; /* check for error */ if (NULL == output) { return PMIX_ERR_BAD_PARAM; } /* Lookup the print function for this type and call it */ if (NULL == (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v20_component.types, type))) { return PMIX_ERR_UNKNOWN_DATA_TYPE; } return info->odti_print_fn(output, prefix, src, type); } /* * STANDARD PRINT FUNCTIONS FOR SYSTEM TYPES */ pmix_status_t pmix20_bfrop_print_bool(char **output, char *prefix, bool *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_BOOL\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_BOOL\tValue: %s", prefix, (*src) ? "TRUE" : "FALSE")) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_byte(char **output, char *prefix, uint8_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_BYTE\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_BYTE\tValue: %x", prefx, *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_string(char **output, char *prefix, char *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_STRING\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_STRING\tValue: %s", prefx, src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_size(char **output, char *prefix, size_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_SIZE\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_SIZE\tValue: %lu", prefx, (unsigned long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_pid(char **output, char *prefix, pid_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_PID\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_PID\tValue: %lu", prefx, (unsigned long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_int(char **output, char *prefix, int *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_INT\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_INT\tValue: %ld", prefx, (long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_uint(char **output, char *prefix, uint *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_UINT\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_UINT\tValue: %lu", prefx, (unsigned long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_uint8(char **output, char *prefix, uint8_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_UINT8\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_UINT8\tValue: %u", prefx, (unsigned int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_uint16(char **output, char *prefix, uint16_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_UINT16\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_UINT16\tValue: %u", prefx, (unsigned int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_uint32(char **output, char *prefix, uint32_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_UINT32\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_UINT32\tValue: %u", prefx, (unsigned int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_int8(char **output, char *prefix, int8_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_INT8\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_INT8\tValue: %d", prefx, (int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_int16(char **output, char *prefix, int16_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_INT16\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_INT16\tValue: %d", prefx, (int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_int32(char **output, char *prefix, int32_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_INT32\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_INT32\tValue: %d", prefx, (int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_uint64(char **output, char *prefix, uint64_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_UINT64\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_UINT64\tValue: %lu", prefx, (unsigned long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_int64(char **output, char *prefix, int64_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_INT64\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_INT64\tValue: %ld", prefx, (long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_float(char **output, char *prefix, float *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_FLOAT\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_FLOAT\tValue: %f", prefx, *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_double(char **output, char *prefix, double *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_DOUBLE\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_DOUBLE\tValue: %f", prefx, *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_time(char **output, char *prefix, time_t *src, pmix_data_type_t type) { char *prefx; char *t; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_TIME\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } t = ctime(src); t[strlen(t) - 1] = '\0'; // remove trailing newline if (0 > asprintf(output, "%sData type: PMIX_TIME\tValue: %s", prefx, t)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_timeval(char **output, char *prefix, struct timeval *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_TIMEVAL\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_TIMEVAL\tValue: %ld.%06ld", prefx, (long) src->tv_sec, (long) src->tv_usec)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_status(char **output, char *prefix, pmix_status_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_STATUS\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_STATUS\tValue: %s", prefx, PMIx_Error_string(*src))) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } /* PRINT FUNCTIONS FOR GENERIC PMIX TYPES */ /* * PMIX_VALUE */ pmix_status_t pmix20_bfrop_print_value(char **output, char *prefix, pmix_value_t *src, pmix_data_type_t type) { char *prefx; int rc; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_VALUE\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } switch (src->type) { case PMIX_UNDEF: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UNDEF", prefx); break; case PMIX_BYTE: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_BYTE\tValue: %x", prefx, src->data.byte); break; case PMIX_STRING: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_STRING\tValue: %s", prefx, src->data.string); break; case PMIX_SIZE: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_SIZE\tValue: %lu", prefx, (unsigned long) src->data.size); break; case PMIX_PID: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_PID\tValue: %lu", prefx, (unsigned long) src->data.pid); break; case PMIX_INT: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_INT\tValue: %d", prefx, src->data.integer); break; case PMIX_INT8: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_INT8\tValue: %d", prefx, (int) src->data.int8); break; case PMIX_INT16: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_INT16\tValue: %d", prefx, (int) src->data.int16); break; case PMIX_INT32: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_INT32\tValue: %d", prefx, src->data.int32); break; case PMIX_INT64: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_INT64\tValue: %ld", prefx, (long) src->data.int64); break; case PMIX_UINT: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UINT\tValue: %u", prefx, src->data.uint); break; case PMIX_UINT8: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UINT8\tValue: %u", prefx, (unsigned int) src->data.uint8); break; case PMIX_UINT16: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UINT16\tValue: %u", prefx, (unsigned int) src->data.uint16); break; case PMIX_UINT32: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UINT32\tValue: %u", prefx, src->data.uint32); break; case PMIX_UINT64: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UINT64\tValue: %lu", prefx, (unsigned long) src->data.uint64); break; case PMIX_FLOAT: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_FLOAT\tValue: %f", prefx, src->data.fval); break; case PMIX_DOUBLE: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_DOUBLE\tValue: %f", prefx, src->data.dval); break; case PMIX_TIMEVAL: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_TIMEVAL\tValue: %ld.%06ld", prefx, (long) src->data.tv.tv_sec, (long) src->data.tv.tv_usec); break; case PMIX_TIME: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_TIME\tValue: %s", prefx, ctime(&src->data.time)); break; case PMIX_STATUS: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_STATUS\tValue: %s", prefx, PMIx_Error_string(src->data.status)); break; case PMIX_PROC: if (NULL == src->data.proc) { rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_PROC\tNULL", prefx); } else { rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_PROC\t%s:%lu", prefx, src->data.proc->nspace, (unsigned long) src->data.proc->rank); } break; case PMIX_BYTE_OBJECT: rc = asprintf(output, "%sPMIX_VALUE: Data type: BYTE_OBJECT\tSIZE: %ld", prefx, (long) src->data.bo.size); break; case PMIX_PERSIST: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_PERSIST\tValue: %s", prefx, PMIx_Persistence_string(src->data.persist)); break; case PMIX_SCOPE: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_SCOPE\tValue: %s", prefx, PMIx_Scope_string(src->data.scope)); break; case PMIX_DATA_RANGE: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_DATA_RANGE\tValue: %s", prefx, PMIx_Data_range_string(src->data.range)); break; case PMIX_PROC_STATE: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_STATE\tValue: %s", prefx, PMIx_Proc_state_string(src->data.state)); break; case PMIX_PROC_INFO: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_PROC_INFO\tProc: %s:%lu\n%s\tHost: " "%s\tExecutable: %s\tPid: %lu", prefx, src->data.pinfo->proc.nspace, (unsigned long) src->data.pinfo->proc.rank, prefx, src->data.pinfo->hostname, src->data.pinfo->executable_name, (unsigned long) src->data.pinfo->pid); break; case PMIX_DATA_ARRAY: rc = asprintf(output, "%sPMIX_VALUE: Data type: DATA_ARRAY\tARRAY SIZE: %ld", prefx, (long) src->data.darray->size); break; default: rc = asprintf(output, "%sPMIX_VALUE: Data type: UNKNOWN\tValue: UNPRINTABLE", prefx); break; } if (prefx != prefix) { free(prefx); } if (0 > rc) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_info(char **output, char *prefix, pmix_info_t *src, pmix_data_type_t type) { char *tmp; int rc; PMIX_HIDE_UNUSED_PARAMS(type); pmix20_bfrop_print_value(&tmp, NULL, &src->value, PMIX_VALUE); rc = asprintf(output, "%sKEY: %s DIRECTIVES: %0x %s", prefix, src->key, src->flags, (NULL == tmp) ? "PMIX_VALUE: NULL" : tmp); if (NULL != tmp) { free(tmp); } if (0 > rc) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_pdata(char **output, char *prefix, pmix_pdata_t *src, pmix_data_type_t type) { char *tmp1, *tmp2; int rc; PMIX_HIDE_UNUSED_PARAMS(type); pmix20_bfrop_print_proc(&tmp1, NULL, &src->proc, PMIX_PROC); pmix20_bfrop_print_value(&tmp2, NULL, &src->value, PMIX_VALUE); rc = asprintf(output, "%s %s KEY: %s %s", prefix, tmp1, src->key, (NULL == tmp2) ? "NULL" : tmp2); if (NULL != tmp1) { free(tmp1); } if (NULL != tmp2) { free(tmp2); } if (0 > rc) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_buf(char **output, char *prefix, pmix_buffer_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_app(char **output, char *prefix, pmix_app_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_proc(char **output, char *prefix, pmix_proc_t *src, pmix_data_type_t type) { char *prefx; int rc; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } switch (src->rank) { case PMIX_RANK_UNDEF: rc = asprintf(output, "%sPROC: %s:PMIX_RANK_UNDEF", prefx, src->nspace); break; case PMIX_RANK_WILDCARD: rc = asprintf(output, "%sPROC: %s:PMIX_RANK_WILDCARD", prefx, src->nspace); break; case PMIX_RANK_LOCAL_NODE: rc = asprintf(output, "%sPROC: %s:PMIX_RANK_LOCAL_NODE", prefx, src->nspace); break; default: rc = asprintf(output, "%sPROC: %s:%lu", prefx, src->nspace, (unsigned long) (src->rank)); } if (prefx != prefix) { free(prefx); } if (0 > rc) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_kval(char **output, char *prefix, pmix_kval_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_modex(char **output, char *prefix, pmix_modex_data_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_persist(char **output, char *prefix, pmix_persistence_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_PERSIST\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_PERSIST\tValue: %ld", prefx, (long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_scope(char **output, char *prefix, pmix_scope_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } if (0 > asprintf(output, "%sData type: PMIX_SCOPE\tValue: %s", prefx, PMIx_Scope_string(*src))) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_range(char **output, char *prefix, pmix_data_range_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } if (0 > asprintf(output, "%sData type: PMIX_DATA_RANGE\tValue: %s", prefx, PMIx_Data_range_string(*src))) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_cmd(char **output, char *prefix, pmix_cmd_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } if (0 > asprintf(output, "%sData type: PMIX_CMD\tValue: %s", prefx, pmix_command_string(*src))) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_infodirs(char **output, char *prefix, pmix_info_directives_t *src, pmix_data_type_t type) { char *prefx, *tmp; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } tmp = PMIx_Info_directives_string(*src); if (0 > asprintf(output, "%sData type: PMIX_INFO_DIRECTIVES\tValue: %s", prefx, tmp)) { free(tmp); if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } free(tmp); if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_bo(char **output, char *prefix, pmix_byte_object_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_BYTE_OBJECT\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_BYTE_OBJECT\tSize: %ld", prefx, (long) src->size)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_ptr(char **output, char *prefix, void *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } if (0 > asprintf(output, "%sData type: PMIX_POINTER\tAddress: %p", prefx, src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_pstate(char **output, char *prefix, pmix_proc_state_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } if (0 > asprintf(output, "%sData type: PMIX_PROC_STATE\tValue: %s", prefx, PMIx_Proc_state_string(*src))) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_pinfo(char **output, char *prefix, pmix_proc_info_t *src, pmix_data_type_t type) { char *prefx; pmix_status_t rc = PMIX_SUCCESS; char *p2=NULL, *tmp; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } if (0 > asprintf(&p2, "%s\t", prefx)) { rc = PMIX_ERR_NOMEM; goto done; } if (PMIX_SUCCESS != (rc = pmix20_bfrop_print_proc(&tmp, p2, &src->proc, PMIX_PROC))) { goto done; } if (0 > asprintf(output, "%sData type: PMIX_PROC_INFO\tValue:\n%s\n%sHostname: %s\tExecutable: " "%s\n%sPid: %lu\tExit code: %d\tState: %s", prefx, tmp, p2, src->hostname, src->executable_name, p2, (unsigned long) src->pid, src->exit_code, PMIx_Proc_state_string(src->state))) { rc = PMIX_ERR_NOMEM; } done: if (prefx != prefix) { free(prefx); } if (NULL != p2) { free(p2); } return rc; } pmix_status_t pmix20_bfrop_print_darray(char **output, char *prefix, pmix_data_array_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } if (0 > asprintf(output, "%sData type: PMIX_DATA_ARRAY\tSize: %lu", prefx, (unsigned long) src->size)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_query(char **output, char *prefix, pmix_query_t *src, pmix_data_type_t type) { char *prefx, *p2; pmix_status_t rc = PMIX_SUCCESS; char *tmp, *t2, *t3; size_t n; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } if (0 > asprintf(&p2, "%s\t", prefx)) { rc = PMIX_ERR_NOMEM; goto done; } if (0 > asprintf(&tmp, "%sData type: PMIX_QUERY\tValue:", prefx)) { free(p2); rc = PMIX_ERR_NOMEM; goto done; } /* print out the keys */ if (NULL != src->keys) { for (n = 0; NULL != src->keys[n]; n++) { if (0 > asprintf(&t2, "%s\n%sKey: %s", tmp, p2, src->keys[n])) { free(p2); free(tmp); rc = PMIX_ERR_NOMEM; goto done; } free(tmp); tmp = t2; } } /* now print the qualifiers */ if (0 < src->nqual) { for (n = 0; n < src->nqual; n++) { if (PMIX_SUCCESS != (rc = pmix20_bfrop_print_info(&t2, p2, &src->qualifiers[n], PMIX_PROC))) { free(p2); free(tmp); goto done; } if (0 > asprintf(&t3, "%s\n%s", tmp, t2)) { free(p2); free(tmp); free(t2); rc = PMIX_ERR_NOMEM; goto done; } free(tmp); free(t2); tmp = t3; } } *output = tmp; free(p2); done: if (prefx != prefix) { free(prefx); } return rc; } pmix_status_t pmix20_bfrop_print_rank(char **output, char *prefix, pmix_rank_t *src, pmix_data_type_t type) { char *prefx; int rc; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } switch (*src) { case PMIX_RANK_UNDEF: rc = asprintf(output, "%sData type: PMIX_PROC_RANK\tValue: PMIX_RANK_UNDEF", prefx); break; case PMIX_RANK_WILDCARD: rc = asprintf(output, "%sData type: PMIX_PROC_RANK\tValue: PMIX_RANK_WILDCARD", prefx); break; case PMIX_RANK_LOCAL_NODE: rc = asprintf(output, "%sData type: PMIX_PROC_RANK\tValue: PMIX_RANK_LOCAL_NODE", prefx); break; default: rc = asprintf(output, "%sData type: PMIX_PROC_RANK\tValue: %lu", prefx, (unsigned long) (*src)); } if (prefx != prefix) { free(prefx); } if (0 > rc) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix20_bfrop_print_alloc_directive(char **output, char *prefix, pmix_alloc_directive_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } if (0 > asprintf(output, "%sData type: PMIX_ALLOC_DIRECTIVE\tValue: %s", prefx, PMIx_Alloc_directive_string(*src))) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } /**** DEPRECATED ****/ pmix_status_t pmix20_bfrop_print_array(char **output, char *prefix, pmix_info_array_t *src, pmix_data_type_t type) { size_t j; char *tmp, *tmp2, *tmp3, *pfx; pmix_info_t *s1; PMIX_HIDE_UNUSED_PARAMS(type); if (0 > asprintf(&tmp, "%sARRAY SIZE: %ld", prefix, (long) src->size)) { return PMIX_ERR_NOMEM; } if (0 > asprintf(&pfx, "\n%s\t", (NULL == prefix) ? "" : prefix)) { free(tmp); return PMIX_ERR_NOMEM; } s1 = (pmix_info_t *) src->array; for (j = 0; j < src->size; j++) { pmix20_bfrop_print_info(&tmp2, pfx, &s1[j], PMIX_INFO); if (0 > asprintf(&tmp3, "%s%s", tmp, tmp2)) { free(tmp); free(tmp2); free(pfx); return PMIX_ERR_NOMEM; } free(tmp); free(tmp2); tmp = tmp3; } *output = tmp; free(pfx); return PMIX_SUCCESS; } /********************/ pmix-6.1.1~rc2/src/mca/bfrops/v20/bfrop_pmix20_component.c0000664000175000017500000000674315203536752023475 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennbfropsee and The University * of Tennbfropsee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include "bfrop_pmix20.h" #include "src/mca/bfrops/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_error.h" extern pmix_bfrops_module_t pmix_bfrops_pmix20_module; static pmix_status_t component_open(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_close(void); static pmix_bfrops_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_bfrops_base_component_t pmix_mca_bfrops_v20_component = { .base = { PMIX_BFROPS_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "v20", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .priority = 20, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, bfrops, v20) pmix_status_t component_open(void) { /* setup the types array */ PMIX_CONSTRUCT(&pmix_mca_bfrops_v20_component.types, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_mca_bfrops_v20_component.types, 32, INT_MAX, 16); return PMIX_SUCCESS; } pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = pmix_mca_bfrops_v20_component.priority; *module = (pmix_mca_base_module_t *) &pmix_bfrops_pmix20_module; return PMIX_SUCCESS; } pmix_status_t component_close(void) { PMIX_DESTRUCT(&pmix_mca_bfrops_v20_component.types); return PMIX_SUCCESS; } static pmix_bfrops_module_t *assign_module(void) { pmix_output_verbose(10, pmix_bfrops_base_framework.framework_output, "bfrops:pmix20x assigning module"); return &pmix_bfrops_pmix20_module; } pmix-6.1.1~rc2/src/mca/bfrops/bfrops_types.h0000664000175000017500000001540215203536752021211 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Buffer management types. */ #ifndef PMIX_MCA_BFROP_TYPES_H_ #define PMIX_MCA_BFROP_TYPES_H_ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/class/pmix_object.h" #include "src/class/pmix_pointer_array.h" BEGIN_C_DECLS /* set the bfrops module */ #define PMIX_BFROPS_SET_MODULE(r, mp, p, v) \ do { \ (mp)->nptr->compat.bfrops = pmix_bfrops_base_assign_module((v)); \ if (NULL == (mp)->nptr->compat.bfrops) { \ (r) = PMIX_ERR_INIT; \ } else { \ (p)->nptr->compat.bfrops = (mp)->nptr->compat.bfrops; \ (mp)->protocol = PMIX_PROTOCOL_V2; \ (r) = PMIX_SUCCESS; \ } \ } while (0) /** * buffer type */ typedef uint8_t pmix_bfrop_buffer_type_t; #define PMIX_BFROP_BUFFER_UNDEF 0x00 #define PMIX_BFROP_BUFFER_NON_DESC 0x01 #define PMIX_BFROP_BUFFER_FULLY_DESC 0x02 #define PMIX_BFROP_BUFFER_TYPE_HTON(h) #define PMIX_BFROP_BUFFER_TYPE_NTOH(h) /* internally used object for transferring data * to/from the server and for storing in the * hash tables */ typedef struct { pmix_list_item_t super; char *key; pmix_value_t *value; } pmix_kval_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_kval_t); static inline pmix_kval_t * pmix_bfrop_tma_kval_new( const char *key, pmix_tma_t *tma ) { pmix_kval_t *k = PMIX_NEW(pmix_kval_t, tma); if (PMIX_LIKELY(NULL != k)) { k->key = pmix_tma_strdup(tma, key); k->value = (pmix_value_t *)pmix_tma_malloc(tma, sizeof(pmix_value_t)); if (PMIX_UNLIKELY(NULL == k->value)) { PMIX_RELEASE(k); k = NULL; } } return k; } /* helpful macro extension of the usual PMIX_NEW */ #define PMIX_KVAL_NEW(k, s) \ do { \ (k) = pmix_bfrop_tma_kval_new((s), NULL); \ } while (0) /** * Structure for holding a buffer */ typedef struct { /** First member must be the object's parent */ pmix_object_t parent; /** type of buffer */ pmix_bfrop_buffer_type_t type; /** Start of my memory */ char *base_ptr; /** Where the next data will be packed to (within the allocated memory starting at base_ptr) */ char *pack_ptr; /** Where the next data will be unpacked from (within the allocated memory starting as base_ptr) */ char *unpack_ptr; /** Number of bytes allocated (starting at base_ptr) */ size_t bytes_allocated; /** Number of bytes used by the buffer (i.e., amount of data -- including overhead -- packed in the buffer) */ size_t bytes_used; } pmix_buffer_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_buffer_t); /* Convenience macro for loading a data blob into a pmix_buffer_t * * p - the pmix_peer_t of the process that provided the blob. This * is needed so we can set the buffer type for later unpacking * * b - pointer to pmix_buffer_t * * d - pointer to the data blob * * s - number of bytes in the blob * * NOTE: the macro does NOT copy the data, but simply assigns * its address to the buffer. Accordingly, the macro will * set the provided data blob pointer to NULL and the size * to zero. */ #define PMIX_LOAD_BUFFER(p, b, d, s) \ do { \ (b)->type = (p)->nptr->compat.type; \ (b)->base_ptr = (char *) (d); \ (b)->bytes_used = (s); \ (b)->bytes_allocated = (s); \ (b)->pack_ptr = ((char *) (b)->base_ptr) + (s); \ (b)->unpack_ptr = (b)->base_ptr; \ (d) = NULL; \ (s) = 0; \ } while (0) #define PMIX_LOAD_BUFFER_NON_DESTRUCT(p, b, d, s) \ do { \ (b)->type = (p)->nptr->compat.type; \ (b)->base_ptr = (char *) (d); \ (b)->bytes_used = (s); \ (b)->bytes_allocated = (s); \ (b)->pack_ptr = ((char *) (b)->base_ptr) + (s); \ (b)->unpack_ptr = (b)->base_ptr; \ } while (0) /* Convenience macro for extracting a pmix_buffer_t's payload * as a data blob * * b - pointer to the pmix_buffer_t * * d - char* pointer to the data blob * * s - number of bytes in the blob * * NOTE: the macro does NOT copy the data, but simply assigns * the address of the buffer's payload to the provided pointer. * Accordingly, the macro will set all pmix_buffer_t internal * tracking pointers to NULL and all counters to zero */ #define PMIX_UNLOAD_BUFFER(b, d, s) \ do { \ (d) = (char *) (b)->unpack_ptr; \ (s) = (b)->bytes_used; \ (b)->base_ptr = NULL; \ (b)->bytes_used = 0; \ (b)->bytes_allocated = 0; \ (b)->pack_ptr = NULL; \ (b)->unpack_ptr = NULL; \ } while (0) /* Convenience macro to check for empty buffer without * exposing the internals */ #define PMIX_BUFFER_IS_EMPTY(b) (0 == (b)->bytes_used || (b)->pack_ptr == (b)->unpack_ptr) END_C_DECLS #endif /* PMIX_BFROP_TYPES_H */ pmix-6.1.1~rc2/src/mca/bfrops/v41/0000775000175000017500000000000015203536752016731 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/bfrops/v41/bfrop_pmix41_component.c0000664000175000017500000000674215203536752023502 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennbfropsee and The University * of Tennbfropsee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include "bfrop_pmix41.h" #include "src/mca/bfrops/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_error.h" extern pmix_bfrops_module_t pmix_bfrops_pmix41_module; static pmix_status_t component_open(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_close(void); static pmix_bfrops_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_bfrops_base_component_t pmix_mca_bfrops_v41_component = { .base = { PMIX_BFROPS_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "v41", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .priority = 58, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, bfrops, v41) pmix_status_t component_open(void) { /* setup the types array */ PMIX_CONSTRUCT(&pmix_mca_bfrops_v41_component.types, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_mca_bfrops_v41_component.types, 50, INT_MAX, 16); return PMIX_SUCCESS; } pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = pmix_mca_bfrops_v41_component.priority; *module = (pmix_mca_base_module_t *) &pmix_bfrops_pmix41_module; return PMIX_SUCCESS; } pmix_status_t component_close(void) { PMIX_DESTRUCT(&pmix_mca_bfrops_v41_component.types); return PMIX_SUCCESS; } static pmix_bfrops_module_t *assign_module(void) { pmix_output_verbose(10, pmix_bfrops_base_framework.framework_output, "bfrops:pmix41 assigning module"); return &pmix_bfrops_pmix41_module; } pmix-6.1.1~rc2/src/mca/bfrops/v41/bfrop_pmix41.c0000664000175000017500000005057115203536752021417 0ustar alastairalastair/* * Copyright (c) 20041-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 20041-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 20041-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 20041-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-20141 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-20141 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 20141-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "bfrop_pmix41.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_error.h" static pmix_status_t init(void); static void finalize(void); static pmix_status_t pmix41_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type); static pmix_status_t pmix41_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix41_copy(void **dest, void *src, pmix_data_type_t type); static pmix_status_t pmix41_print(char **output, char *prefix, void *src, pmix_data_type_t type); static const char *data_type_string(pmix_data_type_t type); pmix_bfrops_module_t pmix_bfrops_pmix41_module = { .version = "v41", .init = init, .finalize = finalize, .pack = pmix41_pack, .unpack = pmix41_unpack, .copy = pmix41_copy, .print = pmix41_print, .copy_payload = pmix_bfrops_base_copy_payload, .value_xfer = pmix_bfrops_base_value_xfer, .value_load = pmix_bfrops_base_value_load, .value_unload = pmix_bfrops_base_value_unload, .value_cmp = pmix_bfrops_base_value_cmp, .data_type_string = data_type_string }; static pmix_status_t init(void) { /* some standard types don't require anything special */ PMIX_REGISTER_TYPE("PMIX_BOOL", PMIX_BOOL, pmix_bfrops_base_pack_bool, pmix_bfrops_base_unpack_bool, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_bool, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE", PMIX_BYTE, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_byte, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_STRING", PMIX_STRING, pmix_bfrops_base_pack_string, pmix_bfrops_base_unpack_string, pmix_bfrops_base_copy_string, pmix_bfrops_base_print_string, &pmix_mca_bfrops_v41_component.types); /* Register the rest of the standard generic types to point to internal functions */ PMIX_REGISTER_TYPE("PMIX_SIZE", PMIX_SIZE, pmix_bfrops_base_pack_sizet, pmix_bfrops_base_unpack_sizet, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_size, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_PID", PMIX_PID, pmix_bfrops_base_pack_pid, pmix_bfrops_base_unpack_pid, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pid, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_INT", PMIX_INT, pmix_bfrops_base_pack_int, pmix_bfrops_base_unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int, &pmix_mca_bfrops_v41_component.types); /* Register all the standard fixed types to point to base functions */ PMIX_REGISTER_TYPE("PMIX_INT8", PMIX_INT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int8, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_INT16", PMIX_INT16, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int16, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_INT32", PMIX_INT32, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int32, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_INT64", PMIX_INT64, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int64, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_UINT", PMIX_UINT, pmix_bfrops_base_pack_int, pmix_bfrops_base_unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_UINT8", PMIX_UINT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint8, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_UINT16", PMIX_UINT16, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint16, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_UINT32", PMIX_UINT32, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint32, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_UINT64", PMIX_UINT64, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint64, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_FLOAT", PMIX_FLOAT, pmix_bfrops_base_pack_float, pmix_bfrops_base_unpack_float, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_float, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_DOUBLE", PMIX_DOUBLE, pmix_bfrops_base_pack_double, pmix_bfrops_base_unpack_double, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_double, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_TIMEVAL", PMIX_TIMEVAL, pmix_bfrops_base_pack_timeval, pmix_bfrops_base_unpack_timeval, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_timeval, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_TIME", PMIX_TIME, pmix_bfrops_base_pack_time, pmix_bfrops_base_unpack_time, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_time, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_STATUS", PMIX_STATUS, pmix_bfrops_base_pack_status, pmix_bfrops_base_unpack_status, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_status, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_VALUE", PMIX_VALUE, pmix_bfrops_base_pack_value, pmix_bfrops_base_unpack_value, pmix_bfrops_base_copy_value, pmix_bfrops_base_print_value, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_PROC", PMIX_PROC, pmix_bfrops_base_pack_proc, pmix_bfrops_base_unpack_proc, pmix_bfrops_base_copy_proc, pmix_bfrops_base_print_proc, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_APP", PMIX_APP, pmix_bfrops_base_pack_app, pmix_bfrops_base_unpack_app, pmix_bfrops_base_copy_app, pmix_bfrops_base_print_app, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_INFO", PMIX_INFO, pmix_bfrops_base_pack_info, pmix_bfrops_base_unpack_info, pmix_bfrops_base_copy_info, pmix_bfrops_base_print_info, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_PDATA", PMIX_PDATA, pmix_bfrops_base_pack_pdata, pmix_bfrops_base_unpack_pdata, pmix_bfrops_base_copy_pdata, pmix_bfrops_base_print_pdata, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_BUFFER", PMIX_BUFFER, pmix_bfrops_base_pack_buf, pmix_bfrops_base_unpack_buf, pmix_bfrops_base_copy_buf, pmix_bfrops_base_print_buf, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE_OBJECT", PMIX_BYTE_OBJECT, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_KVAL", PMIX_KVAL, pmix_bfrops_base_pack_kval, pmix_bfrops_base_unpack_kval, pmix_bfrops_base_copy_kval, pmix_bfrops_base_print_kval, &pmix_mca_bfrops_v41_component.types); /* these are fixed-sized values and can be done by base */ PMIX_REGISTER_TYPE("PMIX_PERSIST", PMIX_PERSIST, pmix_bfrops_base_pack_persist, pmix_bfrops_base_unpack_persist, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_persist, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_POINTER", PMIX_POINTER, pmix_bfrops_base_pack_ptr, pmix_bfrops_base_unpack_ptr, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_SCOPE", PMIX_SCOPE, pmix_bfrops_base_pack_scope, pmix_bfrops_base_unpack_scope, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_scope, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_RANGE", PMIX_DATA_RANGE, pmix_bfrops_base_pack_range, pmix_bfrops_base_unpack_range, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_COMMAND", PMIX_COMMAND, pmix_bfrops_base_pack_cmd, pmix_bfrops_base_unpack_cmd, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_cmd, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_INFO_DIRECTIVES", PMIX_INFO_DIRECTIVES, pmix_bfrops_base_pack_info_directives, pmix_bfrops_base_unpack_info_directives, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_info_directives, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_TYPE", PMIX_DATA_TYPE, pmix_bfrops_base_pack_datatype, pmix_bfrops_base_unpack_datatype, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_datatype, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_STATE", PMIX_PROC_STATE, pmix_bfrops_base_pack_pstate, pmix_bfrops_base_unpack_pstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pstate, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_INFO", PMIX_PROC_INFO, pmix_bfrops_base_pack_pinfo, pmix_bfrops_base_unpack_pinfo, pmix_bfrops_base_copy_pinfo, pmix_bfrops_base_print_pinfo, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_ARRAY", PMIX_DATA_ARRAY, pmix_bfrops_base_pack_darray, pmix_bfrops_base_unpack_darray, pmix_bfrops_base_copy_darray, pmix_bfrops_base_print_darray, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_RANK", PMIX_PROC_RANK, pmix_bfrops_base_pack_rank, pmix_bfrops_base_unpack_rank, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_rank, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_QUERY", PMIX_QUERY, pmix_bfrops_base_pack_query, pmix_bfrops_base_unpack_query, pmix_bfrops_base_copy_query, pmix_bfrops_base_print_query, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_STRING", PMIX_COMPRESSED_STRING, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_ALLOC_DIRECTIVE", PMIX_ALLOC_DIRECTIVE, pmix_bfrops_base_pack_alloc_directive, pmix_bfrops_base_unpack_alloc_directive, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_alloc_directive, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_IOF_CHANNEL", PMIX_IOF_CHANNEL, pmix_bfrops_base_pack_iof_channel, pmix_bfrops_base_unpack_iof_channel, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_iof_channel, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_ENVAR", PMIX_ENVAR, pmix_bfrops_base_pack_envar, pmix_bfrops_base_unpack_envar, pmix_bfrops_base_copy_envar, pmix_bfrops_base_print_envar, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_COORD", PMIX_COORD, pmix_bfrops_base_pack_coord, pmix_bfrops_base_unpack_coord, pmix_bfrops_base_copy_coord, pmix_bfrops_base_print_coord, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_REGATTR", PMIX_REGATTR, pmix_bfrops_base_pack_regattr, pmix_bfrops_base_unpack_regattr, pmix_bfrops_base_copy_regattr, pmix_bfrops_base_print_regattr, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_REGEX", PMIX_REGEX, pmix_bfrops_base_pack_regex, pmix_bfrops_base_unpack_regex, pmix_bfrops_base_copy_regex, pmix_bfrops_base_print_regex, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_JOB_STATE", PMIX_JOB_STATE, pmix_bfrops_base_pack_jobstate, pmix_bfrops_base_unpack_jobstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_jobstate, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_LINK_STATE", PMIX_LINK_STATE, pmix_bfrops_base_pack_linkstate, pmix_bfrops_base_unpack_linkstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_linkstate, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_CPUSET", PMIX_PROC_CPUSET, pmix_bfrops_base_pack_cpuset, pmix_bfrops_base_unpack_cpuset, pmix_bfrops_base_copy_cpuset, pmix_bfrops_base_print_cpuset, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_GEOMETRY", PMIX_GEOMETRY, pmix_bfrops_base_pack_geometry, pmix_bfrops_base_unpack_geometry, pmix_bfrops_base_copy_geometry, pmix_bfrops_base_print_geometry, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_DEVICE_DIST", PMIX_DEVICE_DIST, pmix_bfrops_base_pack_devdist, pmix_bfrops_base_unpack_devdist, pmix_bfrops_base_copy_devdist, pmix_bfrops_base_print_devdist, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_ENDPOINT", PMIX_ENDPOINT, pmix_bfrops_base_pack_endpoint, pmix_bfrops_base_unpack_endpoint, pmix_bfrops_base_copy_endpoint, pmix_bfrops_base_print_endpoint, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_TOPO", PMIX_TOPO, pmix_bfrops_base_pack_topology, pmix_bfrops_base_unpack_topology, pmix_bfrops_base_copy_topology, pmix_bfrops_base_print_topology, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_DEVTYPE", PMIX_DEVTYPE, pmix_bfrops_base_pack_devtype, pmix_bfrops_base_unpack_devtype, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_devtype, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_LOCTYPE", PMIX_LOCTYPE, pmix_bfrops_base_pack_locality, pmix_bfrops_base_unpack_locality, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_locality, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_BYTE_OBJECT", PMIX_COMPRESSED_BYTE_OBJECT, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_NSPACE", PMIX_PROC_NSPACE, pmix_bfrops_base_pack_nspace, pmix_bfrops_base_unpack_nspace, pmix_bfrops_base_copy_nspace, pmix_bfrops_base_print_nspace, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_BUFFER", PMIX_DATA_BUFFER, pmix_bfrops_base_pack_dbuf, pmix_bfrops_base_unpack_dbuf, pmix_bfrops_base_copy_dbuf, pmix_bfrops_base_print_dbuf, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_MEDIUM", PMIX_STOR_MEDIUM, pmix_bfrops_base_pack_smed, pmix_bfrops_base_unpack_smed, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_smed, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_ACCESS", PMIX_STOR_ACCESS, pmix_bfrops_base_pack_sacc, pmix_bfrops_base_unpack_sacc, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_sacc, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_PERSIST", PMIX_STOR_PERSIST, pmix_bfrops_base_pack_spers, pmix_bfrops_base_unpack_spers, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_spers, &pmix_mca_bfrops_v41_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_ACCESS_TYPE", PMIX_STOR_ACCESS_TYPE, pmix_bfrops_base_pack_satyp, pmix_bfrops_base_unpack_satyp, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_satyp, &pmix_mca_bfrops_v41_component.types); return PMIX_SUCCESS; } static void finalize(void) { int n; pmix_bfrop_type_info_t *info; for (n = 0; n < pmix_mca_bfrops_v41_component.types.size; n++) { if (NULL != (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v41_component.types, n))) { PMIX_RELEASE(info); pmix_pointer_array_set_item(&pmix_mca_bfrops_v41_component.types, n, NULL); } } } static pmix_status_t pmix41_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_pack(&pmix_mca_bfrops_v41_component.types, buffer, src, num_vals, type); } static pmix_status_t pmix41_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_unpack(&pmix_mca_bfrops_v41_component.types, buffer, dest, num_vals, type); } static pmix_status_t pmix41_copy(void **dest, void *src, pmix_data_type_t type) { return pmix_bfrops_base_copy(&pmix_mca_bfrops_v41_component.types, dest, src, type); } static pmix_status_t pmix41_print(char **output, char *prefix, void *src, pmix_data_type_t type) { return pmix_bfrops_base_print(&pmix_mca_bfrops_v41_component.types, output, prefix, src, type); } static const char *data_type_string(pmix_data_type_t type) { return pmix_bfrops_base_data_type_string(&pmix_mca_bfrops_v41_component.types, type); } pmix-6.1.1~rc2/src/mca/bfrops/v41/bfrop_pmix41.h0000664000175000017500000000230215203536752021411 0ustar alastairalastair/* * Copyright (c) 20041-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 20041-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 20041-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 20041-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_BFROPS_PMIX41_H #define PMIX_BFROPS_PMIX41_H #include "src/mca/bfrops/bfrops.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_bfrops_base_component_t pmix_mca_bfrops_v41_component; extern pmix_bfrops_module_t pmix_bfrops_pmix41_module; END_C_DECLS #endif /* PMIX_BFROPS_PMIX41_H */ pmix-6.1.1~rc2/src/mca/bfrops/v41/Makefile.am0000664000175000017500000000345315203536752020772 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = bfrop_pmix41.h sources = \ bfrop_pmix41_component.c \ bfrop_pmix41.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_bfrops_v41_DSO lib = lib_sources = component = pmix_mca_bfrops_v41.la component_sources = $(headers) $(sources) else lib = libpmix_mca_bfrops_v41.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_bfrops_v41_la_SOURCES = $(component_sources) pmix_mca_bfrops_v41_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_bfrops_v41_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_bfrops_v41_la_SOURCES = $(lib_sources) libpmix_mca_bfrops_v41_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/bfrops/bfrops.h0000664000175000017500000004677215203536752020003 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Data packing subsystem. */ #ifndef PMIX_BFROP_H_ #define PMIX_BFROP_H_ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_types.h" #include "src/mca/mca.h" #include "bfrops_types.h" BEGIN_C_DECLS /* The overall objective of this framework is to provide seamless * cross-version support for communications by allowing a process * to communicate with a peer: * * (a) using a different version of the buffer operations. We are * allowing changes in the structure compositions and/or data * type definitions between versions. This specifically affects * our ability to pack/unpack across versions. * * (b) using a different buffer type (described vs non-described). * This resolves conflicts when one side was compiled with a * debug option, while the other side has been "optimized". * * This is a mult-select framework - i.e., multiple components * are selected and "active" at the same time. The intent is * to have one component for each data type variation, with the * expectation that the community will do its best not to revise * existing data type definitions. Thus, new variations should be * rare, and only a few components will exist. * * The framework itself reflects the fact that any given peer * will utilize only one variation of the data type definitions. * Thus, once a peer is identified, it will pass its version string * to this framework's "assign_module" function, which will then * pass it to each component until one returns a module capable of * processing the given version. This module is then "attached" to * the pmix_peer_t object so it can be used for all subsequent * communication to/from that peer. * * Buffer type is included in the buffer metadata. Unfortunately, * the metadata is not communicated at each exchange. Thus, the * peers will indicate during the connection handshake the type * of buffer they will use for all subsequent communications. The * peer must then utilize that same buffer type for all messages * sent to that remote proc, so we provide new macros for creating * and constructing buffers that ensures the correct buffer type * is marked. * * Accordingly, there are two levels of APIs defined for this * framework: * * (a) component level - these allow for init/finalize of the * component, and assignment of a module to a given peer * based on the version that peer is using * * (b) module level - implement pack/unpack/copy/recv/etc. of * the various datatypes. Note that the module only needs * to provide those functions that differ from the base * functions - they don't need to duplicate all that code! */ /* The following functions are exposed to the user - they * therefore are implemented in the bfrops/base functions * as wrappers to the real functions. * * NOTE: THESE FUNCTIONS ARE NOT TO BE USED INTERNALLY - * USE THE MACROS INSTEAD */ bool pmix_value_cmp(pmix_value_t *p, pmix_value_t *p1); /**** MODULE INTERFACE DEFINITION ****/ /* initialize the module - the module is expected * to register its datatype functions at this time */ typedef pmix_status_t (*pmix_bfrop_init_fn_t)(void); /* finalize the module */ typedef void (*pmix_bfrop_finalize_fn_t)(void); /** * Pack one or more values into a buffer. * * The pack function packs one or more values of a specified type into * the specified buffer. The buffer must have already been * initialized via an PMIX_NEW or PMIX_CONSTRUCT call - otherwise, the * pack_value function will return an error. Providing an unsupported * type flag will likewise be reported as an error. * * Note that any data to be packed that is not hard type cast (i.e., * not type cast to a specific size) may lose precision when unpacked * by a non-homogeneous recipient. The BFROP will do its best to deal * with heterogeneity issues between the packer and unpacker in such * cases. Sending a number larger than can be handled by the recipient * will return an error code (generated by the BFROP upon unpacking) - * the BFROP cannot detect such errors during packing. * * @param *buffer A pointer to the buffer into which the value is to * be packed. * * @param *src A void* pointer to the data that is to be packed. This * is interpreted as a pointer to an array of that data type containing * length num_values. Note that strings are of data type char*, and so * they are to be passed as (char **) - i.e., the caller must * pass the address of the pointer to the string as the void*. This * allows the BFROP to use a single interface function, but still allow * the caller to pass multiple strings in a single call. * * @param num_values An int32_t indicating the number of values that are * to be packed, beginning at the location pointed to by src. A string * value is counted as a single value regardless of length. The values * must be contiguous in memory. Arrays of pointers (e.g., string * arrays) should be contiguous, although (obviously) the data pointed * to need not be contiguous across array entries. * * @param type The type of the data to be packed - must be one of the * PMIX defined data types. * * @retval PMIX_SUCCESS The data was packed as requested. * * @retval PMIX_ERROR(s) An appropriate PMIX error code indicating the * problem encountered. This error code should be handled * appropriately. * * @code * pmix_buffer_t *buffer; * int32_t src; * * status_code = pmix_bfrop.pack(buffer, &src, 1, PMIX_INT32); * @endcode */ typedef pmix_status_t (*pmix_bfrop_pack_fn_t)(pmix_buffer_t *buffer, const void *src, int32_t num_values, pmix_data_type_t type); /** * Unpack values from a buffer. * * The unpack function unpacks the next value (or values) of a * specified type from the specified buffer. * * The buffer must have already been initialized via an PMIX_NEW or * PMIX_CONSTRUCT call (and assumedly filled with some data) - * otherwise, the unpack_value function will return an * error. Providing an unsupported type flag will likewise be reported * as an error, as will specifying a data type that DOES NOT match the * type of the next item in the buffer. An attempt to read beyond the * end of the stored data held in the buffer will also return an * error. * * NOTE: it is possible for the buffer to be corrupted and that * the BFROP will *think* there is a proper variable type at the * beginning of an unpack region - but that the value is bogus (e.g., just * a byte field in a string array that so happens to have a value that * matches the specified data type flag). Therefore, the data type error check * is NOT completely safe. This is true for ALL unpack functions. * * Warning: The caller is responsible for providing adequate memory * storage for the requested data. As noted below, the user * must provide a parameter indicating the maximum number of values that * can be unpacked into the allocated memory. If more values exist in the * buffer than can fit into the memory storage, then the bfrop will unpack * what it can fit into that location and return an error code indicating * that the buffer was only partially unpacked. * * Note that any data that was not hard type cast (i.e., not type cast * to a specific size) when packed may lose precision when unpacked by * a non-homogeneous recipient. The BFROP will do its best to deal with * heterogeneity issues between the packer and unpacker in such * cases. Sending a number larger than can be handled by the recipient * will return an error code generated by the BFROP upon unpacking - the * BFROP cannot detect such errors during packing. * * @param *buffer A pointer to the buffer from which the value will be * extracted. * * @param *dest A void* pointer to the memory location into which the * data is to be stored. Note that these values will be stored * contiguously in memory. For strings, this pointer must be to (char * **) to provide a means of supporting multiple string * operations. The BFROP unpack function will allocate memory for each * string in the array - the caller must only provide adequate memory * for the array of pointers. * * @param type The type of the data to be unpacked - must be one of * the BFROP defined data types. * * @retval *max_num_values The number of values actually unpacked. In * most cases, this should match the maximum number provided in the * parameters - but in no case will it exceed the value of this * parameter. Note that if you unpack fewer values than are actually * available, the buffer will be in an unpackable state - the bfrop will * return an error code to warn of this condition. * * @note The unpack function will return the actual number of values * unpacked in this location. * * @retval PMIX_SUCCESS The next item in the buffer was successfully * unpacked. * * @retval PMIX_ERROR(s) The unpack function returns an error code * under one of several conditions: (a) the number of values in the * item exceeds the max num provided by the caller; (b) the type of * the next item in the buffer does not match the type specified by * the caller; or (c) the unpack failed due to either an error in the * buffer or an attempt to read past the end of the buffer. * * @code * pmix_buffer_t *buffer; * int32_t dest; * char **string_array; * int32_t num_values; * * num_values = 1; * status_code = pmix_bfrop.unpack(buffer, (void*)&dest, &num_values, PMIX_INT32); * * num_values = 5; * string_array = malloc(num_values*sizeof(char *)); * status_code = pmix_bfrop.unpack(buffer, (void*)(string_array), &num_values, PMIX_STRING); * * @endcode */ typedef pmix_status_t (*pmix_bfrop_unpack_fn_t)(pmix_buffer_t *buffer, void *dest, int32_t *max_num_values, pmix_data_type_t type); /** * Copy a payload from one buffer to another * This function will append a copy of the payload in one buffer into * another buffer. If the destination buffer is NOT empty, then the * type of the two buffers MUST match or else an * error will be returned. If the destination buffer IS empty, then * its type will be set to that of the source buffer. * NOTE: This is NOT a destructive procedure - the * source buffer's payload will remain intact, as will any pre-existing * payload in the destination's buffer. */ typedef pmix_status_t (*pmix_bfrop_copy_payload_fn_t)(pmix_buffer_t *dest, pmix_buffer_t *src); /** * Copy a data value from one location to another. * * Since registered data types can be complex structures, the system * needs some way to know how to copy the data from one location to * another (e.g., for storage in the registry). This function, which * can call other copy functions to build up complex data types, defines * the method for making a copy of the specified data type. * * @param **dest The address of a pointer into which the * address of the resulting data is to be stored. * * @param *src A pointer to the memory location from which the * data is to be copied. * * @param type The type of the data to be copied - must be one of * the BFROP defined data types. * * @retval PMIX_SUCCESS The value was successfully copied. * * @retval PMIX_ERROR(s) An appropriate error code. * */ typedef pmix_status_t (*pmix_bfrop_copy_fn_t)(void **dest, void *src, pmix_data_type_t type); /** * Print a data value. * * Since registered data types can be complex structures, the system * needs some way to know how to print them (i.e., convert them to a string * representation). Provided for debug purposes. * * @retval PMIX_SUCCESS The value was successfully printed. * * @retval PMIX_ERROR(s) An appropriate error code. */ typedef pmix_status_t (*pmix_bfrop_print_fn_t)(char **output, char *prefix, void *src, pmix_data_type_t type); /** * Transfer a value from one pmix_value_t to another. Ordinarily, * this would be executed as a base function. However, it is * possible that future versions may add new data types, and * thus the xfer function may differ * * @retval PMIX_SUCCESS The value was successfully transferred * * @retval PMIX_ERROR(s) An appropriate error code */ typedef pmix_status_t (*pmix_bfrop_value_xfer_fn_t)(pmix_value_t *dest, const pmix_value_t *src); /** * Load data into a pmix_value_t object. Again, this is provided * as a component function to support different data types */ typedef void (*pmix_bfrop_value_load_fn_t)(pmix_value_t *v, const void *data, pmix_data_type_t type); /** * Unload data from a pmix_value_t object * * @retval PMIX_SUCCESS The value was successfully unloaded * * @retval PMIX_ERROR(s) An appropriate error code */ typedef pmix_status_t (*pmix_bfrop_value_unload_fn_t)(pmix_value_t *kv, void **data, size_t *sz); /** * Compare two pmix_value_t structs */ typedef pmix_value_cmp_t (*pmix_bfrop_value_cmp_fn_t)(pmix_value_t *p1, pmix_value_t *p2); /* return the string name of a provided data type */ typedef const char *(*pmix_bfrop_data_type_string_fn_t)(pmix_data_type_t type); /** * Base structure for a BFROP module */ typedef struct { char *version; pmix_bfrop_init_fn_t init; pmix_bfrop_finalize_fn_t finalize; pmix_bfrop_pack_fn_t pack; pmix_bfrop_unpack_fn_t unpack; pmix_bfrop_copy_fn_t copy; pmix_bfrop_print_fn_t print; pmix_bfrop_copy_payload_fn_t copy_payload; pmix_bfrop_value_xfer_fn_t value_xfer; pmix_bfrop_value_load_fn_t value_load; pmix_bfrop_value_unload_fn_t value_unload; pmix_bfrop_value_cmp_fn_t value_cmp; pmix_bfrop_data_type_string_fn_t data_type_string; } pmix_bfrops_module_t; /* get a list of available versions - caller must free results * when done */ PMIX_EXPORT char *pmix_bfrops_base_get_available_modules(void); /* Select a bfrops module for a given version */ PMIX_EXPORT pmix_bfrops_module_t *pmix_bfrops_base_assign_module(const char *version); /* provide a backdoor to access the framework debug output */ PMIX_EXPORT extern int pmix_bfrops_base_output; /* MACROS FOR EXECUTING BFROPS FUNCTIONS */ #define PMIX_BFROPS_ASSIGN_TYPE(p, b) (b)->type = (p)->nptr->compat.type #define PMIX_BFROPS_PACK(r, p, b, s, n, t) \ do { \ pmix_output_verbose(2, pmix_bfrops_base_output, "[%s:%d] PACK version %s type %s", \ __FILE__, __LINE__, (p)->nptr->compat.bfrops->version, \ PMIx_Data_type_string(t)); \ if (PMIX_BFROP_BUFFER_UNDEF == (b)->type) { \ (b)->type = (p)->nptr->compat.type; \ (r) = (p)->nptr->compat.bfrops->pack(b, s, n, t); \ } else if ((b)->type == (p)->nptr->compat.type) { \ (r) = (p)->nptr->compat.bfrops->pack(b, s, n, t); \ } else { \ (r) = PMIX_ERR_PACK_MISMATCH; \ } \ } while (0) #define PMIX_BFROPS_UNPACK(r, p, b, d, m, t) \ do { \ pmix_output_verbose(2, pmix_bfrops_base_output, "[%s:%d] UNPACK version %s type %s", \ __FILE__, __LINE__, (p)->nptr->compat.bfrops->version, \ PMIx_Data_type_string(t)); \ if ((b)->type == (p)->nptr->compat.type) { \ (r) = (p)->nptr->compat.bfrops->unpack(b, d, m, t); \ } else { \ (r) = PMIX_ERR_UNPACK_FAILURE; \ } \ } while (0) #define PMIX_BFROPS_COPY(r, p, d, s, t) (r) = (p)->nptr->compat.bfrops->copy(d, s, t) #define PMIX_BFROPS_PRINT(r, p, o, pr, s, t) (r) = (p)->nptr->compat.bfrops->print(o, pr, s, t) #define PMIX_BFROPS_COPY_PAYLOAD(r, p, d, s) \ do { \ if (PMIX_BFROP_BUFFER_UNDEF == (d)->type) { \ (d)->type = (p)->nptr->compat.type; \ (r) = (p)->nptr->compat.bfrops->copy_payload(d, s); \ } else if ((d)->type == (p)->nptr->compat.type) { \ (r) = (p)->nptr->compat.bfrops->copy_payload(d, s); \ } else { \ (r) = PMIX_ERR_PACK_MISMATCH; \ } \ } while (0) #define PMIX_BFROPS_VALUE_XFER(r, p, d, s) (r) = (p)->nptr->compat.bfrops->value_xfer(d, s) #define PMIX_BFROPS_VALUE_LOAD(p, v, d, t) (p)->nptr->compat.bfrops->value_load(v, d, t) #define PMIX_BFROPS_VALUE_UNLOAD(r, p, k, d, s) \ (r) = (p)->nptr->compat.bfrops->value_unload(k, , d, s) #define PMIX_BFROPS_VALUE_CMP(r, p, q, s) (r) = (p)->nptr->compat.bfrops->value_cmp(q, s) #define PMIX_BFROPS_REGISTER(r, p, n, t, pk, u, c, pr) \ (r) = (p)->nptr->compat.bfrops->register_type(n, t, pk, u, c, pr) #define PMIX_BFROPS_PRINT_TYPE(c, p, t) (c) = (p)->nptr->compat.bfrops->data_type_string(t) /**** COMPONENT STRUCTURE DEFINITION ****/ /* define a component-level API for getting a module */ typedef pmix_bfrops_module_t *(*pmix_bfrop_base_component_assign_module_fn_t)(void); /* * the standard component data structure */ struct pmix_bfrops_base_component_t { pmix_mca_base_component_t base; int priority; pmix_pointer_array_t types; pmix_bfrop_base_component_assign_module_fn_t assign_module; }; typedef struct pmix_bfrops_base_component_t pmix_bfrops_base_component_t; /* * Macro for use in components that are of type bfrops */ #define PMIX_BFROPS_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("bfrops", 1, 0, 0) END_C_DECLS #endif /* PMIX_BFROP_H */ pmix-6.1.1~rc2/src/mca/bfrops/v61/0000775000175000017500000000000015203536752016733 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/bfrops/v61/bfrop_pmix61.c0000664000175000017500000005275315203536752021427 0ustar alastairalastair/* * Copyright (c) 2005-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2005-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "bfrop_pmix61.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_error.h" static pmix_status_t init(void); static void finalize(void); static pmix_status_t pmix61_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type); static pmix_status_t pmix61_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix61_copy(void **dest, void *src, pmix_data_type_t type); static pmix_status_t pmix61_print(char **output, char *prefix, void *src, pmix_data_type_t type); static const char *data_type_string(pmix_data_type_t type); pmix_bfrops_module_t pmix_bfrops_pmix61_module = { .version = "v61", .init = init, .finalize = finalize, .pack = pmix61_pack, .unpack = pmix61_unpack, .copy = pmix61_copy, .print = pmix61_print, .copy_payload = pmix_bfrops_base_copy_payload, .value_xfer = pmix_bfrops_base_value_xfer, .value_load = pmix_bfrops_base_value_load, .value_unload = pmix_bfrops_base_value_unload, .value_cmp = pmix_bfrops_base_value_cmp, .data_type_string = data_type_string }; static pmix_status_t init(void) { /* some standard types don't require anything special */ PMIX_REGISTER_TYPE("PMIX_BOOL", PMIX_BOOL, pmix_bfrops_base_pack_bool, pmix_bfrops_base_unpack_bool, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_bool, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE", PMIX_BYTE, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_byte, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_STRING", PMIX_STRING, pmix_bfrops_base_pack_string, pmix_bfrops_base_unpack_string, pmix_bfrops_base_copy_string, pmix_bfrops_base_print_string, &pmix_mca_bfrops_v61_component.types); /* Register the rest of the standard generic types to point to internal functions */ PMIX_REGISTER_TYPE("PMIX_SIZE", PMIX_SIZE, pmix_bfrops_base_pack_sizet, pmix_bfrops_base_unpack_sizet, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_size, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_PID", PMIX_PID, pmix_bfrops_base_pack_pid, pmix_bfrops_base_unpack_pid, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pid, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_INT", PMIX_INT, pmix_bfrops_base_pack_int, pmix_bfrops_base_unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int, &pmix_mca_bfrops_v61_component.types); /* Register all the standard fixed types to point to base functions */ PMIX_REGISTER_TYPE("PMIX_INT8", PMIX_INT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int8, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_INT16", PMIX_INT16, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int16, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_INT32", PMIX_INT32, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int32, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_INT64", PMIX_INT64, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int64, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_UINT", PMIX_UINT, pmix_bfrops_base_pack_int, pmix_bfrops_base_unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_UINT8", PMIX_UINT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint8, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_UINT16", PMIX_UINT16, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint16, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_UINT32", PMIX_UINT32, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint32, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_UINT64", PMIX_UINT64, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint64, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_FLOAT", PMIX_FLOAT, pmix_bfrops_base_pack_float, pmix_bfrops_base_unpack_float, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_float, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_DOUBLE", PMIX_DOUBLE, pmix_bfrops_base_pack_double, pmix_bfrops_base_unpack_double, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_double, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_TIMEVAL", PMIX_TIMEVAL, pmix_bfrops_base_pack_timeval, pmix_bfrops_base_unpack_timeval, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_timeval, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_TIME", PMIX_TIME, pmix_bfrops_base_pack_time, pmix_bfrops_base_unpack_time, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_time, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_STATUS", PMIX_STATUS, pmix_bfrops_base_pack_status, pmix_bfrops_base_unpack_status, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_status, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_VALUE", PMIX_VALUE, pmix_bfrops_base_pack_value, pmix_bfrops_base_unpack_value, pmix_bfrops_base_copy_value, pmix_bfrops_base_print_value, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_PROC", PMIX_PROC, pmix_bfrops_base_pack_proc, pmix_bfrops_base_unpack_proc, pmix_bfrops_base_copy_proc, pmix_bfrops_base_print_proc, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_APP", PMIX_APP, pmix_bfrops_base_pack_app, pmix_bfrops_base_unpack_app, pmix_bfrops_base_copy_app, pmix_bfrops_base_print_app, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_INFO", PMIX_INFO, pmix_bfrops_base_pack_info, pmix_bfrops_base_unpack_info, pmix_bfrops_base_copy_info, pmix_bfrops_base_print_info, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_PDATA", PMIX_PDATA, pmix_bfrops_base_pack_pdata, pmix_bfrops_base_unpack_pdata, pmix_bfrops_base_copy_pdata, pmix_bfrops_base_print_pdata, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_BUFFER", PMIX_BUFFER, pmix_bfrops_base_pack_buf, pmix_bfrops_base_unpack_buf, pmix_bfrops_base_copy_buf, pmix_bfrops_base_print_buf, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE_OBJECT", PMIX_BYTE_OBJECT, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_KVAL", PMIX_KVAL, pmix_bfrops_base_pack_kval, pmix_bfrops_base_unpack_kval, pmix_bfrops_base_copy_kval, pmix_bfrops_base_print_kval, &pmix_mca_bfrops_v61_component.types); /* these are fixed-sized values and can be done by base */ PMIX_REGISTER_TYPE("PMIX_PERSIST", PMIX_PERSIST, pmix_bfrops_base_pack_persist, pmix_bfrops_base_unpack_persist, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_persist, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_POINTER", PMIX_POINTER, pmix_bfrops_base_pack_ptr, pmix_bfrops_base_unpack_ptr, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_SCOPE", PMIX_SCOPE, pmix_bfrops_base_pack_scope, pmix_bfrops_base_unpack_scope, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_scope, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_RANGE", PMIX_DATA_RANGE, pmix_bfrops_base_pack_range, pmix_bfrops_base_unpack_range, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_COMMAND", PMIX_COMMAND, pmix_bfrops_base_pack_cmd, pmix_bfrops_base_unpack_cmd, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_cmd, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_INFO_DIRECTIVES", PMIX_INFO_DIRECTIVES, pmix_bfrops_base_pack_info_directives, pmix_bfrops_base_unpack_info_directives, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_info_directives, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_TYPE", PMIX_DATA_TYPE, pmix_bfrops_base_pack_datatype, pmix_bfrops_base_unpack_datatype, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_datatype, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_STATE", PMIX_PROC_STATE, pmix_bfrops_base_pack_pstate, pmix_bfrops_base_unpack_pstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pstate, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_INFO", PMIX_PROC_INFO, pmix_bfrops_base_pack_pinfo, pmix_bfrops_base_unpack_pinfo, pmix_bfrops_base_copy_pinfo, pmix_bfrops_base_print_pinfo, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_ARRAY", PMIX_DATA_ARRAY, pmix_bfrops_base_pack_darray, pmix_bfrops_base_unpack_darray, pmix_bfrops_base_copy_darray, pmix_bfrops_base_print_darray, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_RANK", PMIX_PROC_RANK, pmix_bfrops_base_pack_rank, pmix_bfrops_base_unpack_rank, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_rank, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_QUERY", PMIX_QUERY, pmix_bfrops_base_pack_query, pmix_bfrops_base_unpack_query, pmix_bfrops_base_copy_query, pmix_bfrops_base_print_query, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_STRING", PMIX_COMPRESSED_STRING, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_ALLOC_DIRECTIVE", PMIX_ALLOC_DIRECTIVE, pmix_bfrops_base_pack_alloc_directive, pmix_bfrops_base_unpack_alloc_directive, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_alloc_directive, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_RESBLOCK_DIRECTIVE", PMIX_RESBLOCK_DIRECTIVE, pmix_bfrops_base_pack_resblock_directive, pmix_bfrops_base_unpack_resblock_directive, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_resblock_directive, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_IOF_CHANNEL", PMIX_IOF_CHANNEL, pmix_bfrops_base_pack_iof_channel, pmix_bfrops_base_unpack_iof_channel, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_iof_channel, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_ENVAR", PMIX_ENVAR, pmix_bfrops_base_pack_envar, pmix_bfrops_base_unpack_envar, pmix_bfrops_base_copy_envar, pmix_bfrops_base_print_envar, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_COORD", PMIX_COORD, pmix_bfrops_base_pack_coord, pmix_bfrops_base_unpack_coord, pmix_bfrops_base_copy_coord, pmix_bfrops_base_print_coord, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_REGATTR", PMIX_REGATTR, pmix_bfrops_base_pack_regattr, pmix_bfrops_base_unpack_regattr, pmix_bfrops_base_copy_regattr, pmix_bfrops_base_print_regattr, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_REGEX", PMIX_REGEX, pmix_bfrops_base_pack_regex, pmix_bfrops_base_unpack_regex, pmix_bfrops_base_copy_regex, pmix_bfrops_base_print_regex, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_JOB_STATE", PMIX_JOB_STATE, pmix_bfrops_base_pack_jobstate, pmix_bfrops_base_unpack_jobstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_jobstate, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_LINK_STATE", PMIX_LINK_STATE, pmix_bfrops_base_pack_linkstate, pmix_bfrops_base_unpack_linkstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_linkstate, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_CPUSET", PMIX_PROC_CPUSET, pmix_bfrops_base_pack_cpuset, pmix_bfrops_base_unpack_cpuset, pmix_bfrops_base_copy_cpuset, pmix_bfrops_base_print_cpuset, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_GEOMETRY", PMIX_GEOMETRY, pmix_bfrops_base_pack_geometry, pmix_bfrops_base_unpack_geometry, pmix_bfrops_base_copy_geometry, pmix_bfrops_base_print_geometry, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_DEVICE", PMIX_DEVICE, pmix_bfrops_base_pack_device, pmix_bfrops_base_unpack_device, pmix_bfrops_base_copy_device, pmix_bfrops_base_print_device, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_RESOURCE_UNIT", PMIX_RESOURCE_UNIT, pmix_bfrops_base_pack_resunit, pmix_bfrops_base_unpack_resunit, pmix_bfrops_base_copy_resunit, pmix_bfrops_base_print_resunit, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_DEVICE_DIST", PMIX_DEVICE_DIST, pmix_bfrops_base_pack_devdist, pmix_bfrops_base_unpack_devdist, pmix_bfrops_base_copy_devdist, pmix_bfrops_base_print_devdist, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_ENDPOINT", PMIX_ENDPOINT, pmix_bfrops_base_pack_endpoint, pmix_bfrops_base_unpack_endpoint, pmix_bfrops_base_copy_endpoint, pmix_bfrops_base_print_endpoint, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_TOPO", PMIX_TOPO, pmix_bfrops_base_pack_topology, pmix_bfrops_base_unpack_topology, pmix_bfrops_base_copy_topology, pmix_bfrops_base_print_topology, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_DEVTYPE", PMIX_DEVTYPE, pmix_bfrops_base_pack_devtype, pmix_bfrops_base_unpack_devtype, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_devtype, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_LOCTYPE", PMIX_LOCTYPE, pmix_bfrops_base_pack_locality, pmix_bfrops_base_unpack_locality, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_locality, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_BYTE_OBJECT", PMIX_COMPRESSED_BYTE_OBJECT, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_NSPACE", PMIX_PROC_NSPACE, pmix_bfrops_base_pack_nspace, pmix_bfrops_base_unpack_nspace, pmix_bfrops_base_copy_nspace, pmix_bfrops_base_print_nspace, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_BUFFER", PMIX_DATA_BUFFER, pmix_bfrops_base_pack_dbuf, pmix_bfrops_base_unpack_dbuf, pmix_bfrops_base_copy_dbuf, pmix_bfrops_base_print_dbuf, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_MEDIUM", PMIX_STOR_MEDIUM, pmix_bfrops_base_pack_smed, pmix_bfrops_base_unpack_smed, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_smed, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_ACCESS", PMIX_STOR_ACCESS, pmix_bfrops_base_pack_sacc, pmix_bfrops_base_unpack_sacc, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_sacc, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_PERSIST", PMIX_STOR_PERSIST, pmix_bfrops_base_pack_spers, pmix_bfrops_base_unpack_spers, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_spers, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_ACCESS_TYPE", PMIX_STOR_ACCESS_TYPE, pmix_bfrops_base_pack_satyp, pmix_bfrops_base_unpack_satyp, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_satyp, &pmix_mca_bfrops_v61_component.types); PMIX_REGISTER_TYPE("PMIX_NODE_PID", PMIX_NODE_PID, pmix_bfrops_base_pack_nodepid, pmix_bfrops_base_unpack_nodepid, pmix_bfrops_base_copy_nodepid, pmix_bfrops_base_print_nodepid, &pmix_mca_bfrops_v61_component.types); return PMIX_SUCCESS; } static void finalize(void) { int n; pmix_bfrop_type_info_t *info; for (n = 0; n < pmix_mca_bfrops_v61_component.types.size; n++) { if (NULL != (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v61_component.types, n))) { PMIX_RELEASE(info); pmix_pointer_array_set_item(&pmix_mca_bfrops_v61_component.types, n, NULL); } } } static pmix_status_t pmix61_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_pack(&pmix_mca_bfrops_v61_component.types, buffer, src, num_vals, type); } static pmix_status_t pmix61_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_unpack(&pmix_mca_bfrops_v61_component.types, buffer, dest, num_vals, type); } static pmix_status_t pmix61_copy(void **dest, void *src, pmix_data_type_t type) { return pmix_bfrops_base_copy(&pmix_mca_bfrops_v61_component.types, dest, src, type); } static pmix_status_t pmix61_print(char **output, char *prefix, void *src, pmix_data_type_t type) { return pmix_bfrops_base_print(&pmix_mca_bfrops_v61_component.types, output, prefix, src, type); } static const char *data_type_string(pmix_data_type_t type) { return pmix_bfrops_base_data_type_string(&pmix_mca_bfrops_v61_component.types, type); } pmix-6.1.1~rc2/src/mca/bfrops/v61/Makefile.am0000664000175000017500000000345215203536752020773 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = bfrop_pmix61.h sources = \ bfrop_pmix61_component.c \ bfrop_pmix61.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_bfrops_v61_DSO lib = lib_sources = component = pmix_mca_bfrops_v61.la component_sources = $(headers) $(sources) else lib = libpmix_mca_bfrops_v61.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_bfrops_v61_la_SOURCES = $(component_sources) pmix_mca_bfrops_v61_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_bfrops_v61_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_bfrops_v61_la_SOURCES = $(lib_sources) libpmix_mca_bfrops_v61_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/bfrops/v61/bfrop_pmix61.h0000664000175000017500000000227515203536752021426 0ustar alastairalastair/* * Copyright (c) 2005-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2005-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_BFROPS_PMIX61_H #define PMIX_BFROPS_PMIX61_H #include "src/mca/bfrops/bfrops.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_bfrops_base_component_t pmix_mca_bfrops_v61_component; extern pmix_bfrops_module_t pmix_bfrops_pmix61_module; END_C_DECLS #endif /* PMIX_BFROPS_PMIX61_H */ pmix-6.1.1~rc2/src/mca/bfrops/v61/bfrop_pmix61_component.c0000664000175000017500000000674215203536752023506 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennbfropsee and The University * of Tennbfropsee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include "bfrop_pmix61.h" #include "src/mca/bfrops/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_error.h" extern pmix_bfrops_module_t pmix_bfrops_pmix61_module; static pmix_status_t component_open(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_close(void); static pmix_bfrops_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_bfrops_base_component_t pmix_mca_bfrops_v61_component = { .base = { PMIX_BFROPS_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "v61", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .priority = 70, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, bfrops, v61) pmix_status_t component_open(void) { /* setup the types array */ PMIX_CONSTRUCT(&pmix_mca_bfrops_v61_component.types, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_mca_bfrops_v61_component.types, 50, INT_MAX, 16); return PMIX_SUCCESS; } pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = pmix_mca_bfrops_v61_component.priority; *module = (pmix_mca_base_module_t *) &pmix_bfrops_pmix61_module; return PMIX_SUCCESS; } pmix_status_t component_close(void) { PMIX_DESTRUCT(&pmix_mca_bfrops_v61_component.types); return PMIX_SUCCESS; } static pmix_bfrops_module_t *assign_module(void) { pmix_output_verbose(10, pmix_bfrops_base_framework.framework_output, "bfrops:pmix61 assigning module"); return &pmix_bfrops_pmix61_module; } pmix-6.1.1~rc2/src/mca/bfrops/v4/0000775000175000017500000000000015203536752016650 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/bfrops/v4/bfrop_pmix4_component.c0000664000175000017500000000672615203536752023342 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennbfropsee and The University * of Tennbfropsee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include "bfrop_pmix4.h" #include "src/mca/bfrops/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_error.h" extern pmix_bfrops_module_t pmix_bfrops_pmix4_module; static pmix_status_t component_open(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_close(void); static pmix_bfrops_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_bfrops_base_component_t pmix_mca_bfrops_v4_component = { .base = { PMIX_BFROPS_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "v4", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .priority = 50, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, bfrops, v4) pmix_status_t component_open(void) { /* setup the types array */ PMIX_CONSTRUCT(&pmix_mca_bfrops_v4_component.types, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_mca_bfrops_v4_component.types, 42, INT_MAX, 16); return PMIX_SUCCESS; } pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = pmix_mca_bfrops_v4_component.priority; *module = (pmix_mca_base_module_t *) &pmix_bfrops_pmix4_module; return PMIX_SUCCESS; } pmix_status_t component_close(void) { PMIX_DESTRUCT(&pmix_mca_bfrops_v4_component.types); return PMIX_SUCCESS; } static pmix_bfrops_module_t *assign_module(void) { pmix_output_verbose(10, pmix_bfrops_base_framework.framework_output, "bfrops:pmix4 assigning module"); return &pmix_bfrops_pmix4_module; } pmix-6.1.1~rc2/src/mca/bfrops/v4/bfrop_pmix4.h0000664000175000017500000000227115203536752021254 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_BFROPS_PMIX4_H #define PMIX_BFROPS_PMIX4_H #include "src/mca/bfrops/bfrops.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_bfrops_base_component_t pmix_mca_bfrops_v4_component; extern pmix_bfrops_module_t pmix_bfrops_pmix4_module; END_C_DECLS #endif /* PMIX_BFROPS_PMIX4_H */ pmix-6.1.1~rc2/src/mca/bfrops/v4/bfrop_pmix4.c0000664000175000017500000004534415203536752021257 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2014 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 IBM Corporation. All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "bfrop_pmix4.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_error.h" static pmix_status_t init(void); static void finalize(void); static pmix_status_t pmix4_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type); static pmix_status_t pmix4_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix4_copy(void **dest, void *src, pmix_data_type_t type); static pmix_status_t pmix4_print(char **output, char *prefix, void *src, pmix_data_type_t type); static const char *data_type_string(pmix_data_type_t type); pmix_bfrops_module_t pmix_bfrops_pmix4_module = { .version = "v4", .init = init, .finalize = finalize, .pack = pmix4_pack, .unpack = pmix4_unpack, .copy = pmix4_copy, .print = pmix4_print, .copy_payload = pmix_bfrops_base_copy_payload, .value_xfer = pmix_bfrops_base_value_xfer, .value_load = pmix_bfrops_base_value_load, .value_unload = pmix_bfrops_base_value_unload, .value_cmp = pmix_bfrops_base_value_cmp, .data_type_string = data_type_string }; static pmix_status_t init(void) { /* some standard types don't require anything special */ PMIX_REGISTER_TYPE("PMIX_BOOL", PMIX_BOOL, pmix_bfrops_base_pack_bool, pmix_bfrops_base_unpack_bool, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_bool, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE", PMIX_BYTE, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_byte, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_STRING", PMIX_STRING, pmix_bfrops_base_pack_string, pmix_bfrops_base_unpack_string, pmix_bfrops_base_copy_string, pmix_bfrops_base_print_string, &pmix_mca_bfrops_v4_component.types); /* Register the rest of the standard generic types to point to internal functions */ PMIX_REGISTER_TYPE("PMIX_SIZE", PMIX_SIZE, pmix_bfrops_base_pack_sizet, pmix_bfrops_base_unpack_sizet, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_size, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_PID", PMIX_PID, pmix_bfrops_base_pack_pid, pmix_bfrops_base_unpack_pid, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pid, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_INT", PMIX_INT, pmix_bfrops_base_pack_int, pmix_bfrops_base_unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int, &pmix_mca_bfrops_v4_component.types); /* Register all the standard fixed types to point to base functions */ PMIX_REGISTER_TYPE("PMIX_INT8", PMIX_INT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int8, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_INT16", PMIX_INT16, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int16, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_INT32", PMIX_INT32, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int32, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_INT64", PMIX_INT64, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int64, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_UINT", PMIX_UINT, pmix_bfrops_base_pack_int, pmix_bfrops_base_unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_UINT8", PMIX_UINT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint8, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_UINT16", PMIX_UINT16, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint16, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_UINT32", PMIX_UINT32, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint32, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_UINT64", PMIX_UINT64, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint64, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_FLOAT", PMIX_FLOAT, pmix_bfrops_base_pack_float, pmix_bfrops_base_unpack_float, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_float, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_DOUBLE", PMIX_DOUBLE, pmix_bfrops_base_pack_double, pmix_bfrops_base_unpack_double, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_double, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_TIMEVAL", PMIX_TIMEVAL, pmix_bfrops_base_pack_timeval, pmix_bfrops_base_unpack_timeval, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_timeval, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_TIME", PMIX_TIME, pmix_bfrops_base_pack_time, pmix_bfrops_base_unpack_time, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_time, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_STATUS", PMIX_STATUS, pmix_bfrops_base_pack_status, pmix_bfrops_base_unpack_status, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_status, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_VALUE", PMIX_VALUE, pmix_bfrops_base_pack_value, pmix_bfrops_base_unpack_value, pmix_bfrops_base_copy_value, pmix_bfrops_base_print_value, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_PROC", PMIX_PROC, pmix_bfrops_base_pack_proc, pmix_bfrops_base_unpack_proc, pmix_bfrops_base_copy_proc, pmix_bfrops_base_print_proc, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_APP", PMIX_APP, pmix_bfrops_base_pack_app, pmix_bfrops_base_unpack_app, pmix_bfrops_base_copy_app, pmix_bfrops_base_print_app, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_INFO", PMIX_INFO, pmix_bfrops_base_pack_info, pmix_bfrops_base_unpack_info, pmix_bfrops_base_copy_info, pmix_bfrops_base_print_info, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_PDATA", PMIX_PDATA, pmix_bfrops_base_pack_pdata, pmix_bfrops_base_unpack_pdata, pmix_bfrops_base_copy_pdata, pmix_bfrops_base_print_pdata, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_BUFFER", PMIX_BUFFER, pmix_bfrops_base_pack_buf, pmix_bfrops_base_unpack_buf, pmix_bfrops_base_copy_buf, pmix_bfrops_base_print_buf, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE_OBJECT", PMIX_BYTE_OBJECT, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_KVAL", PMIX_KVAL, pmix_bfrops_base_pack_kval, pmix_bfrops_base_unpack_kval, pmix_bfrops_base_copy_kval, pmix_bfrops_base_print_kval, &pmix_mca_bfrops_v4_component.types); /* these are fixed-sized values and can be done by base */ PMIX_REGISTER_TYPE("PMIX_PERSIST", PMIX_PERSIST, pmix_bfrops_base_pack_persist, pmix_bfrops_base_unpack_persist, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_persist, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_POINTER", PMIX_POINTER, pmix_bfrops_base_pack_ptr, pmix_bfrops_base_unpack_ptr, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_SCOPE", PMIX_SCOPE, pmix_bfrops_base_pack_scope, pmix_bfrops_base_unpack_scope, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_scope, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_RANGE", PMIX_DATA_RANGE, pmix_bfrops_base_pack_range, pmix_bfrops_base_unpack_range, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_COMMAND", PMIX_COMMAND, pmix_bfrops_base_pack_cmd, pmix_bfrops_base_unpack_cmd, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_cmd, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_INFO_DIRECTIVES", PMIX_INFO_DIRECTIVES, pmix_bfrops_base_pack_info_directives, pmix_bfrops_base_unpack_info_directives, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_info_directives, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_TYPE", PMIX_DATA_TYPE, pmix_bfrops_base_pack_datatype, pmix_bfrops_base_unpack_datatype, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_datatype, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_STATE", PMIX_PROC_STATE, pmix_bfrops_base_pack_pstate, pmix_bfrops_base_unpack_pstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pstate, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_INFO", PMIX_PROC_INFO, pmix_bfrops_base_pack_pinfo, pmix_bfrops_base_unpack_pinfo, pmix_bfrops_base_copy_pinfo, pmix_bfrops_base_print_pinfo, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_ARRAY", PMIX_DATA_ARRAY, pmix_bfrops_base_pack_darray, pmix_bfrops_base_unpack_darray, pmix_bfrops_base_copy_darray, pmix_bfrops_base_print_darray, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_RANK", PMIX_PROC_RANK, pmix_bfrops_base_pack_rank, pmix_bfrops_base_unpack_rank, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_rank, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_QUERY", PMIX_QUERY, pmix_bfrops_base_pack_query, pmix_bfrops_base_unpack_query, pmix_bfrops_base_copy_query, pmix_bfrops_base_print_query, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_STRING", PMIX_COMPRESSED_STRING, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_ALLOC_DIRECTIVE", PMIX_ALLOC_DIRECTIVE, pmix_bfrops_base_pack_alloc_directive, pmix_bfrops_base_unpack_alloc_directive, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_alloc_directive, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_IOF_CHANNEL", PMIX_IOF_CHANNEL, pmix_bfrops_base_pack_iof_channel, pmix_bfrops_base_unpack_iof_channel, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_iof_channel, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_ENVAR", PMIX_ENVAR, pmix_bfrops_base_pack_envar, pmix_bfrops_base_unpack_envar, pmix_bfrops_base_copy_envar, pmix_bfrops_base_print_envar, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_COORD", PMIX_COORD, pmix_bfrops_base_pack_coord, pmix_bfrops_base_unpack_coord, pmix_bfrops_base_copy_coord, pmix_bfrops_base_print_coord, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_REGATTR", PMIX_REGATTR, pmix_bfrops_base_pack_regattr, pmix_bfrops_base_unpack_regattr, pmix_bfrops_base_copy_regattr, pmix_bfrops_base_print_regattr, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_REGEX", PMIX_REGEX, pmix_bfrops_base_pack_regex, pmix_bfrops_base_unpack_regex, pmix_bfrops_base_copy_regex, pmix_bfrops_base_print_regex, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_JOB_STATE", PMIX_JOB_STATE, pmix_bfrops_base_pack_jobstate, pmix_bfrops_base_unpack_jobstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_jobstate, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_LINK_STATE", PMIX_LINK_STATE, pmix_bfrops_base_pack_linkstate, pmix_bfrops_base_unpack_linkstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_linkstate, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_CPUSET", PMIX_PROC_CPUSET, pmix_bfrops_base_pack_cpuset, pmix_bfrops_base_unpack_cpuset, pmix_bfrops_base_copy_cpuset, pmix_bfrops_base_print_cpuset, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_GEOMETRY", PMIX_GEOMETRY, pmix_bfrops_base_pack_geometry, pmix_bfrops_base_unpack_geometry, pmix_bfrops_base_copy_geometry, pmix_bfrops_base_print_geometry, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_DEVICE_DIST", PMIX_DEVICE_DIST, pmix_bfrops_base_pack_devdist, pmix_bfrops_base_unpack_devdist, pmix_bfrops_base_copy_devdist, pmix_bfrops_base_print_devdist, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_ENDPOINT", PMIX_ENDPOINT, pmix_bfrops_base_pack_endpoint, pmix_bfrops_base_unpack_endpoint, pmix_bfrops_base_copy_endpoint, pmix_bfrops_base_print_endpoint, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_TOPO", PMIX_TOPO, pmix_bfrops_base_pack_topology, pmix_bfrops_base_unpack_topology, pmix_bfrops_base_copy_topology, pmix_bfrops_base_print_topology, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_DEVTYPE", PMIX_DEVTYPE, pmix_bfrops_base_pack_devtype, pmix_bfrops_base_unpack_devtype, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_devtype, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_LOCTYPE", PMIX_LOCTYPE, pmix_bfrops_base_pack_locality, pmix_bfrops_base_unpack_locality, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_locality, &pmix_mca_bfrops_v4_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_BYTE_OBJECT", PMIX_COMPRESSED_BYTE_OBJECT, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v4_component.types); return PMIX_SUCCESS; } static void finalize(void) { int n; pmix_bfrop_type_info_t *info; for (n = 0; n < pmix_mca_bfrops_v4_component.types.size; n++) { if (NULL != (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v4_component.types, n))) { PMIX_RELEASE(info); pmix_pointer_array_set_item(&pmix_mca_bfrops_v4_component.types, n, NULL); } } } static pmix_status_t pmix4_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_pack(&pmix_mca_bfrops_v4_component.types, buffer, src, num_vals, type); } static pmix_status_t pmix4_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_unpack(&pmix_mca_bfrops_v4_component.types, buffer, dest, num_vals, type); } static pmix_status_t pmix4_copy(void **dest, void *src, pmix_data_type_t type) { return pmix_bfrops_base_copy(&pmix_mca_bfrops_v4_component.types, dest, src, type); } static pmix_status_t pmix4_print(char **output, char *prefix, void *src, pmix_data_type_t type) { return pmix_bfrops_base_print(&pmix_mca_bfrops_v4_component.types, output, prefix, src, type); } static const char *data_type_string(pmix_data_type_t type) { return pmix_bfrops_base_data_type_string(&pmix_mca_bfrops_v4_component.types, type); } pmix-6.1.1~rc2/src/mca/bfrops/v4/Makefile.am0000664000175000017500000000344015203536752020705 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = bfrop_pmix4.h sources = \ bfrop_pmix4_component.c \ bfrop_pmix4.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_bfrops_v4_DSO lib = lib_sources = component = pmix_mca_bfrops_v4.la component_sources = $(headers) $(sources) else lib = libpmix_mca_bfrops_v4.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_bfrops_v4_la_SOURCES = $(component_sources) pmix_mca_bfrops_v4_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_bfrops_v4_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_bfrops_v4_la_SOURCES = $(lib_sources) libpmix_mca_bfrops_v4_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/bfrops/v51/0000775000175000017500000000000015203536752016732 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/bfrops/v51/bfrop_pmix51.h0000664000175000017500000000227515203536752021424 0ustar alastairalastair/* * Copyright (c) 2005-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2005-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_BFROPS_PMIX51_H #define PMIX_BFROPS_PMIX51_H #include "src/mca/bfrops/bfrops.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_bfrops_base_component_t pmix_mca_bfrops_v51_component; extern pmix_bfrops_module_t pmix_bfrops_pmix51_module; END_C_DECLS #endif /* PMIX_BFROPS_PMIX51_H */ pmix-6.1.1~rc2/src/mca/bfrops/v51/bfrop_pmix51_component.c0000664000175000017500000000674215203536752023504 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennbfropsee and The University * of Tennbfropsee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include "bfrop_pmix51.h" #include "src/mca/bfrops/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_error.h" extern pmix_bfrops_module_t pmix_bfrops_pmix51_module; static pmix_status_t component_open(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_close(void); static pmix_bfrops_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_bfrops_base_component_t pmix_mca_bfrops_v51_component = { .base = { PMIX_BFROPS_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "v51", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .priority = 60, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, bfrops, v51) pmix_status_t component_open(void) { /* setup the types array */ PMIX_CONSTRUCT(&pmix_mca_bfrops_v51_component.types, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_mca_bfrops_v51_component.types, 50, INT_MAX, 16); return PMIX_SUCCESS; } pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = pmix_mca_bfrops_v51_component.priority; *module = (pmix_mca_base_module_t *) &pmix_bfrops_pmix51_module; return PMIX_SUCCESS; } pmix_status_t component_close(void) { PMIX_DESTRUCT(&pmix_mca_bfrops_v51_component.types); return PMIX_SUCCESS; } static pmix_bfrops_module_t *assign_module(void) { pmix_output_verbose(10, pmix_bfrops_base_framework.framework_output, "bfrops:pmix51 assigning module"); return &pmix_bfrops_pmix51_module; } pmix-6.1.1~rc2/src/mca/bfrops/v51/bfrop_pmix51.c0000664000175000017500000005233715203536752021423 0ustar alastairalastair/* * Copyright (c) 2005-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2005-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "bfrop_pmix51.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_error.h" static pmix_status_t init(void); static void finalize(void); static pmix_status_t pmix51_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type); static pmix_status_t pmix51_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix51_copy(void **dest, void *src, pmix_data_type_t type); static pmix_status_t pmix51_print(char **output, char *prefix, void *src, pmix_data_type_t type); static const char *data_type_string(pmix_data_type_t type); pmix_bfrops_module_t pmix_bfrops_pmix51_module = { .version = "v51", .init = init, .finalize = finalize, .pack = pmix51_pack, .unpack = pmix51_unpack, .copy = pmix51_copy, .print = pmix51_print, .copy_payload = pmix_bfrops_base_copy_payload, .value_xfer = pmix_bfrops_base_value_xfer, .value_load = pmix_bfrops_base_value_load, .value_unload = pmix_bfrops_base_value_unload, .value_cmp = pmix_bfrops_base_value_cmp, .data_type_string = data_type_string }; static pmix_status_t init(void) { /* some standard types don't require anything special */ PMIX_REGISTER_TYPE("PMIX_BOOL", PMIX_BOOL, pmix_bfrops_base_pack_bool, pmix_bfrops_base_unpack_bool, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_bool, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE", PMIX_BYTE, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_byte, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_STRING", PMIX_STRING, pmix_bfrops_base_pack_string, pmix_bfrops_base_unpack_string, pmix_bfrops_base_copy_string, pmix_bfrops_base_print_string, &pmix_mca_bfrops_v51_component.types); /* Register the rest of the standard generic types to point to internal functions */ PMIX_REGISTER_TYPE("PMIX_SIZE", PMIX_SIZE, pmix_bfrops_base_pack_sizet, pmix_bfrops_base_unpack_sizet, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_size, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_PID", PMIX_PID, pmix_bfrops_base_pack_pid, pmix_bfrops_base_unpack_pid, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pid, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_INT", PMIX_INT, pmix_bfrops_base_pack_int, pmix_bfrops_base_unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int, &pmix_mca_bfrops_v51_component.types); /* Register all the standard fixed types to point to base functions */ PMIX_REGISTER_TYPE("PMIX_INT8", PMIX_INT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int8, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_INT16", PMIX_INT16, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int16, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_INT32", PMIX_INT32, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int32, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_INT64", PMIX_INT64, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int64, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_UINT", PMIX_UINT, pmix_bfrops_base_pack_int, pmix_bfrops_base_unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_UINT8", PMIX_UINT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint8, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_UINT16", PMIX_UINT16, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint16, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_UINT32", PMIX_UINT32, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint32, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_UINT64", PMIX_UINT64, pmix_bfrops_base_pack_general_int, pmix_bfrops_base_unpack_general_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint64, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_FLOAT", PMIX_FLOAT, pmix_bfrops_base_pack_float, pmix_bfrops_base_unpack_float, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_float, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_DOUBLE", PMIX_DOUBLE, pmix_bfrops_base_pack_double, pmix_bfrops_base_unpack_double, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_double, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_TIMEVAL", PMIX_TIMEVAL, pmix_bfrops_base_pack_timeval, pmix_bfrops_base_unpack_timeval, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_timeval, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_TIME", PMIX_TIME, pmix_bfrops_base_pack_time, pmix_bfrops_base_unpack_time, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_time, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_STATUS", PMIX_STATUS, pmix_bfrops_base_pack_status, pmix_bfrops_base_unpack_status, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_status, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_VALUE", PMIX_VALUE, pmix_bfrops_base_pack_value, pmix_bfrops_base_unpack_value, pmix_bfrops_base_copy_value, pmix_bfrops_base_print_value, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_PROC", PMIX_PROC, pmix_bfrops_base_pack_proc, pmix_bfrops_base_unpack_proc, pmix_bfrops_base_copy_proc, pmix_bfrops_base_print_proc, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_APP", PMIX_APP, pmix_bfrops_base_pack_app, pmix_bfrops_base_unpack_app, pmix_bfrops_base_copy_app, pmix_bfrops_base_print_app, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_INFO", PMIX_INFO, pmix_bfrops_base_pack_info, pmix_bfrops_base_unpack_info, pmix_bfrops_base_copy_info, pmix_bfrops_base_print_info, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_PDATA", PMIX_PDATA, pmix_bfrops_base_pack_pdata, pmix_bfrops_base_unpack_pdata, pmix_bfrops_base_copy_pdata, pmix_bfrops_base_print_pdata, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_BUFFER", PMIX_BUFFER, pmix_bfrops_base_pack_buf, pmix_bfrops_base_unpack_buf, pmix_bfrops_base_copy_buf, pmix_bfrops_base_print_buf, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE_OBJECT", PMIX_BYTE_OBJECT, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_KVAL", PMIX_KVAL, pmix_bfrops_base_pack_kval, pmix_bfrops_base_unpack_kval, pmix_bfrops_base_copy_kval, pmix_bfrops_base_print_kval, &pmix_mca_bfrops_v51_component.types); /* these are fixed-sized values and can be done by base */ PMIX_REGISTER_TYPE("PMIX_PERSIST", PMIX_PERSIST, pmix_bfrops_base_pack_persist, pmix_bfrops_base_unpack_persist, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_persist, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_POINTER", PMIX_POINTER, pmix_bfrops_base_pack_ptr, pmix_bfrops_base_unpack_ptr, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_SCOPE", PMIX_SCOPE, pmix_bfrops_base_pack_scope, pmix_bfrops_base_unpack_scope, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_scope, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_RANGE", PMIX_DATA_RANGE, pmix_bfrops_base_pack_range, pmix_bfrops_base_unpack_range, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_COMMAND", PMIX_COMMAND, pmix_bfrops_base_pack_cmd, pmix_bfrops_base_unpack_cmd, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_cmd, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_INFO_DIRECTIVES", PMIX_INFO_DIRECTIVES, pmix_bfrops_base_pack_info_directives, pmix_bfrops_base_unpack_info_directives, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_info_directives, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_TYPE", PMIX_DATA_TYPE, pmix_bfrops_base_pack_datatype, pmix_bfrops_base_unpack_datatype, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_datatype, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_STATE", PMIX_PROC_STATE, pmix_bfrops_base_pack_pstate, pmix_bfrops_base_unpack_pstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pstate, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_INFO", PMIX_PROC_INFO, pmix_bfrops_base_pack_pinfo, pmix_bfrops_base_unpack_pinfo, pmix_bfrops_base_copy_pinfo, pmix_bfrops_base_print_pinfo, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_ARRAY", PMIX_DATA_ARRAY, pmix_bfrops_base_pack_darray, pmix_bfrops_base_unpack_darray, pmix_bfrops_base_copy_darray, pmix_bfrops_base_print_darray, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_RANK", PMIX_PROC_RANK, pmix_bfrops_base_pack_rank, pmix_bfrops_base_unpack_rank, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_rank, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_QUERY", PMIX_QUERY, pmix_bfrops_base_pack_query, pmix_bfrops_base_unpack_query, pmix_bfrops_base_copy_query, pmix_bfrops_base_print_query, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_STRING", PMIX_COMPRESSED_STRING, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_ALLOC_DIRECTIVE", PMIX_ALLOC_DIRECTIVE, pmix_bfrops_base_pack_alloc_directive, pmix_bfrops_base_unpack_alloc_directive, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_alloc_directive, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_RESBLOCK_DIRECTIVE", PMIX_RESBLOCK_DIRECTIVE, pmix_bfrops_base_pack_resblock_directive, pmix_bfrops_base_unpack_resblock_directive, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_resblock_directive, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_IOF_CHANNEL", PMIX_IOF_CHANNEL, pmix_bfrops_base_pack_iof_channel, pmix_bfrops_base_unpack_iof_channel, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_iof_channel, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_ENVAR", PMIX_ENVAR, pmix_bfrops_base_pack_envar, pmix_bfrops_base_unpack_envar, pmix_bfrops_base_copy_envar, pmix_bfrops_base_print_envar, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_COORD", PMIX_COORD, pmix_bfrops_base_pack_coord, pmix_bfrops_base_unpack_coord, pmix_bfrops_base_copy_coord, pmix_bfrops_base_print_coord, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_REGATTR", PMIX_REGATTR, pmix_bfrops_base_pack_regattr, pmix_bfrops_base_unpack_regattr, pmix_bfrops_base_copy_regattr, pmix_bfrops_base_print_regattr, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_REGEX", PMIX_REGEX, pmix_bfrops_base_pack_regex, pmix_bfrops_base_unpack_regex, pmix_bfrops_base_copy_regex, pmix_bfrops_base_print_regex, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_JOB_STATE", PMIX_JOB_STATE, pmix_bfrops_base_pack_jobstate, pmix_bfrops_base_unpack_jobstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_jobstate, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_LINK_STATE", PMIX_LINK_STATE, pmix_bfrops_base_pack_linkstate, pmix_bfrops_base_unpack_linkstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_linkstate, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_CPUSET", PMIX_PROC_CPUSET, pmix_bfrops_base_pack_cpuset, pmix_bfrops_base_unpack_cpuset, pmix_bfrops_base_copy_cpuset, pmix_bfrops_base_print_cpuset, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_GEOMETRY", PMIX_GEOMETRY, pmix_bfrops_base_pack_geometry, pmix_bfrops_base_unpack_geometry, pmix_bfrops_base_copy_geometry, pmix_bfrops_base_print_geometry, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_DEVICE", PMIX_DEVICE, pmix_bfrops_base_pack_device, pmix_bfrops_base_unpack_device, pmix_bfrops_base_copy_device, pmix_bfrops_base_print_device, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_RESOURCE_UNIT", PMIX_RESOURCE_UNIT, pmix_bfrops_base_pack_resunit, pmix_bfrops_base_unpack_resunit, pmix_bfrops_base_copy_resunit, pmix_bfrops_base_print_resunit, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_DEVICE_DIST", PMIX_DEVICE_DIST, pmix_bfrops_base_pack_devdist, pmix_bfrops_base_unpack_devdist, pmix_bfrops_base_copy_devdist, pmix_bfrops_base_print_devdist, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_ENDPOINT", PMIX_ENDPOINT, pmix_bfrops_base_pack_endpoint, pmix_bfrops_base_unpack_endpoint, pmix_bfrops_base_copy_endpoint, pmix_bfrops_base_print_endpoint, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_TOPO", PMIX_TOPO, pmix_bfrops_base_pack_topology, pmix_bfrops_base_unpack_topology, pmix_bfrops_base_copy_topology, pmix_bfrops_base_print_topology, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_DEVTYPE", PMIX_DEVTYPE, pmix_bfrops_base_pack_devtype, pmix_bfrops_base_unpack_devtype, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_devtype, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_LOCTYPE", PMIX_LOCTYPE, pmix_bfrops_base_pack_locality, pmix_bfrops_base_unpack_locality, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_locality, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_BYTE_OBJECT", PMIX_COMPRESSED_BYTE_OBJECT, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_NSPACE", PMIX_PROC_NSPACE, pmix_bfrops_base_pack_nspace, pmix_bfrops_base_unpack_nspace, pmix_bfrops_base_copy_nspace, pmix_bfrops_base_print_nspace, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_BUFFER", PMIX_DATA_BUFFER, pmix_bfrops_base_pack_dbuf, pmix_bfrops_base_unpack_dbuf, pmix_bfrops_base_copy_dbuf, pmix_bfrops_base_print_dbuf, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_MEDIUM", PMIX_STOR_MEDIUM, pmix_bfrops_base_pack_smed, pmix_bfrops_base_unpack_smed, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_smed, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_ACCESS", PMIX_STOR_ACCESS, pmix_bfrops_base_pack_sacc, pmix_bfrops_base_unpack_sacc, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_sacc, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_PERSIST", PMIX_STOR_PERSIST, pmix_bfrops_base_pack_spers, pmix_bfrops_base_unpack_spers, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_spers, &pmix_mca_bfrops_v51_component.types); PMIX_REGISTER_TYPE("PMIX_STOR_ACCESS_TYPE", PMIX_STOR_ACCESS_TYPE, pmix_bfrops_base_pack_satyp, pmix_bfrops_base_unpack_satyp, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_satyp, &pmix_mca_bfrops_v51_component.types); return PMIX_SUCCESS; } static void finalize(void) { int n; pmix_bfrop_type_info_t *info; for (n = 0; n < pmix_mca_bfrops_v51_component.types.size; n++) { if (NULL != (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v51_component.types, n))) { PMIX_RELEASE(info); pmix_pointer_array_set_item(&pmix_mca_bfrops_v51_component.types, n, NULL); } } } static pmix_status_t pmix51_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_pack(&pmix_mca_bfrops_v51_component.types, buffer, src, num_vals, type); } static pmix_status_t pmix51_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_unpack(&pmix_mca_bfrops_v51_component.types, buffer, dest, num_vals, type); } static pmix_status_t pmix51_copy(void **dest, void *src, pmix_data_type_t type) { return pmix_bfrops_base_copy(&pmix_mca_bfrops_v51_component.types, dest, src, type); } static pmix_status_t pmix51_print(char **output, char *prefix, void *src, pmix_data_type_t type) { return pmix_bfrops_base_print(&pmix_mca_bfrops_v51_component.types, output, prefix, src, type); } static const char *data_type_string(pmix_data_type_t type) { return pmix_bfrops_base_data_type_string(&pmix_mca_bfrops_v51_component.types, type); } pmix-6.1.1~rc2/src/mca/bfrops/v51/Makefile.am0000664000175000017500000000345215203536752020772 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2021-2023 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = bfrop_pmix51.h sources = \ bfrop_pmix51_component.c \ bfrop_pmix51.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_bfrops_v51_DSO lib = lib_sources = component = pmix_mca_bfrops_v51.la component_sources = $(headers) $(sources) else lib = libpmix_mca_bfrops_v51.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_bfrops_v51_la_SOURCES = $(component_sources) pmix_mca_bfrops_v51_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_bfrops_v51_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_bfrops_v51_la_SOURCES = $(lib_sources) libpmix_mca_bfrops_v51_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/bfrops/base/0000775000175000017500000000000015203536752017231 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_stubs.c0000664000175000017500000001563415203536752022730 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/mca/bfrops/base/base.h" static const char *basic_type_string(pmix_data_type_t type) { switch (type) { case PMIX_BOOL: return "PMIX_BOOL"; case PMIX_BYTE: return "PMIX_BYTE"; case PMIX_STRING: return "PMIX_STRING"; case PMIX_SIZE: return "PMIX_SIZE"; case PMIX_PID: return "PMIX_PID"; case PMIX_INT: return "PMIX_INT"; case PMIX_INT8: return "PMIX_INT8"; case PMIX_INT16: return "PMIX_INT16"; case PMIX_INT32: return "PMIX_INT32"; case PMIX_INT64: return "PMIX_INT64"; case PMIX_UINT: return "PMIX_UINT"; case PMIX_UINT8: return "PMIX_UINT8"; case PMIX_UINT16: return "PMIX_UINT16"; case PMIX_UINT32: return "PMIX_UINT32"; case PMIX_UINT64: return "PMIX_UINT64"; case PMIX_FLOAT: return "PMIX_FLOAT"; case PMIX_DOUBLE: return "PMIX_DOUBLE"; case PMIX_TIMEVAL: return "PMIX_TIMEVAL"; case PMIX_TIME: return "PMIX_TIME"; case PMIX_STATUS: return "PMIX_STATUS"; case PMIX_VALUE: return "PMIX_VALUE"; case PMIX_PROC: return "PMIX_PROC"; case PMIX_APP: return "PMIX_APP"; case PMIX_INFO: return "PMIX_INFO"; case PMIX_PDATA: return "PMIX_PDATA"; case PMIX_BUFFER: return "PMIX_BUFFER"; case PMIX_BYTE_OBJECT: return "PMIX_BYTE_OBJECT"; case PMIX_KVAL: return "PMIX_KVAL"; case PMIX_PERSIST: return "PMIX_PERSIST"; case PMIX_POINTER: return "PMIX_POINTER"; case PMIX_SCOPE: return "PMIX_SCOPE"; case PMIX_DATA_RANGE: return "PMIX_DATA_RANGE"; case PMIX_COMMAND: return "PMIX_COMMAND"; case PMIX_INFO_DIRECTIVES: return "PMIX_INFO_DIRECTIVES"; case PMIX_DATA_TYPE: return "PMIX_DATA_TYPE"; case PMIX_PROC_STATE: return "PMIX_PROC_STATE"; case PMIX_PROC_INFO: return "PMIX_PROC_INFO"; case PMIX_DATA_ARRAY: return "PMIX_DATA_ARRAY"; case PMIX_PROC_RANK: return "PMIX_PROC_RANK"; case PMIX_QUERY: return "PMIX_QUERY"; case PMIX_COMPRESSED_STRING: return "PMIX_COMPRESSED_STRING"; case PMIX_ALLOC_DIRECTIVE: return "PMIX_ALLOC_DIRECTIVE"; case PMIX_IOF_CHANNEL: return "PMIX_IOF_CHANNEL"; case PMIX_ENVAR: return "PMIX_ENVAR"; case PMIX_COORD: return "PMIX_COORD"; case PMIX_REGATTR: return "PMIX_REGATTR"; case PMIX_REGEX: return "PMIX_REGEX"; case PMIX_JOB_STATE: return "PMIX_JOB_STATE"; case PMIX_LINK_STATE: return "PMIX_LINK_STATE"; case PMIX_PROC_CPUSET: return "PMIX_PROC_CPUSET"; case PMIX_GEOMETRY: return "PMIX_GEOMETRY"; case PMIX_DEVICE_DIST: return "PMIX_DEVICE_DIST"; case PMIX_ENDPOINT: return "PMIX_ENDPOINT"; case PMIX_TOPO: return "PMIX_TOPO"; case PMIX_DEVTYPE: return "PMIX_DEVTYPE"; case PMIX_LOCTYPE: return "PMIX_LOCTYPE"; case PMIX_COMPRESSED_BYTE_OBJECT: return "PMIX_COMPRESSED_BYTE_OBJECT"; case PMIX_PROC_NSPACE: return "PMIX_PROC_NSPACE"; case PMIX_DATA_BUFFER: return "PMIX_DATA_BUFFER"; case PMIX_STOR_MEDIUM: return "PMIX_STOR_MEDIUM"; case PMIX_STOR_ACCESS: return "PMIX_STOR_ACCESS"; case PMIX_STOR_PERSIST: return "PMIX_STOR_PERSIST"; case PMIX_STOR_ACCESS_TYPE: return "PMIX_STOR_ACCESS_TYPE"; case PMIX_DEVICE: return "PMIX_DEVICE"; case PMIX_RESBLOCK_DIRECTIVE: return "PMIX_RESBLOCK_DIRECTIVE"; case PMIX_RESOURCE_UNIT: return "PMIX_RESOURCE_UNIT"; default: return "NOT INITIALIZED"; } } PMIX_EXPORT const char *PMIx_Data_type_string(pmix_data_type_t type) { pmix_bfrops_base_active_module_t *active; char *reply; if (!pmix_bfrops_globals.initialized) { return basic_type_string(type); } PMIX_LIST_FOREACH (active, &pmix_bfrops_globals.actives, pmix_bfrops_base_active_module_t) { if (NULL != active->module->data_type_string) { if (NULL != (reply = (char *) active->module->data_type_string(type))) { return reply; } } } return "UNKNOWN"; } char *pmix_bfrops_base_get_available_modules(void) { pmix_bfrops_base_active_module_t *active; char **tmp = NULL, *reply = NULL; if (!pmix_bfrops_globals.initialized) { return NULL; } PMIX_LIST_FOREACH (active, &pmix_bfrops_globals.actives, pmix_bfrops_base_active_module_t) { PMIx_Argv_append_nosize(&tmp, active->component->base.pmix_mca_component_name); } if (NULL != tmp) { reply = PMIx_Argv_join(tmp, ','); PMIx_Argv_free(tmp); } return reply; } pmix_bfrops_module_t *pmix_bfrops_base_assign_module(const char *version) { pmix_bfrops_base_active_module_t *active; pmix_bfrops_module_t *mod; char **tmp = NULL; int i; if (!pmix_bfrops_globals.initialized) { return NULL; } if (NULL != version) { tmp = PMIx_Argv_split(version, ','); } PMIX_LIST_FOREACH (active, &pmix_bfrops_globals.actives, pmix_bfrops_base_active_module_t) { if (NULL == tmp) { if (NULL != (mod = active->component->assign_module())) { return mod; } } else { for (i = 0; NULL != tmp[i]; i++) { if (0 == strcmp(tmp[i], active->component->base.pmix_mca_component_name)) { if (NULL != (mod = active->component->assign_module())) { PMIx_Argv_free(tmp); return mod; } } } } } /* we only get here if nothing was found */ if (NULL != tmp) { PMIx_Argv_free(tmp); } return NULL; } pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_cmp.c0000664000175000017500000011414215203536752022341 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include "pmix.h" #include "src/include/pmix_globals.h" #include "src/mca/preg/preg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/bfrops/base/base.h" #define PMIX_CHECK_SIMPLE(r) \ do { \ if (r < 0) { \ return PMIX_VALUE2_GREATER; \ } else if (0 < r) { \ return PMIX_VALUE1_GREATER; \ } else { \ return PMIX_EQUAL; \ } \ } while(0) static pmix_value_cmp_t cmp_string(char *s1, char *s2) { int ret; if (NULL == s1 && NULL == s2) { return PMIX_EQUAL; } else if (NULL != s1 && NULL == s2) { return PMIX_VALUE1_GREATER; } else if (NULL == s1 && NULL != s2) { return PMIX_VALUE2_GREATER; } else { /* both are non-NULL */ ret = strcmp(s1, s2); PMIX_CHECK_SIMPLE(ret); } } static pmix_value_cmp_t cmp_byte_object(pmix_byte_object_t *bo1, pmix_byte_object_t *bo2) { int ret; if (bo1->size == bo2->size) { if (0 == bo1->size) { return PMIX_EQUAL; } ret = memcmp(bo1->bytes, bo2->bytes, bo1->size); PMIX_CHECK_SIMPLE(ret); } else if (bo1->size > bo2->size) { return PMIX_VALUE1_GREATER; } else { return PMIX_VALUE2_GREATER; } } static pmix_value_cmp_t cmp_proc_info(pmix_proc_info_t *pi1, pmix_proc_info_t *pi2) { int ret; ret = memcmp(&pi1->proc, &pi2->proc, sizeof(pmix_proc_t)); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (ret > 0) { return PMIX_VALUE1_GREATER; } /* proc fields are the same - check further */ if (NULL == pi1->hostname && NULL != pi2->hostname) { return PMIX_VALUE2_GREATER; } else if (NULL != pi1->hostname && NULL == pi2->hostname) { return PMIX_VALUE1_GREATER; } // both can be NULL if (NULL != pi1->hostname && NULL != pi2->hostname) { ret = strcmp(pi1->hostname, pi2->hostname); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } /* hostnames match */ if (NULL == pi1->executable_name && NULL != pi2->executable_name) { return PMIX_VALUE2_GREATER; } else if (NULL != pi1->executable_name && NULL == pi2->executable_name) { return PMIX_VALUE1_GREATER; } // both can be NULL if (NULL != pi1->executable_name && NULL != pi2->executable_name) { ret = strcmp(pi1->executable_name, pi2->executable_name); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } /* executables match */ if (pi1->pid > pi2->pid) { return PMIX_VALUE1_GREATER; } else if (pi2->pid > pi1->pid) { return PMIX_VALUE2_GREATER; } /* pids match */ if (pi1->exit_code > pi2->exit_code) { return PMIX_VALUE1_GREATER; } else if (pi2->exit_code > pi1->exit_code) { return PMIX_VALUE2_GREATER; } return PMIX_EQUAL; } static pmix_value_cmp_t cmp_envar(pmix_envar_t *e1, pmix_envar_t *e2) { int ret; if (NULL != e1) { if (NULL == e2) { return PMIX_VALUE1_GREATER; } if (NULL == e1->envar && NULL == e2->envar) { goto checkvalue; } else if (NULL == e1->envar) { return PMIX_VALUE2_GREATER; } else if (NULL == e2->envar) { return PMIX_VALUE1_GREATER; } /* both must not be NULL */ ret = strcmp(e1->envar, e2->envar); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else { /* if e1 is NULL and e2 is not, then e2 is greater */ if (NULL != e2) { return PMIX_VALUE2_GREATER; } else { /* if both are NULL, then they are equal */ return PMIX_EQUAL; } } checkvalue: /* if both envar strings are NULL or are equal, then check value */ if (NULL != e1->value) { if (NULL == e2->value) { return PMIX_VALUE1_GREATER; } ret = strcmp(e1->value, e2->value); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else if (NULL != e2->value) { /* we know e1->value had to be NULL */ return PMIX_VALUE2_GREATER; } /* finally, check separator */ if (e1->separator < e2->separator) { return PMIX_VALUE2_GREATER; } if (e1->separator < e2->separator) { return PMIX_VALUE1_GREATER; } return PMIX_EQUAL; } static pmix_value_cmp_t cmp_coord(pmix_coord_t *c1, pmix_coord_t *c2) { int ret; if (c1->view != c2->view) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } if (0 == c1->dims && 0 != c2->dims) { return PMIX_VALUE2_GREATER; } else if (0 != c1->dims && 0 == c2->dims) { return PMIX_VALUE1_GREATER; } ret = memcmp(c1->coord, c2->coord, c1->dims * sizeof(uint32_t)); PMIX_CHECK_SIMPLE(ret); } static pmix_value_cmp_t cmp_geometry(pmix_geometry_t *g1, pmix_geometry_t *g2) { int ret; pmix_value_cmp_t rc; size_t n; if (g1->fabric != g2->fabric) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } if (NULL != g1->uuid) { if (NULL == g2->uuid) { return PMIX_VALUE1_GREATER; } ret = strcmp(g1->uuid, g2->uuid); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else if (NULL != g2->uuid) { /* we know g1->uuid had to be NULL */ return PMIX_VALUE2_GREATER; } /* uuids match or are both NULL */ if (NULL != g1->osname) { if (NULL == g2->osname) { return PMIX_VALUE1_GREATER; } ret = strcmp(g1->osname, g2->osname); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else if (NULL != g2->osname) { /* we know g1->osname had to be NULL */ return PMIX_VALUE2_GREATER; } /* osnames match or are both NULL */ if (NULL == g1->coordinates && NULL == g2->coordinates) { return PMIX_EQUAL; } else if (NULL != g1->coordinates && NULL == g2->coordinates) { return PMIX_VALUE1_GREATER; } else if (NULL == g1->coordinates && NULL != g2->coordinates) { return PMIX_VALUE2_GREATER; } /* both are not NULL */ if (g1->ncoords > g2->ncoords) { return PMIX_VALUE1_GREATER; } else if (g1->ncoords < g2->ncoords) { return PMIX_VALUE2_GREATER; } /* both have same number of coords */ if (0 == g1->ncoords) { return PMIX_EQUAL; } for (n=0; n < g1->ncoords; n++) { rc = cmp_coord(&g1->coordinates[n], &g2->coordinates[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; } static pmix_value_cmp_t cmp_topo(pmix_topology_t *t1, pmix_topology_t *t2) { int ret; char *p1, *p2; if (NULL == t1->source && NULL == t2->source) { return PMIX_VALUE_COMPARISON_NOT_AVAIL; } if (NULL != t1->source && NULL == t2->source) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } else if (NULL == t1->source && NULL != t2->source) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } /* both are not NULL */ ret = strcmp(t1->source, t2->source); if (0 != ret) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } /* sources match */ if (NULL == t1->topology && NULL == t2->topology) { return PMIX_EQUAL; } else if (NULL != t1->topology && NULL == t2->topology) { return PMIX_VALUE1_GREATER; } else if (NULL == t1->topology && NULL != t2->topology) { return PMIX_VALUE2_GREATER; } /* both are not NULL */ /* stringify the topologies */ p1 = pmix_hwloc_print_topology(t1->topology); if (NULL == p1) { return PMIX_VALUE_COMPARISON_NOT_AVAIL; } p2 = pmix_hwloc_print_topology(t2->topology); if (NULL == p2) { free(p1); return PMIX_VALUE_COMPARISON_NOT_AVAIL; } ret = strcmp(p1, p2); free(p1); free(p2); PMIX_CHECK_SIMPLE(ret); } static pmix_value_cmp_t cmp_cpuset(pmix_cpuset_t *cs1, pmix_cpuset_t *cs2) { int ret; char *p1, *p2; if (NULL == cs1->source && NULL == cs2->source) { return PMIX_VALUE_COMPARISON_NOT_AVAIL; } if (NULL != cs1->source && NULL == cs2->source) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } else if (NULL == cs1->source && NULL != cs2->source) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } /* both are not NULL */ ret = strcmp(cs1->source, cs2->source); if (0 != ret) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } /* sources match */ /* stringify the cpusets */ p1 = pmix_hwloc_print_cpuset(cs1->bitmap); if (NULL == p1) { return PMIX_VALUE_COMPARISON_NOT_AVAIL; } p2 = pmix_hwloc_print_cpuset(cs2->bitmap); if (NULL == p2) { free(p1); return PMIX_VALUE_COMPARISON_NOT_AVAIL; } ret = strcmp(p1, p2); free(p1); free(p2); PMIX_CHECK_SIMPLE(ret); } static pmix_value_cmp_t cmp_device(pmix_device_t *dd1, pmix_device_t *dd2) { int ret; if (dd1->type != dd2->type) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } if (NULL != dd1->uuid) { if (NULL == dd2->uuid) { return PMIX_VALUE1_GREATER; } ret = strcmp(dd1->uuid, dd2->uuid); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else if (NULL != dd2->uuid) { /* we know g1->uuid had to be NULL */ return PMIX_VALUE2_GREATER; } /* uuids match or are both NULL */ if (NULL != dd1->osname) { if (NULL == dd2->osname) { return PMIX_VALUE1_GREATER; } ret = strcmp(dd1->osname, dd2->osname); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else if (NULL != dd2->osname) { /* we know g1->osname had to be NULL */ return PMIX_VALUE2_GREATER; } /* osnames match or are both NULL */ return PMIX_EQUAL; } static pmix_value_cmp_t cmp_resunit(pmix_resource_unit_t *dd1, pmix_resource_unit_t *dd2) { if (dd1->type != dd2->type) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } if (dd1->count > dd2->count) { return PMIX_VALUE1_GREATER; } else if (dd1->count < dd2->count) { return PMIX_VALUE2_GREATER; } return PMIX_EQUAL; } static pmix_value_cmp_t cmp_devdist(pmix_device_distance_t *dd1, pmix_device_distance_t *dd2) { int ret; if (dd1->type != dd2->type) { return PMIX_VALUE_INCOMPATIBLE_OBJECTS; } if (NULL != dd1->uuid) { if (NULL == dd2->uuid) { return PMIX_VALUE1_GREATER; } ret = strcmp(dd1->uuid, dd2->uuid); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else if (NULL != dd2->uuid) { /* we know g1->uuid had to be NULL */ return PMIX_VALUE2_GREATER; } /* uuids match or are both NULL */ if (NULL != dd1->osname) { if (NULL == dd2->osname) { return PMIX_VALUE1_GREATER; } ret = strcmp(dd1->osname, dd2->osname); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else if (NULL != dd2->osname) { /* we know g1->osname had to be NULL */ return PMIX_VALUE2_GREATER; } /* osnames match or are both NULL */ if (dd1->mindist > dd2->mindist) { return PMIX_VALUE1_GREATER; } else if (dd1->mindist < dd2->mindist) { return PMIX_VALUE2_GREATER; } if (dd1->maxdist > dd2->maxdist) { return PMIX_VALUE1_GREATER; } else if (dd1->maxdist < dd2->maxdist) { return PMIX_VALUE2_GREATER; } return PMIX_EQUAL; } static pmix_value_cmp_t cmp_endpoint(pmix_endpoint_t *e1, pmix_endpoint_t *e2) { pmix_value_cmp_t rc; int ret; if (NULL != e1->uuid) { if (NULL == e2->uuid) { return PMIX_VALUE1_GREATER; } ret = strcmp(e1->uuid, e2->uuid); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else if (NULL != e2->uuid) { /* we know e1->uuid had to be NULL */ return PMIX_VALUE2_GREATER; } /* uuids match or are both NULL */ if (NULL != e1->osname) { if (NULL == e2->osname) { return PMIX_VALUE1_GREATER; } ret = strcmp(e1->osname, e2->osname); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else if (NULL != e2->osname) { /* we know e1->osname had to be NULL */ return PMIX_VALUE2_GREATER; } /* osnames match or are both NULL */ rc = cmp_byte_object(&e1->endpt, &e2->endpt); return rc; } static pmix_value_cmp_t cmp_regattr(pmix_regattr_t *r1, pmix_regattr_t *r2) { int ret, c1, c2, n; if (NULL == r1->name && NULL == r2->name) { return PMIX_VALUE_COMPARISON_NOT_AVAIL; } if (NULL != r1->name) { if (NULL == r2->name) { return PMIX_VALUE1_GREATER; } ret = strcmp(r1->name, r2->name); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } } else if (NULL != r2->name) { /* we know r1->name had to be NULL */ return PMIX_VALUE2_GREATER; } /* both are non-NULL and equal */ ret = strcmp(r1->string, r2->string); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } if (r1->type > r2->type) { return PMIX_VALUE1_GREATER; } else if (r2->type > r1->type) { return PMIX_VALUE2_GREATER; } if (NULL == r1->description && NULL == r2->description) { return PMIX_EQUAL; } else if (NULL != r1->description && NULL == r2->description) { return PMIX_VALUE1_GREATER; } else if (NULL == r1->description && NULL != r2->description) { return PMIX_VALUE2_GREATER; } /* both are non-NULL */ c1 = PMIx_Argv_count(r1->description); c2 = PMIx_Argv_count(r2->description); if (c1 > c2) { return PMIX_VALUE1_GREATER; } else if (c2 > c1) { return PMIX_VALUE2_GREATER; } /* same number of lines */ for (n=0; n < c1; n++) { ret = strcmp(r1->description[n], r2->description[n]); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (ret > 0) { return PMIX_VALUE1_GREATER; } } return PMIX_EQUAL; } static pmix_value_cmp_t cmp_info(pmix_info_t *i1, pmix_info_t *i2) { int ret; pmix_value_cmp_t rc; ret = strcmp(i1->key, i2->key); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (ret > 0) { return PMIX_VALUE1_GREATER; } rc = pmix_bfrops_base_value_cmp(&i1->value, &i2->value); return rc; } static pmix_value_cmp_t cmp_dbuf(pmix_data_buffer_t *db1, pmix_data_buffer_t *db2) { int ret; if (NULL == db1->base_ptr && NULL == db2->base_ptr) { return PMIX_EQUAL; } if (NULL != db1->base_ptr) { if (NULL == db2->base_ptr) { return PMIX_VALUE1_GREATER; } } else if (NULL != db2->base_ptr) { /* we know db1->base_ptr had to be NULL */ return PMIX_VALUE2_GREATER; } /* both are non-NULL */ if (db1->bytes_used > db2->bytes_used) { return PMIX_VALUE1_GREATER; } else if (db2->bytes_used > db1->bytes_used) { return PMIX_VALUE2_GREATER; } /* same number of bytes used */ ret = memcmp(db1->base_ptr, db2->base_ptr, db1->bytes_used); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } return PMIX_EQUAL; } static pmix_value_cmp_t cmp_nodepid(pmix_node_pid_t *r1, pmix_node_pid_t *r2) { int ret; if (NULL != r1->hostname) { if (NULL == r2->hostname) { return PMIX_VALUE1_GREATER; } ret = strcmp(r1->hostname, r2->hostname); if (ret < 0) { return PMIX_VALUE2_GREATER; } else if (0 < ret) { return PMIX_VALUE1_GREATER; } // just drop through if they are equal } else if (NULL != r2->hostname) { return PMIX_VALUE2_GREATER; } // hostnames are the same if (r1->nodeid > r2->nodeid) { return PMIX_VALUE1_GREATER; } else if (r2->nodeid > r1->nodeid) { return PMIX_VALUE2_GREATER; } if (r1->pid > r2->pid) { return PMIX_VALUE1_GREATER; } else if (r2->pid > r1->pid) { return PMIX_VALUE2_GREATER; } return PMIX_EQUAL; } static pmix_value_cmp_t cmp_darray(pmix_data_array_t *d1, pmix_data_array_t *d2) { size_t n; int ret; pmix_value_cmp_t rc; char *st1, *st2; pmix_byte_object_t *bo1, *bo2; pmix_proc_info_t *pi1, *pi2; pmix_coord_t *c1, *c2; pmix_geometry_t *g1, *g2; pmix_envar_t *e1, *e2; pmix_topology_t *t1, *t2; pmix_cpuset_t *cs1, *cs2; pmix_device_t *dev1, *dev2; pmix_resource_unit_t *rs1, *rs2; pmix_device_distance_t *dd1, *dd2; pmix_endpoint_t *end1, *end2; pmix_regattr_t *ra1, *ra2; pmix_info_t *i1, *i2; pmix_data_buffer_t *db1, *db2; pmix_node_pid_t *ndpd1, *ndpd2; if (NULL == d1 && NULL == d2) { return PMIX_EQUAL; } else if (NULL != d1 && NULL == d2) { return PMIX_VALUE1_GREATER; } else if (NULL == d1) { return PMIX_VALUE2_GREATER; } /* both are non-NULL */ if (d1->type != d2->type) { return PMIX_VALUE_TYPE_DIFFERENT; } if (NULL == d1->array && NULL == d2->array) { return PMIX_EQUAL; } else if (NULL != d1->array && NULL == d2->array) { return PMIX_VALUE1_GREATER; } else if (NULL == d1->array) { return PMIX_VALUE2_GREATER; } /* both are non-NULL */ if (d1->size > d2->size) { return PMIX_VALUE1_GREATER; } else if (d1->size < d2->size) { return PMIX_VALUE2_GREATER; } /* they are the same size */ if (0 == d1->size) { return PMIX_EQUAL; } /* the size is greater than zero */ switch (d1->type) { case PMIX_UNDEF: return PMIX_EQUAL; break; case PMIX_BOOL: ret = memcmp(d1->array, d2->array, d1->size * sizeof(bool)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_BYTE: ret = memcmp(d1->array, d2->array, d1->size); PMIX_CHECK_SIMPLE(ret); break; case PMIX_STRING: st1 = (char*)d1->array; st2 = (char*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_string(&st1[n], &st2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_SIZE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(size_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PID: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pid_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INT: case PMIX_UINT: ret = memcmp(d1->array, d2->array, d1->size * sizeof(int)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INT8: case PMIX_UINT8: ret = memcmp(d1->array, d2->array, d1->size * sizeof(int8_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INT16: case PMIX_UINT16: case PMIX_STOR_ACCESS_TYPE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(int16_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INT32: case PMIX_UINT32: ret = memcmp(d1->array, d2->array, d1->size * sizeof(int32_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INT64: case PMIX_UINT64: case PMIX_STOR_MEDIUM: case PMIX_STOR_ACCESS: case PMIX_STOR_PERSIST: ret = memcmp(d1->array, d2->array, d1->size * sizeof(int64_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_FLOAT: ret = memcmp(d1->array, d2->array, d1->size * sizeof(float)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_DOUBLE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(double)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_TIMEVAL: ret = memcmp(d1->array, d2->array, d1->size * sizeof(struct timeval)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_TIME: ret = memcmp(d1->array, d2->array, d1->size * sizeof(time_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_STATUS: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_status_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PROC_RANK: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_rank_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PROC_NSPACE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_nspace_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PROC: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_proc_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INFO: i1 = (pmix_info_t*)d1->array; i2 = (pmix_info_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_info(&i1[n], &i2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: case PMIX_COMPRESSED_BYTE_OBJECT: case PMIX_REGEX: bo1 = (pmix_byte_object_t*)d1->array; bo2 = (pmix_byte_object_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_byte_object(&bo1[n], &bo2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_PERSIST: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_persistence_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_SCOPE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_scope_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_DATA_RANGE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_data_range_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PROC_STATE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_proc_state_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PROC_INFO: pi1 = (pmix_proc_info_t*)d1->array; pi2 = (pmix_proc_info_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_proc_info(&pi1[n], &pi2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_DATA_ARRAY: return cmp_darray(d1->array, d2->array); break; case PMIX_POINTER: ret = memcmp(d1->array, d2->array, d1->size * sizeof(char*)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_ALLOC_DIRECTIVE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_alloc_directive_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_RESBLOCK_DIRECTIVE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_resource_block_directive_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_ENVAR: e1 = (pmix_envar_t*)d1->array; e2 = (pmix_envar_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_envar(&e1[n], &e2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_COORD: c1 = (pmix_coord_t*)d1->array; c2 = (pmix_coord_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_coord(&c1[n], &c2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_LINK_STATE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_link_state_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_JOB_STATE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_job_state_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_TOPO: t1 = (pmix_topology_t *)d1->array; t2 = (pmix_topology_t *)d1->array; for (n=0; n < d1->size; n++) { rc = cmp_topo(&t1[n], &t2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_PROC_CPUSET: cs1 = (pmix_cpuset_t *)d1->array; cs2 = (pmix_cpuset_t *)d1->array; for (n=0; n < d1->size; n++) { rc = cmp_cpuset(&cs1[n], &cs2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_LOCTYPE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_locality_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_GEOMETRY: g1 = (pmix_geometry_t*)d1->array; g2 = (pmix_geometry_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_geometry(&g1[n], &g2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_DEVTYPE: ret = memcmp(d1->array, d2->array, d1->size * sizeof(pmix_device_type_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_DEVICE: dev1 = (pmix_device_t*)d1->array; dev2 = (pmix_device_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_device(&dev1[n], &dev2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; case PMIX_RESOURCE_UNIT: rs1 = (pmix_resource_unit_t*)d1->array; rs2 = (pmix_resource_unit_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_resunit(&rs1[n], &rs2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; case PMIX_DEVICE_DIST: dd1 = (pmix_device_distance_t*)d1->array; dd2 = (pmix_device_distance_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_devdist(&dd1[n], &dd2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_ENDPOINT: end1 = (pmix_endpoint_t*)d1->array; end2 = (pmix_endpoint_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_endpoint(&end1[n], &end2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_DATA_BUFFER: db1 = (pmix_data_buffer_t*)d1->array; db2 = (pmix_data_buffer_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_dbuf(&db1[n], &db2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_REGATTR: ra1 = (pmix_regattr_t*)d1->array; ra2 = (pmix_regattr_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_regattr(&ra1[n], &ra2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; case PMIX_NODE_PID: ndpd1 = (pmix_node_pid_t*)d1->array; ndpd2 = (pmix_node_pid_t*)d2->array; for (n=0; n < d1->size; n++) { rc = cmp_nodepid(&ndpd1[n], &ndpd2[n]); if (PMIX_EQUAL != rc) { return rc; } } return PMIX_EQUAL; break; default: pmix_output(0, "COMPARE-PMIX-VALUE: UNSUPPORTED TYPE %s (%d)", PMIx_Data_type_string(d1->type), (int) d1->type); } return PMIX_VALUE_COMPARISON_NOT_AVAIL; } /* compare function for pmix_value_t */ pmix_value_cmp_t pmix_bfrops_base_value_cmp(pmix_value_t *p1, pmix_value_t *p2) { pmix_value_cmp_t rc; int ret; if (p1->type != p2->type) { return PMIX_VALUE_TYPE_DIFFERENT; } switch (p1->type) { case PMIX_UNDEF: return PMIX_EQUAL; break; case PMIX_BOOL: ret = memcmp(&p1->data.flag, &p2->data.flag, sizeof(bool)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_BYTE: ret = memcmp(&p1->data.byte, &p2->data.byte, 1); PMIX_CHECK_SIMPLE(ret); break; case PMIX_STRING: rc = cmp_string(p1->data.string, p2->data.string); return rc; break; case PMIX_SIZE: ret = memcmp(&p1->data.size, &p2->data.size, sizeof(size_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PID: ret = memcmp(&p1->data.pid, &p2->data.pid, sizeof(pid_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INT: case PMIX_UINT: ret = memcmp(&p1->data.integer, &p2->data.integer, sizeof(int)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INT8: case PMIX_UINT8: ret = memcmp(&p1->data.int8, &p2->data.int8, sizeof(int8_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INT16: case PMIX_UINT16: case PMIX_STOR_ACCESS_TYPE: ret = memcmp(&p1->data.int16, &p2->data.int16, sizeof(int16_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INT32: case PMIX_UINT32: ret = memcmp(&p1->data.int32, &p2->data.int32, sizeof(int32_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_INT64: case PMIX_UINT64: case PMIX_STOR_MEDIUM: case PMIX_STOR_ACCESS: case PMIX_STOR_PERSIST: ret = memcmp(&p1->data.int64, &p2->data.int64, sizeof(int64_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_FLOAT: ret = memcmp(&p1->data.fval, &p2->data.fval, sizeof(float)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_DOUBLE: ret = memcmp(&p1->data.dval, &p2->data.dval, sizeof(double)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_TIMEVAL: ret = memcmp(&p1->data.tv, &p2->data.tv, sizeof(struct timeval)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_TIME: ret = memcmp(&p1->data.time, &p2->data.time, sizeof(time_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_STATUS: ret = memcmp(&p1->data.status, &p2->data.status, sizeof(pmix_status_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PROC_RANK: ret = memcmp(&p1->data.rank, &p2->data.rank, sizeof(pmix_rank_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PROC_NSPACE: ret = memcmp(p1->data.nspace, p2->data.nspace, sizeof(pmix_nspace_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PROC: ret = memcmp(p1->data.proc, p2->data.proc, sizeof(pmix_proc_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: case PMIX_COMPRESSED_BYTE_OBJECT: case PMIX_REGEX: rc = cmp_byte_object(&p1->data.bo, &p2->data.bo); return rc; break; case PMIX_PERSIST: ret = memcmp(&p1->data.persist, &p2->data.persist, sizeof(pmix_persistence_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_SCOPE: ret = memcmp(&p1->data.scope, &p2->data.scope, sizeof(pmix_scope_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_DATA_RANGE: ret = memcmp(&p1->data.range, &p2->data.range, sizeof(pmix_data_range_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PROC_STATE: ret = memcmp(&p1->data.state, &p2->data.state, sizeof(pmix_proc_state_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_PROC_INFO: rc = cmp_proc_info(p1->data.pinfo, p2->data.pinfo); return rc; break; case PMIX_DATA_ARRAY: return cmp_darray(p1->data.darray, p2->data.darray); break; case PMIX_POINTER: if (p1->data.ptr == p2->data.ptr) { return PMIX_EQUAL; } else if (p1->data.ptr > p2->data.ptr) { return PMIX_VALUE1_GREATER; } else { return PMIX_VALUE2_GREATER; } break; case PMIX_ALLOC_DIRECTIVE: ret = memcmp(&p1->data.adir, &p2->data.adir, sizeof(pmix_alloc_directive_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_RESBLOCK_DIRECTIVE: ret = memcmp(&p1->data.rbdir, &p2->data.rbdir, sizeof(pmix_resource_block_directive_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_ENVAR: rc = cmp_envar(&p1->data.envar, &p2->data.envar); return rc; break; case PMIX_COORD: rc = cmp_coord(p1->data.coord, p2->data.coord); return rc; break; case PMIX_LINK_STATE: ret = memcmp(&p1->data.linkstate, &p2->data.linkstate, sizeof(pmix_link_state_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_JOB_STATE: ret = memcmp(&p1->data.jstate, &p2->data.jstate, sizeof(pmix_job_state_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_TOPO: rc = cmp_topo(p1->data.topo, p2->data.topo); return rc; break; case PMIX_PROC_CPUSET: rc = cmp_cpuset(p1->data.cpuset, p2->data.cpuset); return rc; break; case PMIX_LOCTYPE: ret = memcmp(&p1->data.locality, &p2->data.locality, sizeof(pmix_locality_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_GEOMETRY: rc = cmp_geometry(p1->data.geometry, p2->data.geometry); return rc; break; case PMIX_DEVTYPE: ret = memcmp(&p1->data.devtype, &p2->data.devtype, sizeof(pmix_device_type_t)); PMIX_CHECK_SIMPLE(ret); break; case PMIX_DEVICE: rc = cmp_device(p1->data.device, p2->data.device); return rc; break; case PMIX_RESOURCE_UNIT: rc = cmp_resunit(p1->data.resunit, p2->data.resunit); return rc; break; case PMIX_DEVICE_DIST: rc = cmp_devdist(p1->data.devdist, p2->data.devdist); return rc; break; case PMIX_ENDPOINT: rc = cmp_endpoint(p1->data.endpoint, p2->data.endpoint); return rc; break; case PMIX_DATA_BUFFER: rc = cmp_dbuf(p1->data.dbuf, p2->data.dbuf); return rc; break; /* account for types that don't use a specific field * in the union */ case PMIX_REGATTR: rc = cmp_regattr(p1->data.ptr, p2->data.ptr); return rc; break; case PMIX_NODE_PID: rc = cmp_nodepid(p1->data.nodepid, p2->data.nodepid); return rc; break; default: pmix_output(0, "COMPARE-PMIX-VALUE: UNSUPPORTED TYPE %s (%d)", PMIx_Data_type_string(p1->type), (int) p1->type); } return PMIX_VALUE_COMPARISON_NOT_AVAIL; } pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_frame.c0000664000175000017500000001500315203536752022650 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2009 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/bfrops/base/bfrop_base_tma.h" #include "src/mca/mca.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public mca_base_component_t struct. */ #include "src/mca/bfrops/base/static-components.h" /* Instantiate the global vars */ pmix_bfrops_globals_t pmix_bfrops_globals = { .actives = PMIX_LIST_STATIC_INIT, .initialized = false, .initial_size = 0, .threshold_size = 0, #if PMIX_ENABLE_DEBUG .default_type = PMIX_BFROP_BUFFER_FULLY_DESC #else .default_type = PMIX_BFROP_BUFFER_NON_DESC #endif }; int pmix_bfrops_base_output = 0; static int pmix_bfrop_register(pmix_mca_base_register_flag_t flags) { PMIX_HIDE_UNUSED_PARAMS(flags); if (PMIX_MCA_BASE_REGISTER_DEFAULT == flags) { /* do something to silence warning */ } pmix_bfrops_globals.initial_size = PMIX_BFROP_DEFAULT_INITIAL_SIZE; pmix_mca_base_var_register("pmix", "bfrops", "base", "initial_size", "Initial size of a buffer", PMIX_MCA_BASE_VAR_TYPE_SIZE_T, &pmix_bfrops_globals.initial_size); pmix_bfrops_globals.threshold_size = PMIX_BFROP_DEFAULT_THRESHOLD_SIZE; pmix_mca_base_var_register("pmix", "bfrops", "base", "threshold_size", "Size at which we switch from extending a buffer by doubling to " "extending by a smaller value", PMIX_MCA_BASE_VAR_TYPE_SIZE_T, &pmix_bfrops_globals.threshold_size); #if PMIX_ENABLE_DEBUG pmix_bfrops_globals.default_type = PMIX_BFROP_BUFFER_FULLY_DESC; #else pmix_bfrops_globals.default_type = PMIX_BFROP_BUFFER_NON_DESC; #endif pmix_mca_base_var_register("pmix", "bfrops", "base", "default_type", "Default type for buffers", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_bfrops_globals.default_type); return PMIX_SUCCESS; } static pmix_status_t pmix_bfrop_close(void) { if (!pmix_bfrops_globals.initialized) { return PMIX_SUCCESS; } pmix_bfrops_globals.initialized = false; pmix_bfrops_globals.selected = false; /* the components will cleanup when closed */ PMIX_LIST_DESTRUCT(&pmix_bfrops_globals.actives); return pmix_mca_base_framework_components_close(&pmix_bfrops_base_framework, NULL); } static pmix_status_t pmix_bfrop_open(pmix_mca_base_open_flag_t flags) { pmix_status_t rc; /* initialize globals */ pmix_bfrops_globals.initialized = true; PMIX_CONSTRUCT(&pmix_bfrops_globals.actives, pmix_list_t); /* Open up all available components */ rc = pmix_mca_base_framework_components_open(&pmix_bfrops_base_framework, flags); pmix_bfrops_base_output = pmix_bfrops_base_framework.framework_output; return rc; } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, bfrops, "PMIx Buffer Operations", pmix_bfrop_register, pmix_bfrop_open, pmix_bfrop_close, pmix_mca_bfrops_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); static void moddes(pmix_bfrops_base_active_module_t *p) { if (NULL != p->module->finalize) { p->module->finalize(); } } PMIX_CLASS_INSTANCE(pmix_bfrops_base_active_module_t, pmix_list_item_t, NULL, moddes); /** * Object constructors, destructors, and instantiations */ /** Value **/ static void pmix_buffer_construct(pmix_buffer_t *buffer) { /** set the buffer type to UNDEF so the first pack operation * can correctly set it */ buffer->type = PMIX_BFROP_BUFFER_UNDEF; /* Make everything NULL to begin with */ buffer->base_ptr = buffer->pack_ptr = buffer->unpack_ptr = NULL; buffer->bytes_allocated = buffer->bytes_used = 0; } static void pmix_buffer_destruct(pmix_buffer_t *buffer) { if (NULL != buffer->base_ptr) { free(buffer->base_ptr); } } PMIX_CLASS_INSTANCE(pmix_buffer_t, pmix_object_t, pmix_buffer_construct, pmix_buffer_destruct); static void pmix_bfrop_type_info_construct(pmix_bfrop_type_info_t *obj) { obj->odti_name = NULL; obj->odti_pack_fn = NULL; obj->odti_unpack_fn = NULL; obj->odti_copy_fn = NULL; obj->odti_print_fn = NULL; } static void pmix_bfrop_type_info_destruct(pmix_bfrop_type_info_t *obj) { if (NULL != obj->odti_name) { free(obj->odti_name); } } PMIX_CLASS_INSTANCE(pmix_bfrop_type_info_t, pmix_object_t, pmix_bfrop_type_info_construct, pmix_bfrop_type_info_destruct); static void kvcon(pmix_kval_t *k) { k->key = NULL; k->value = NULL; } static void kvdes(pmix_kval_t *k) { pmix_tma_t *const tma = pmix_obj_get_tma(&k->super.super); if (NULL != k->key) { pmix_tma_free(tma, k->key); } if (NULL != k->value) { pmix_bfrops_base_tma_value_destruct(k->value, tma); pmix_tma_free(tma, k->value); k->value = NULL; } } PMIX_CLASS_INSTANCE(pmix_kval_t, pmix_list_item_t, kvcon, kvdes); pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_get_number.c0000664000175000017500000020045015203536752023707 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022 IBM Corporation. All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include "pmix.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_error.h" #include "src/mca/bfrops/base/base.h" /* check differences in type between source and destination * to see if we lose precision or might change the sign of * the value - note that we already dealt with the case * where the source and destination have the same type */ static pmix_status_t check_size(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_int(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_int8(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_int16(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_int32(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_int64(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_uint(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_uint8(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_uint16(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_uint32(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_uint64(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_float(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_double(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_rank(const pmix_value_t *value, void *dest, pmix_data_type_t type); static pmix_status_t check_status(const pmix_value_t *value, void *dest, pmix_data_type_t type); pmix_status_t PMIx_Value_get_number(const pmix_value_t *value, void *dest, pmix_data_type_t type) { if (PMIX_SIZE == value->type) { if (PMIX_SIZE == type) { size_t *sz; sz = (size_t*)dest; *sz = value->data.size; return PMIX_SUCCESS; } else { return check_size(value, dest, type); } } if (PMIX_INT == value->type) { if (PMIX_INT == type) { int *i; i = (int*)dest; *i = value->data.integer; return PMIX_SUCCESS; } else { return check_int(value, dest, type); } } if (PMIX_INT8 == value->type) { if (PMIX_INT8 == type) { int8_t *i8; i8 = (int8_t*)dest; *i8 = value->data.int8; return PMIX_SUCCESS; } else { return check_int8(value, dest, type); } } if (PMIX_INT16 == value->type) { if (PMIX_INT16 == type) { int16_t *i16; i16 = (int16_t*)dest; *i16 = value->data.int16; return PMIX_SUCCESS; } else { return check_int16(value, dest, type); } } if (PMIX_INT32 == value->type) { if (PMIX_INT32 == type) { int32_t *i32; i32 = (int32_t*)dest; *i32 = value->data.int32; return PMIX_SUCCESS; } else { return check_int32(value, dest, type); } } if (PMIX_INT64 == value->type) { if (PMIX_INT64 == type) { int64_t *i64; i64 = (int64_t*)dest; *i64 = value->data.int64; return PMIX_SUCCESS; } else { return check_int64(value, dest, type); } } if (PMIX_UINT == value->type) { if (PMIX_UINT == type) { unsigned int *ui; ui = (unsigned int*)dest; *ui = value->data.uint; return PMIX_SUCCESS; } else { return check_uint(value, dest, type); } } if (PMIX_UINT8 == value->type) { if (PMIX_UINT8 == type) { uint8_t *u8; u8 = (uint8_t*)dest; *u8 = value->data.uint8; return PMIX_SUCCESS; } else { return check_uint8(value, dest, type); } } if (PMIX_UINT16 == value->type) { if (PMIX_UINT16 == type) { uint16_t *u16; u16 = (uint16_t*)dest; *u16 = value->data.uint16; return PMIX_SUCCESS; } else { return check_uint16(value, dest, type); } } if (PMIX_UINT32 == value->type) { if (PMIX_UINT32 == type) { uint32_t *u32; u32 = (uint32_t*)dest; *u32 = value->data.uint32; return PMIX_SUCCESS; } else { return check_uint32(value, dest, type); } } if (PMIX_UINT64 == value->type) { if (PMIX_UINT64 == type) { uint64_t *u64; u64 = (uint64_t*)dest; *u64 = value->data.uint64; return PMIX_SUCCESS; } else { return check_uint64(value, dest, type); } } if (PMIX_FLOAT == value->type) { if (PMIX_FLOAT == type) { float *f; f = (float*)dest; *f = value->data.fval; return PMIX_SUCCESS; } else { return check_float(value, dest, type); } } if (PMIX_DOUBLE == value->type) { if (PMIX_DOUBLE == type) { double *d; d = (double*)dest; *d = value->data.dval; return PMIX_SUCCESS; } else { return check_double(value, dest, type); } } if (PMIX_PID == value->type) { if (PMIX_PID == type) { pid_t *p; p = (pid_t*)dest; *p = value->data.pid; return PMIX_SUCCESS; } } if (PMIX_PROC_RANK == value->type) { if (PMIX_PROC_RANK == type) { pmix_rank_t *r; r = (pmix_rank_t*)dest; *r = value->data.rank; return PMIX_SUCCESS; } else { return check_rank(value, dest, type); } } if (PMIX_STATUS == value->type) { if (PMIX_STATUS== type) { pmix_status_t *s; s = (pmix_status_t*)dest; *s = value->data.status; return PMIX_SUCCESS; } else { return check_status(value, dest, type); } } /* if we get here, then the value is not a numeric type */ return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_size(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *ui; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; if (PMIX_INT == type) { // potentially out-of-range if (INT_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } i = (int*)dest; *i = (int)value->data.size; return PMIX_SUCCESS; } if (PMIX_INT8 == type) { if (INT8_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.size; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (INT16_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.size; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { if (INT32_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } i32 = (int32_t*)dest; *i32 = (int32_t)value->data.size; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { if (INT64_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } i64 = (int64_t*)dest; *i64 = (int64_t)value->data.size; return PMIX_SUCCESS; } if (PMIX_UINT == type) { if (UINT_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } ui = (unsigned int*)dest; *ui = (unsigned int)value->data.size; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.size; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (UINT16_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.size; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { if (UINT32_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.size; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.size; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.size; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.size; return PMIX_SUCCESS; } if (PMIX_PID == type) { // pid_t is a signed int if (INT_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } pid = (pid_t*)dest; *pid = (pid_t)value->data.size; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int if (INT_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.size; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is a uint32 if (UINT32_MAX < value->data.size) { return PMIX_ERR_LOST_PRECISION; } pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.size; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_int(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *ui; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; // check if this xfer would change sign if (0 > value->data.integer) { if (PMIX_SIZE == type || PMIX_UINT == type || PMIX_UINT8 == type || PMIX_UINT16 == type || PMIX_UINT32 == type || PMIX_UINT64 == type || PMIX_PROC_RANK == type) { return PMIX_ERR_CHANGE_SIGN; } } /* already took care of the negative value case when * transferring to unsigned types, and no loss of * precision if the dest is equal in size or larger */ if (PMIX_INT64 == type) { i64 = (int64_t*)dest; *i64 = (int64_t)value->data.integer; return PMIX_SUCCESS; } if (PMIX_UINT == type) { ui = (unsigned int*)dest; *ui = (unsigned int)value->data.integer; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.integer; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.integer; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.integer; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.integer; return PMIX_SUCCESS; } if (PMIX_PID == type) { // pid_t is a signed int pid = (pid_t*)dest; *pid = (pid_t)value->data.integer; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.integer; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is an unsigned int pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.integer; } // if we get here, then we are dealing with a smaller // destination, which means we can lose precision if (PMIX_INT8 == type) { if (0 < value->data.integer) { if (INT8_MAX < value->data.integer) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT8_MIN > value->data.integer) { return PMIX_ERR_LOST_PRECISION; } } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.integer; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (0 < value->data.integer) { if (INT16_MAX < value->data.integer) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT16_MIN > value->data.integer) { return PMIX_ERR_LOST_PRECISION; } } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.integer; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { i32 = (int32_t*)dest; *i32 = (int32_t)value->data.integer; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.integer) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.integer; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (UINT16_MAX < value->data.integer) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.integer; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.integer; return PMIX_SUCCESS; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_int8(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *ui; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; // check if this xfer would change sign if (0 > value->data.int8) { if (PMIX_SIZE == type || PMIX_UINT == type || PMIX_UINT8 == type || PMIX_UINT16 == type || PMIX_UINT32 == type || PMIX_UINT64 == type || PMIX_PROC_RANK == type) { return PMIX_ERR_CHANGE_SIGN; } } // everything is at least 8-bits if (PMIX_INT == type) { i = (int*)dest; *i = (int)value->data.int8; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { i16 = (int16_t*)dest; *i16 = (int16_t)value->data.int8; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { i32 = (int32_t*)dest; *i32 = (int32_t)value->data.int8; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { i64 = (int64_t*)dest; *i64 = (int64_t)value->data.int8; return PMIX_SUCCESS; } if (PMIX_UINT == type) { ui = (unsigned int*)dest; *ui = (unsigned int)value->data.int8; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.int8; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.int8; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.int8; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.int8; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.int8; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.int8; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.int8; return PMIX_SUCCESS; } if (PMIX_PID == type) { // pid_t is a signed int pid = (pid_t*)dest; *pid = (pid_t)value->data.int8; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.int8; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.int8; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_int16(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int32_t *i32; int64_t *i64; unsigned int *ui; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; // check if this xfer would change sign if (0 > value->data.integer) { if (PMIX_SIZE == type || PMIX_UINT == type || PMIX_UINT8 == type || PMIX_UINT16 == type || PMIX_UINT32 == type || PMIX_UINT64 == type || PMIX_PROC_RANK == type) { return PMIX_ERR_CHANGE_SIGN; } } /* already took care of the negative value case when * transferring to unsigned types, and no loss of * precision if the dest is equal in size or larger */ if (PMIX_INT == type) { i = (int*)dest; *i = (int)value->data.int16; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { i32 = (int32_t*)dest; *i32 = (int32_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { i64 = (int64_t*)dest; *i64 = (int64_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_UINT == type) { ui = (unsigned int*)dest; *ui = (unsigned int)value->data.int16; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.int16; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.int16; return PMIX_SUCCESS; } if (PMIX_PID == type) { // pid_t is a signed int pid = (pid_t*)dest; *pid = (pid_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is an unsigned int pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.int16; } // if we get here, then we are dealing with a smaller // destination, which means we can lose precision if (PMIX_INT8 == type) { if (0 < value->data.int16) { if (INT8_MAX < value->data.int16) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT8_MIN > value->data.int16) { return PMIX_ERR_LOST_PRECISION; } } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.int16) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.int16; return PMIX_SUCCESS; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_int32(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int64_t *i64; unsigned int *ui; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; // check if this xfer would change sign if (0 > value->data.integer) { if (PMIX_SIZE == type || PMIX_UINT == type || PMIX_UINT8 == type || PMIX_UINT16 == type || PMIX_UINT32 == type || PMIX_UINT64 == type || PMIX_PROC_RANK == type) { return PMIX_ERR_CHANGE_SIGN; } } /* already took care of the negative value case when * transferring to unsigned types, and no loss of * precision if the dest is equal in size or larger */ if (PMIX_INT == type) { i = (int*)dest; *i = (int)value->data.int32; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { i64 = (int64_t*)dest; *i64 = (int64_t)value->data.int32; return PMIX_SUCCESS; } if (PMIX_UINT == type) { ui = (unsigned int*)dest; *ui = (unsigned int)value->data.int32; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.int32; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.int32; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.int32; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.int32; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.int32; return PMIX_SUCCESS; } if (PMIX_PID == type) { // pid_t is a signed int pid = (pid_t*)dest; *pid = (pid_t)value->data.int32; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.int32; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is an unsigned int pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.int32; } // if we get here, then we are dealing with a smaller // destination, which means we can lose precision if (PMIX_INT8 == type) { if (0 < value->data.int16) { if (INT8_MAX < value->data.int16) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT8_MIN > value->data.int16) { return PMIX_ERR_LOST_PRECISION; } } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (0 < value->data.int32) { if (INT16_MAX < value->data.int32) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT16_MIN > value->data.int32) { return PMIX_ERR_LOST_PRECISION; } } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.int32; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.int16) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.int16; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (UINT16_MAX < value->data.int32) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.int32; return PMIX_SUCCESS; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_int64(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; unsigned int *ui; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; // check if this xfer would change sign if (0 > value->data.integer) { if (PMIX_SIZE == type || PMIX_UINT == type || PMIX_UINT8 == type || PMIX_UINT16 == type || PMIX_UINT32 == type || PMIX_UINT64 == type || PMIX_PROC_RANK == type) { return PMIX_ERR_CHANGE_SIGN; } } /* already took care of the negative value case when * transferring to unsigned types, and no loss of * precision if the dest is equal in size or larger */ if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.int64; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.int64; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.int64; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.int64; return PMIX_SUCCESS; } // if we get here, then we are dealing with a smaller // destination, which means we can lose precision if (PMIX_INT == type) { if (0 < value->data.int64) { if (INT_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT_MIN > value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } i = (int*)dest; *i = (int)value->data.int64; return PMIX_SUCCESS; } if (PMIX_INT8 == type) { if (0 < value->data.int64) { if (INT8_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT8_MIN > value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.int64; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (0 < value->data.int64) { if (INT16_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT16_MIN > value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.int64; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { if (0 < value->data.int64) { if (INT32_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT32_MIN > value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } i32 = (int32_t*)dest; *i32 = (int32_t)value->data.int64; return PMIX_SUCCESS; } if (PMIX_UINT == type) { if (0 < value->data.int64) { if (UINT_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } ui = (unsigned int*)dest; *ui = (unsigned int)value->data.int64; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.int64; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (UINT16_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.int64; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { if (0 < value->data.int64) { if (UINT32_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.int64; return PMIX_SUCCESS; } if (PMIX_PID == type) { // pid_t is a signed int if (0 < value->data.int64) { if (UINT32_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } pid = (pid_t*)dest; *pid = (pid_t)value->data.int64; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int if (0 < value->data.int64) { if (UINT32_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } } ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.int64; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is a uint32 if (UINT32_MAX < value->data.int64) { return PMIX_ERR_LOST_PRECISION; } pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.int64; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_uint(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; /* no negative value to be concerned about, and no loss of * precision if the dest is equal in size or larger */ if (PMIX_INT64 == type) { i64 = (int64_t*)dest; *i64 = (int64_t)value->data.uint; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.uint; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.uint; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.uint; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.uint; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is an unsigned int pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.uint; } // if we get here, then we are dealing with a smaller // destination, which means we can lose precision if (PMIX_INT == type) { if (INT_MAX < value->data.uint) { return PMIX_ERR_LOST_PRECISION; } i = (int*)dest; *i = (int)value->data.uint; return PMIX_SUCCESS; } if (PMIX_INT8 == type) { if (INT8_MAX < value->data.uint) { return PMIX_ERR_LOST_PRECISION; } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.uint; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (INT16_MAX < value->data.uint) { return PMIX_ERR_LOST_PRECISION; } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.uint; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { if (INT32_MAX < value->data.uint) { return PMIX_ERR_LOST_PRECISION; } i32 = (int32_t*)dest; *i32 = (int32_t)value->data.uint; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.uint) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.uint; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (UINT16_MAX < value->data.uint) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.uint; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.uint; return PMIX_SUCCESS; } if (PMIX_PID == type) { // pid_t is a signed int if (INT_MAX < value->data.uint) { return PMIX_ERR_LOST_PRECISION; } pid = (pid_t*)dest; *pid = (pid_t)value->data.uint; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int if (INT_MAX < value->data.uint) { return PMIX_ERR_LOST_PRECISION; } ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.uint; return PMIX_SUCCESS; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_uint8(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *u; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; /* no negative value to be concerned about, and no loss of * precision since everything is at least 8 bits */ if (PMIX_INT == type) { i = (int*)dest; *i = (int)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_INT8 == type) { if (INT8_MAX < value->data.uint8) { return PMIX_ERR_LOST_PRECISION; } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { i16 = (int16_t*)dest; *i16 = (int16_t)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { i32 = (int32_t*)dest; *i32 = (int32_t)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { i64 = (int64_t*)dest; *i64 = (int64_t)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_UINT == type) { u = (unsigned int *)dest; *u = (unsigned int)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is an unsigned int pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.uint8; } if (PMIX_PID == type) { // pid_t is a signed int pid = (pid_t*)dest; *pid = (pid_t)value->data.uint8; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.uint8; return PMIX_SUCCESS; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_uint16(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *u; uint8_t *u8; uint32_t *u32; uint64_t *u64; size_t *sz; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; /* no negative value to be concerned about */ if (PMIX_INT == type) { i = (int*)dest; *i = (int)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_INT8 == type) { if (INT8_MAX < value->data.uint16) { return PMIX_ERR_LOST_PRECISION; } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (INT16_MAX < value->data.uint16) { return PMIX_ERR_LOST_PRECISION; } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { i32 = (int32_t*)dest; *i32 = (int32_t)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { i64 = (int64_t*)dest; *i64 = (int64_t)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_UINT == type) { u = (unsigned int *)dest; *u = (unsigned int)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.uint16) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is an unsigned int pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.uint16; } if (PMIX_PID == type) { // pid_t is a signed int pid = (pid_t*)dest; *pid = (pid_t)value->data.uint16; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.uint16; return PMIX_SUCCESS; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_uint32(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *u; uint8_t *u8; uint16_t *u16; uint64_t *u64; size_t *sz; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; /* no negative value to be concerned about */ if (PMIX_INT == type) { if (INT_MAX < value->data.uint32) { return PMIX_ERR_LOST_PRECISION; } i = (int*)dest; *i = (int)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_INT8 == type) { if (INT8_MAX < value->data.uint32) { return PMIX_ERR_LOST_PRECISION; } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (INT16_MAX < value->data.uint32) { return PMIX_ERR_LOST_PRECISION; } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { if (INT32_MAX < value->data.uint32) { return PMIX_ERR_LOST_PRECISION; } i32 = (int32_t*)dest; *i32 = (int32_t)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { i64 = (int64_t*)dest; *i64 = (int64_t)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_UINT == type) { u = (unsigned int *)dest; *u = (unsigned int)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.uint32) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (UINT16_MAX < value->data.uint32) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is an unsigned int pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.uint32; } if (PMIX_PID == type) { // pid_t is a signed int if (INT_MAX < value->data.uint32) { return PMIX_ERR_LOST_PRECISION; } pid = (pid_t*)dest; *pid = (pid_t)value->data.uint32; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int if (INT_MAX < value->data.uint32) { return PMIX_ERR_LOST_PRECISION; } ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.uint32; return PMIX_SUCCESS; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_uint64(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *u; uint8_t *u8; uint16_t *u16; uint32_t *u32; size_t *sz; float *flt; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; /* no negative value to be concerned about */ if (PMIX_INT == type) { if (INT_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } i = (int*)dest; *i = (int)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_INT8 == type) { if (INT8_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (INT16_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { if (INT32_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } i32 = (int32_t*)dest; *i32 = (int32_t)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { if (INT64_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } i64 = (int64_t*)dest; *i64 = (int64_t)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_UINT == type) { if (UINT_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } u = (unsigned int *)dest; *u = (unsigned int)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (UINT16_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { if (UINT32_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is an unsigned int if (UINT32_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.uint64; } if (PMIX_PID == type) { // pid_t is a signed int if (INT_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } pid = (pid_t*)dest; *pid = (pid_t)value->data.uint64; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int if (INT_MAX < value->data.uint64) { return PMIX_ERR_LOST_PRECISION; } ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.uint64; return PMIX_SUCCESS; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_float(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *u; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; double *dbl; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; // check if this xfer would change sign if (0 > value->data.fval) { if (PMIX_SIZE == type || PMIX_UINT == type || PMIX_UINT8 == type || PMIX_UINT16 == type || PMIX_UINT32 == type || PMIX_UINT64 == type || PMIX_PROC_RANK == type) { return PMIX_ERR_CHANGE_SIGN; } } if (PMIX_INT == type) { if (2147483647.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } else if (-2147483648.0 > value->data.fval) { return PMIX_ERR_LOST_PRECISION; } i = (int*)dest; *i = (int)value->data.fval; return PMIX_SUCCESS; } if (PMIX_INT8 == type) { if (127.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } else if (-128.0 > value->data.fval) { return PMIX_ERR_LOST_PRECISION; } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.fval; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (32767.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } else if (-32768.0 > value->data.fval) { return PMIX_ERR_LOST_PRECISION; } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.fval; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { if (2147483647.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } else if (-2147483648.0 > value->data.fval) { return PMIX_ERR_LOST_PRECISION; } i32 = (int32_t*)dest; *i32 = (int32_t)value->data.fval; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { if (18446744073709551000.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } else if (-9223372036854775808.0 > value->data.fval) { return PMIX_ERR_LOST_PRECISION; } i64 = (int64_t*)dest; *i64 = (int64_t)value->data.fval; return PMIX_SUCCESS; } if (PMIX_UINT == type) { if (42949670295.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } u = (unsigned int *)dest; *u = (unsigned int)value->data.fval; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (256.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.fval; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (65535.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.fval; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { if (4294967040.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.fval; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { if (18446744073709551000.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.fval; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { if (18446744073709551000.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } sz = (size_t*)dest; *sz = (size_t)value->data.fval; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.fval; return PMIX_SUCCESS; } if (PMIX_PROC_RANK == type) { // rank is an unsigned int if (4294967040.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.fval; } if (PMIX_PID == type) { // pid_t is a signed int if (2147483647.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } pid = (pid_t*)dest; *pid = (pid_t)value->data.fval; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int if (2147483647.0 < value->data.fval) { return PMIX_ERR_LOST_PRECISION; } ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.fval; return PMIX_SUCCESS; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_double(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *u; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; pid_t *pid; pmix_status_t *ps; pmix_rank_t *pr; // check if this xfer would change sign if (0 > value->data.dval) { if (PMIX_SIZE == type || PMIX_UINT == type || PMIX_UINT8 == type || PMIX_UINT16 == type || PMIX_UINT32 == type || PMIX_UINT64 == type || PMIX_PROC_RANK == type) { return PMIX_ERR_CHANGE_SIGN; } } if (PMIX_INT == type) { if (2147483647.0f < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } else if (-2147483648.0f > value->data.dval) { return PMIX_ERR_LOST_PRECISION; } i = (int*)dest; *i = (int)value->data.dval; return PMIX_SUCCESS; } if (PMIX_INT8 == type) { if (127.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } else if (-128.0 > value->data.dval) { return PMIX_ERR_LOST_PRECISION; } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.dval; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (32767.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } else if (-32768.0 > value->data.dval) { return PMIX_ERR_LOST_PRECISION; } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.dval; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { if (2147483647.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } else if (-2147483648.0 > value->data.dval) { return PMIX_ERR_LOST_PRECISION; } i32 = (int32_t*)dest; *i32 = (int32_t)value->data.dval; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { if (18446744073709551000.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } else if (-9223372036854775808.0 > value->data.dval) { return PMIX_ERR_LOST_PRECISION; } i64 = (int64_t*)dest; *i64 = (int64_t)value->data.dval; return PMIX_SUCCESS; } if (PMIX_UINT == type) { if (42949670295.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } u = (unsigned int *)dest; *u = (unsigned int)value->data.dval; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (256.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.dval; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (65535.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.dval; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { if (4294967040.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.dval; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { if (18446744073709551000.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.dval; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { if (18446744073709551000.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } sz = (size_t*)dest; *sz = (size_t)value->data.dval; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { return PMIX_ERR_LOST_PRECISION; } if (PMIX_PROC_RANK == type) { // rank is an unsigned int if (4294967040.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } pr = (pmix_rank_t*)dest; *pr = (pmix_rank_t)value->data.dval; } if (PMIX_PID == type) { // pid_t is a signed int if (2147483647.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } else if (INT_MIN > value->data.dval) { return PMIX_ERR_LOST_PRECISION; } pid = (pid_t*)dest; *pid = (pid_t)value->data.dval; return PMIX_SUCCESS; } if (PMIX_STATUS == type) { // status is a signed int if (2147483647.0 < value->data.dval) { return PMIX_ERR_LOST_PRECISION; } else if (INT_MIN > value->data.dval) { return PMIX_ERR_LOST_PRECISION; } ps = (pmix_status_t*)dest; *ps = (pmix_status_t)value->data.dval; return PMIX_SUCCESS; } // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_rank(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *u; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; float *flt; double *dval; // rank is an unsigned int if (PMIX_INT == type) { if (INT_MAX < value->data.rank) { return PMIX_ERR_LOST_PRECISION; } i = (int*)dest; *i = (int)value->data.rank; return PMIX_SUCCESS; } if (PMIX_INT8 == type) { if (INT8_MAX < value->data.rank) { return PMIX_ERR_LOST_PRECISION; } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.rank; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (INT16_MAX < value->data.rank) { return PMIX_ERR_LOST_PRECISION; } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.rank; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { if (INT32_MAX < value->data.rank) { return PMIX_ERR_LOST_PRECISION; } i32 = (int32_t*)dest; *i32 = (int32_t)value->data.rank; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { i64 = (int64_t*)dest; *i64 = (int64_t)value->data.rank; return PMIX_SUCCESS; } if (PMIX_UINT == type) { u = (unsigned int *)dest; *u = (unsigned int)value->data.rank; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.rank) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.rank; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (UINT16_MAX < value->data.rank) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.rank; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { u32 = (uint32_t *)dest; *u32 = (uint32_t)value->data.rank; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t *)dest; *u64 = (uint64_t)value->data.rank; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.rank; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.rank; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dval = (double*)dest; *dval = (double)value->data.rank; return PMIX_SUCCESS; } // do not allow rank (a PMIx structured value) to be // unloaded into other PMIx structured value types // get here if the destination is a non-numerical type return PMIX_ERR_BAD_PARAM; } static pmix_status_t check_status(const pmix_value_t *value, void *dest, pmix_data_type_t type) { int *i; int8_t *i8; int16_t *i16; int32_t *i32; int64_t *i64; unsigned int *ui; uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; size_t *sz; float *flt; double *dbl; // check if this xfer would change sign if (0 > value->data.status) { if (PMIX_SIZE == type || PMIX_UINT == type || PMIX_UINT8 == type || PMIX_UINT16 == type || PMIX_UINT32 == type || PMIX_UINT64 == type) { return PMIX_ERR_CHANGE_SIGN; } } /* already took care of the negative value case when * transferring to unsigned types, and no loss of * precision if the dest is equal in size or larger */ if (PMIX_UINT == type) { ui = (unsigned int*)dest; *ui = (unsigned int)value->data.status; return PMIX_SUCCESS; } if (PMIX_INT == type) { // status is a signed int i = (int*)dest; *i = (int)value->data.status; return PMIX_SUCCESS; } if (PMIX_INT32 == type) { i32 = (int32_t*)dest; *i32 = (int32_t)value->data.status; return PMIX_SUCCESS; } if (PMIX_INT64 == type) { i64 = (int64_t*)dest; *i64 = (int64_t)value->data.status; return PMIX_SUCCESS; } if (PMIX_UINT64 == type) { u64 = (uint64_t*)dest; *u64 = (uint64_t)value->data.status; return PMIX_SUCCESS; } if (PMIX_SIZE == type) { sz = (size_t*)dest; *sz = (size_t)value->data.status; return PMIX_SUCCESS; } if (PMIX_FLOAT == type) { flt = (float*)dest; *flt = (float)value->data.status; return PMIX_SUCCESS; } if (PMIX_DOUBLE == type) { dbl = (double*)dest; *dbl = (double)value->data.status; return PMIX_SUCCESS; } // if we get here, then we are dealing with a smaller // destination, which means we can lose precision if (PMIX_INT8 == type) { if (0 < value->data.status) { if (INT8_MAX < value->data.status) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT8_MIN > value->data.status) { return PMIX_ERR_LOST_PRECISION; } } i8 = (int8_t*)dest; *i8 = (int8_t)value->data.status; return PMIX_SUCCESS; } if (PMIX_INT16 == type) { if (0 < value->data.status) { if (INT16_MAX < value->data.status) { return PMIX_ERR_LOST_PRECISION; } } else { if (INT16_MIN > value->data.status) { return PMIX_ERR_LOST_PRECISION; } } i16 = (int16_t*)dest; *i16 = (int16_t)value->data.status; return PMIX_SUCCESS; } if (PMIX_UINT8 == type) { if (UINT8_MAX < value->data.status) { return PMIX_ERR_LOST_PRECISION; } u8 = (uint8_t*)dest; *u8 = (uint8_t)value->data.status; return PMIX_SUCCESS; } if (PMIX_UINT16 == type) { if (UINT16_MAX < value->data.status) { return PMIX_ERR_LOST_PRECISION; } u16 = (uint16_t*)dest; *u16 = (uint16_t)value->data.status; return PMIX_SUCCESS; } if (PMIX_UINT32 == type) { u32 = (uint32_t*)dest; *u32 = (uint32_t)value->data.status; return PMIX_SUCCESS; } /* get here if the destination is a non-numerical type * or a mismatched structured type */ return PMIX_ERR_BAD_PARAM; } pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_fns.c0000664000175000017500000015254415203536752022360 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022 IBM Corporation. All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include "pmix.h" #include "src/include/pmix_globals.h" #include "src/mca/pcompress/pcompress.h" #include "src/mca/preg/preg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/bfrops/base/bfrop_base_tma.h" char* pmix_bfrops_base_get_components(void) { pmix_bfrops_base_active_module_t *mod; char *ptr, **list=NULL, *tmp; // cycle across the available components PMIX_LIST_FOREACH(mod, &pmix_bfrops_globals.actives, pmix_bfrops_base_active_module_t) { ptr = strrchr(mod->component->base.pmix_mca_component_name, 'v'); ++ptr; pmix_asprintf(&tmp, "PMIX_SERVER_URI%s", ptr); PMIx_Argv_append_nosize(&list, tmp); free(tmp); } tmp = PMIx_Argv_join(list, ':'); PMIx_Argv_free(list); return tmp; } void pmix_bfrops_base_value_load(pmix_value_t *v, const void *data, pmix_data_type_t type) { pmix_byte_object_t *bo; pmix_proc_info_t *pi; pmix_envar_t *envar; pmix_data_array_t *darray; pmix_status_t rc; pmix_coord_t *coord; pmix_regattr_t *regattr; pmix_topology_t *topo; pmix_cpuset_t *cpuset; pmix_geometry_t *geometry; pmix_endpoint_t *endpoint; pmix_device_t *device; pmix_resource_unit_t *resunit; pmix_device_distance_t *devdist; pmix_data_buffer_t *dbuf; pmix_nspace_t *nspace; pmix_node_pid_t *ndpidptr; v->type = type; if (NULL == data) { /* just set the fields to zero */ memset(&v->data, 0, sizeof(v->data)); if (PMIX_BOOL == type) { v->data.flag = true; // existence of the attribute indicates true unless specified different } } else { switch (type) { case PMIX_UNDEF: break; case PMIX_BOOL: memcpy(&(v->data.flag), data, 1); break; case PMIX_BYTE: memcpy(&(v->data.byte), data, 1); break; case PMIX_STRING: v->data.string = strdup(data); break; case PMIX_SIZE: memcpy(&(v->data.size), data, sizeof(size_t)); break; case PMIX_PID: memcpy(&(v->data.pid), data, sizeof(pid_t)); break; case PMIX_INT: memcpy(&(v->data.integer), data, sizeof(int)); break; case PMIX_INT8: memcpy(&(v->data.int8), data, 1); break; case PMIX_INT16: memcpy(&(v->data.int16), data, 2); break; case PMIX_INT32: memcpy(&(v->data.int32), data, 4); break; case PMIX_INT64: memcpy(&(v->data.int64), data, 8); break; case PMIX_UINT: memcpy(&(v->data.uint), data, sizeof(int)); break; case PMIX_UINT8: memcpy(&(v->data.uint8), data, 1); break; case PMIX_UINT16: case PMIX_STOR_ACCESS_TYPE: memcpy(&(v->data.uint16), data, 2); break; case PMIX_UINT32: memcpy(&(v->data.uint32), data, 4); break; case PMIX_UINT64: case PMIX_STOR_MEDIUM: case PMIX_STOR_ACCESS: case PMIX_STOR_PERSIST: memcpy(&(v->data.uint64), data, 8); break; case PMIX_FLOAT: memcpy(&(v->data.fval), data, sizeof(float)); break; case PMIX_DOUBLE: memcpy(&(v->data.dval), data, sizeof(double)); break; case PMIX_TIMEVAL: memcpy(&(v->data.tv), data, sizeof(struct timeval)); break; case PMIX_TIME: memcpy(&(v->data.time), data, sizeof(time_t)); break; case PMIX_STATUS: memcpy(&(v->data.status), data, sizeof(pmix_status_t)); break; case PMIX_PROC_RANK: memcpy(&(v->data.rank), data, sizeof(pmix_rank_t)); break; case PMIX_PROC_NSPACE: nspace = (pmix_nspace_t *) data; v->data.nspace = (pmix_nspace_t *) malloc(sizeof(pmix_nspace_t)); PMIX_LOAD_NSPACE(*(v->data.nspace), *nspace); break; case PMIX_PROC: PMIX_PROC_CREATE(v->data.proc, 1); if (NULL == v->data.proc) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } memcpy(v->data.proc, data, sizeof(pmix_proc_t)); break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: case PMIX_COMPRESSED_BYTE_OBJECT: bo = (pmix_byte_object_t *) data; v->data.bo.bytes = (char *) malloc(bo->size); if (NULL == v->data.bo.bytes) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } memcpy(v->data.bo.bytes, bo->bytes, bo->size); memcpy(&(v->data.bo.size), &bo->size, sizeof(size_t)); break; case PMIX_PERSIST: memcpy(&(v->data.persist), data, sizeof(pmix_persistence_t)); break; case PMIX_SCOPE: memcpy(&(v->data.scope), data, sizeof(pmix_scope_t)); break; case PMIX_DATA_RANGE: memcpy(&(v->data.range), data, sizeof(pmix_data_range_t)); break; case PMIX_PROC_STATE: memcpy(&(v->data.state), data, sizeof(pmix_proc_state_t)); break; case PMIX_PROC_INFO: PMIX_PROC_INFO_CREATE(v->data.pinfo, 1); if (NULL == v->data.pinfo) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } pi = (pmix_proc_info_t *) data; memcpy(&(v->data.pinfo->proc), &pi->proc, sizeof(pmix_proc_t)); if (NULL != pi->hostname) { v->data.pinfo->hostname = strdup(pi->hostname); } if (NULL != pi->executable_name) { v->data.pinfo->executable_name = strdup(pi->executable_name); } memcpy(&(v->data.pinfo->pid), &pi->pid, sizeof(pid_t)); memcpy(&(v->data.pinfo->exit_code), &pi->exit_code, sizeof(int)); break; case PMIX_DATA_ARRAY: darray = (pmix_data_array_t *) data; rc = pmix_bfrops_base_copy_darray(&v->data.darray, darray, PMIX_DATA_ARRAY); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; case PMIX_POINTER: v->data.ptr = (void *) data; break; case PMIX_ALLOC_DIRECTIVE: memcpy(&(v->data.adir), data, sizeof(pmix_alloc_directive_t)); break; case PMIX_RESBLOCK_DIRECTIVE: memcpy(&(v->data.rbdir), data, sizeof(pmix_resource_block_directive_t)); break; case PMIX_ENVAR: envar = (pmix_envar_t *) data; if (NULL != envar->envar) { v->data.envar.envar = strdup(envar->envar); } if (NULL != envar->value) { v->data.envar.value = strdup(envar->value); } v->data.envar.separator = envar->separator; break; case PMIX_COORD: coord = (pmix_coord_t *) data; rc = pmix_bfrops_base_copy_coord(&v->data.coord, coord, PMIX_COORD); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; case PMIX_LINK_STATE: memcpy(&(v->data.linkstate), data, sizeof(pmix_link_state_t)); break; case PMIX_JOB_STATE: memcpy(&(v->data.jstate), data, sizeof(pmix_job_state_t)); break; case PMIX_TOPO: topo = (pmix_topology_t *) data; rc = pmix_bfrops_base_copy_topology(&v->data.topo, topo, PMIX_TOPO); if (PMIX_ERR_INIT == rc || PMIX_ERR_NOT_SUPPORTED == rc) { /* we are not initialized yet, so just copy the pointer */ v->data.topo = topo; rc = PMIX_SUCCESS; } break; case PMIX_PROC_CPUSET: cpuset = (pmix_cpuset_t *) data; rc = pmix_bfrops_base_copy_cpuset(&v->data.cpuset, cpuset, PMIX_PROC_CPUSET); if (PMIX_ERR_INIT == rc || PMIX_ERR_NOT_SUPPORTED == rc) { /* we are not initialized yet, so just copy the pointer */ v->data.cpuset = cpuset; rc = PMIX_SUCCESS; } break; case PMIX_LOCTYPE: memcpy(&(v->data.locality), data, sizeof(pmix_locality_t)); break; case PMIX_GEOMETRY: geometry = (pmix_geometry_t *) data; rc = pmix_bfrops_base_copy_geometry(&v->data.geometry, geometry, PMIX_GEOMETRY); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; case PMIX_DEVTYPE: memcpy(&(v->data.devtype), data, sizeof(pmix_device_type_t)); break; case PMIX_DEVICE: device = (pmix_device_t *) data; rc = pmix_bfrops_base_copy_device(&v->data.device, device, PMIX_DEVICE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; case PMIX_RESOURCE_UNIT: resunit = (pmix_resource_unit_t *) data; rc = pmix_bfrops_base_copy_resunit(&v->data.resunit, resunit, PMIX_RESOURCE_UNIT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; case PMIX_DEVICE_DIST: devdist = (pmix_device_distance_t *) data; rc = pmix_bfrops_base_copy_devdist(&v->data.devdist, devdist, PMIX_DEVICE_DIST); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; case PMIX_ENDPOINT: endpoint = (pmix_endpoint_t *) data; rc = pmix_bfrops_base_copy_endpoint(&v->data.endpoint, endpoint, PMIX_ENDPOINT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; case PMIX_REGATTR: regattr = (pmix_regattr_t *) data; rc = pmix_bfrops_base_copy_regattr((pmix_regattr_t **) &v->data.ptr, regattr, PMIX_REGATTR); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; case PMIX_REGEX: /* load it into the byte object */ rc = pmix_preg.copy(&v->data.bo.bytes, &v->data.bo.size, (char *) data); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; case PMIX_DATA_BUFFER: dbuf = (pmix_data_buffer_t *) data; PMIX_DATA_BUFFER_CREATE(v->data.dbuf); rc = PMIx_Data_copy_payload(v->data.dbuf, dbuf); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; case PMIX_NODE_PID: ndpidptr = (pmix_node_pid_t*)data; rc = pmix_bfrops_base_copy_nodepid(&v->data.nodepid, ndpidptr, PMIX_NODE_PID); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } break; default: /* silence warnings */ break; } } return; } pmix_status_t pmix_bfrops_base_value_unload(pmix_value_t *kv, void **data, size_t *sz) { pmix_status_t rc; pmix_envar_t *envar; pmix_data_array_t **darray; pmix_regattr_t *regattr, *r; pmix_node_pid_t *ndpidptr, *ndpd; int n; pmix_data_type_t simple[] = { PMIX_BOOL, PMIX_BYTE, PMIX_SIZE, PMIX_PID, PMIX_INT, PMIX_INT8, PMIX_INT16, PMIX_INT32, PMIX_INT64, PMIX_UINT, PMIX_UINT8, PMIX_UINT16, PMIX_UINT32, PMIX_UINT64, PMIX_FLOAT, PMIX_DOUBLE, PMIX_STATUS, PMIX_PROC_NSPACE, PMIX_PROC_RANK, PMIX_STOR_ACCESS_TYPE, PMIX_STOR_MEDIUM, PMIX_STOR_ACCESS, PMIX_STOR_PERSIST, PMIX_TIMEVAL, PMIX_TIME, PMIX_PROC, PMIX_PERSIST, PMIX_SCOPE, PMIX_DATA_RANGE, PMIX_PROC_STATE, PMIX_POINTER, PMIX_ALLOC_DIRECTIVE, PMIX_LINK_STATE, PMIX_LOCTYPE, PMIX_DEVTYPE, PMIX_UNDEF }; rc = PMIX_SUCCESS; if (NULL == data) { return PMIX_ERR_BAD_PARAM; } if (NULL == *data) { // if the value contains a simple data type, then this is an error for (n=0; PMIX_UNDEF != simple[n]; n++) { if (kv->type == simple[n]) { return PMIX_ERR_BAD_PARAM; } } } switch (kv->type) { case PMIX_UNDEF: rc = PMIX_ERR_UNKNOWN_DATA_TYPE; break; case PMIX_BOOL: memcpy(*data, &(kv->data.flag), sizeof(bool)); *sz = sizeof(bool); break; case PMIX_BYTE: memcpy(*data, &(kv->data.byte), sizeof(uint8_t)); *sz = sizeof(uint8_t); break; case PMIX_STRING: if (NULL != kv->data.string) { *data = strdup(kv->data.string); *sz = strlen(kv->data.string); } break; case PMIX_SIZE: memcpy(*data, &(kv->data.size), sizeof(size_t)); *sz = sizeof(size_t); break; case PMIX_PID: memcpy(*data, &(kv->data.pid), sizeof(pid_t)); *sz = sizeof(pid_t); break; case PMIX_UINT: case PMIX_INT: memcpy(*data, &(kv->data.integer), sizeof(int)); *sz = sizeof(int); break; case PMIX_UINT8: case PMIX_INT8: memcpy(*data, &(kv->data.int8), sizeof(int8_t)); *sz = sizeof(int8_t); break; case PMIX_UINT16: case PMIX_INT16: case PMIX_STOR_ACCESS_TYPE: memcpy(*data, &(kv->data.int16), sizeof(int16_t)); *sz = sizeof(int16_t); break; case PMIX_UINT32: case PMIX_INT32: memcpy(*data, &(kv->data.int32), sizeof(int32_t)); *sz = sizeof(int32_t); break; case PMIX_UINT64: case PMIX_INT64: case PMIX_STOR_MEDIUM: case PMIX_STOR_ACCESS: case PMIX_STOR_PERSIST: memcpy(*data, &(kv->data.int64), sizeof(int64_t)); *sz = sizeof(int64_t); break; case PMIX_FLOAT: memcpy(*data, &(kv->data.fval), sizeof(float)); *sz = sizeof(float); break; case PMIX_DOUBLE: memcpy(*data, &(kv->data.dval), sizeof(double)); *sz = sizeof(double); break; case PMIX_TIMEVAL: memcpy(*data, &(kv->data.tv), sizeof(struct timeval)); *sz = sizeof(struct timeval); break; case PMIX_TIME: memcpy(*data, &(kv->data.time), sizeof(time_t)); *sz = sizeof(time_t); break; case PMIX_STATUS: memcpy(*data, &(kv->data.status), sizeof(pmix_status_t)); *sz = sizeof(pmix_status_t); break; case PMIX_PROC_RANK: memcpy(*data, &(kv->data.rank), sizeof(pmix_rank_t)); *sz = sizeof(pmix_rank_t); break; case PMIX_PROC_NSPACE: PMIX_LOAD_NSPACE(*data, *kv->data.nspace); *sz = strlen(*kv->data.nspace); break; case PMIX_PROC: PMIX_XFER_PROCID(*data, kv->data.proc); *sz = sizeof(pmix_proc_t); break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: case PMIX_COMPRESSED_BYTE_OBJECT: case PMIX_REGEX: if (NULL != kv->data.bo.bytes && 0 < kv->data.bo.size) { rc = pmix_bfrops_base_copy_bo((pmix_byte_object_t**)data, &kv->data.bo, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_byte_object_t); } else { *data = NULL; *sz = 0; } } else { *data = NULL; *sz = 0; } break; case PMIX_PERSIST: memcpy(*data, &(kv->data.persist), sizeof(pmix_persistence_t)); *sz = sizeof(pmix_persistence_t); break; case PMIX_SCOPE: memcpy(*data, &(kv->data.scope), sizeof(pmix_scope_t)); *sz = sizeof(pmix_scope_t); break; case PMIX_DATA_RANGE: memcpy(*data, &(kv->data.range), sizeof(pmix_data_range_t)); *sz = sizeof(pmix_data_range_t); break; case PMIX_PROC_STATE: memcpy(*data, &(kv->data.state), sizeof(pmix_proc_state_t)); *sz = sizeof(pmix_proc_state_t); break; case PMIX_PROC_INFO: rc = pmix_bfrops_base_copy_pinfo((pmix_proc_info_t **) data, kv->data.pinfo, PMIX_PROC_INFO); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_proc_info_t); } break; case PMIX_DATA_ARRAY: darray = (pmix_data_array_t **) data; rc = pmix_bfrops_base_copy_darray(darray, kv->data.darray, PMIX_DATA_ARRAY); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_data_array_t); } break; case PMIX_POINTER: *data = (void *) kv->data.ptr; *sz = sizeof(void *); break; case PMIX_ALLOC_DIRECTIVE: memcpy(*data, &(kv->data.adir), sizeof(pmix_alloc_directive_t)); *sz = sizeof(pmix_alloc_directive_t); break; case PMIX_RESBLOCK_DIRECTIVE: memcpy(*data, &(kv->data.rbdir), sizeof(pmix_resource_block_directive_t)); *sz = sizeof(pmix_resource_block_directive_t); break; case PMIX_ENVAR: PMIX_ENVAR_CREATE(envar, 1); if (NULL == envar) { return PMIX_ERR_NOMEM; } if (NULL != kv->data.envar.envar) { envar->envar = strdup(kv->data.envar.envar); } if (NULL != kv->data.envar.value) { envar->value = strdup(kv->data.envar.value); } envar->separator = kv->data.envar.separator; *data = envar; *sz = sizeof(pmix_envar_t); break; case PMIX_COORD: rc = pmix_bfrops_base_copy_coord((pmix_coord_t **) data, kv->data.coord, PMIX_COORD); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_coord_t); } break; case PMIX_LINK_STATE: memcpy(*data, &(kv->data.linkstate), sizeof(pmix_link_state_t)); *sz = sizeof(pmix_link_state_t); break; case PMIX_JOB_STATE: memcpy(*data, &(kv->data.jstate), sizeof(pmix_job_state_t)); *sz = sizeof(pmix_job_state_t); break; case PMIX_TOPO: rc = pmix_bfrops_base_copy_topology((pmix_topology_t **) data, kv->data.topo, PMIX_TOPO); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_topology_t); } else if (PMIX_ERR_INIT == rc || PMIX_ERR_NOT_SUPPORTED == rc) { *data = malloc(sizeof(pmix_topology_t)); memcpy(*data, kv->data.topo, sizeof(pmix_topology_t)); *sz = sizeof(pmix_topology_t); rc = PMIX_SUCCESS; } break; case PMIX_PROC_CPUSET: rc = pmix_bfrops_base_copy_cpuset((pmix_cpuset_t **) data, kv->data.cpuset, PMIX_PROC_CPUSET); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_cpuset_t); } else if (PMIX_ERR_INIT == rc || PMIX_ERR_NOT_SUPPORTED == rc) { *data = malloc(sizeof(pmix_cpuset_t)); memcpy(*data, kv->data.cpuset, sizeof(pmix_cpuset_t)); *sz = sizeof(pmix_cpuset_t); rc = PMIX_SUCCESS; } break; case PMIX_LOCTYPE: memcpy(*data, &(kv->data.locality), sizeof(pmix_locality_t)); *sz = sizeof(pmix_locality_t); break; case PMIX_GEOMETRY: rc = pmix_bfrops_base_copy_geometry((pmix_geometry_t **) data, kv->data.geometry, PMIX_GEOMETRY); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_geometry_t); } break; case PMIX_DEVTYPE: memcpy(*data, &(kv->data.devtype), sizeof(pmix_device_type_t)); *sz = sizeof(pmix_device_type_t); break; case PMIX_DEVICE: rc = pmix_bfrops_base_copy_device((pmix_device_t **) data, kv->data.device, PMIX_DEVICE); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_device_t); } break; case PMIX_RESOURCE_UNIT: rc = pmix_bfrops_base_copy_resunit((pmix_resource_unit_t **) data, kv->data.resunit, PMIX_RESOURCE_UNIT); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_resource_unit_t); } break; case PMIX_DEVICE_DIST: rc = pmix_bfrops_base_copy_devdist((pmix_device_distance_t **) data, kv->data.devdist, PMIX_DEVICE_DIST); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_device_distance_t); } break; case PMIX_ENDPOINT: rc = pmix_bfrops_base_copy_endpoint((pmix_endpoint_t **) data, kv->data.endpoint, PMIX_ENDPOINT); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_endpoint_t); } break; case PMIX_REGATTR: PMIX_REGATTR_CREATE(regattr, 1); if (NULL == regattr) { return PMIX_ERR_NOMEM; } r = (pmix_regattr_t *) kv->data.ptr; if (NULL != r->name) { regattr->name = strdup(r->name); } PMIX_LOAD_KEY(regattr->string, r->string); regattr->type = r->type; regattr->description = PMIx_Argv_copy(r->description); *data = regattr; *sz = sizeof(pmix_regattr_t); break; case PMIX_DATA_BUFFER: rc = pmix_bfrops_base_copy_dbuf((pmix_data_buffer_t **) data, kv->data.dbuf, PMIX_DATA_BUFFER); if (PMIX_SUCCESS == rc) { *sz = sizeof(pmix_data_buffer_t); } break; case PMIX_NODE_PID: ndpidptr = PMIx_Node_pid_create(1); if (NULL == ndpidptr) { return PMIX_ERR_NOMEM; } ndpd = (pmix_node_pid_t*)kv->data.nodepid; if (NULL != ndpd->hostname) { ndpidptr->hostname = strdup(ndpd->hostname); } ndpidptr->nodeid = ndpd->nodeid; ndpidptr->pid = ndpd->pid; *data = ndpidptr; *sz = sizeof(pmix_node_pid_t); break; default: /* silence warnings */ rc = PMIX_ERROR; break; } return rc; } void pmix_bfrops_base_darray_destruct(pmix_data_array_t *d) { pmix_bfrops_base_tma_data_array_destruct(d, NULL); } void pmix_bfrops_base_value_destruct(pmix_value_t *v) { pmix_bfrops_base_tma_value_destruct(v, NULL); } /* Xfer FUNCTIONS FOR GENERIC PMIX TYPES */ pmix_status_t pmix_bfrops_base_value_xfer(pmix_value_t *p, const pmix_value_t *src) { return pmix_bfrops_base_tma_value_xfer(p, src, NULL); } /** * Internal function that resizes (expands) an inuse buffer if * necessary. */ char *pmix_bfrop_buffer_extend(pmix_buffer_t *buffer, size_t bytes_to_add) { return pmix_bfrops_base_tma_buffer_extend(buffer, bytes_to_add, NULL); } /* * Internal function that checks to see if the specified number of bytes * remain in the buffer for unpacking */ bool pmix_bfrop_too_small(pmix_buffer_t *buffer, size_t bytes_reqd) { size_t bytes_remaining_packed; if (buffer->pack_ptr < buffer->unpack_ptr) { return true; } bytes_remaining_packed = buffer->pack_ptr - buffer->unpack_ptr; if (bytes_remaining_packed < bytes_reqd) { /* don't error log this - it could be that someone is trying to * simply read until the buffer is empty */ return true; } return false; } pmix_status_t pmix_bfrop_store_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t type) { pmix_status_t ret; PMIX_BFROPS_PACK_TYPE(ret, buffer, &type, 1, PMIX_UINT16, regtypes); return ret; } pmix_status_t pmix_bfrop_get_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t *type) { pmix_status_t ret; int32_t m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, type, &m, PMIX_UINT16, regtypes); return ret; } const char *pmix_bfrops_base_data_type_string(pmix_pointer_array_t *regtypes, pmix_data_type_t type) { pmix_bfrop_type_info_t *info; /* Lookup the object for this type and call it */ if (NULL == (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(regtypes, type))) { return NULL; } return info->odti_name; } PMIX_EXPORT void *PMIx_Info_list_start(void) { pmix_list_t *p; p = PMIX_NEW(pmix_list_t); return p; } PMIX_EXPORT pmix_status_t PMIx_Info_list_add(void *ptr, const char *key, const void *value, pmix_data_type_t type) { pmix_list_t *p = (pmix_list_t *) ptr; pmix_infolist_t *iptr; iptr = PMIX_NEW(pmix_infolist_t); if (NULL == iptr) { return PMIX_ERR_NOMEM; } PMIX_INFO_LOAD(&iptr->info, key, value, type); pmix_list_append(p, &iptr->super); return PMIX_SUCCESS; } pmix_status_t PMIx_Info_list_add_unique(void *ptr, const char *key, const void *value, pmix_data_type_t type, bool overwrite) { pmix_list_t *p = (pmix_list_t *) ptr; pmix_infolist_t *iptr; // see if this key is already on the list PMIX_LIST_FOREACH(iptr, p, pmix_infolist_t) { if (PMIX_CHECK_KEY(&iptr->info, key)) { if (overwrite) { // replace with new value PMIx_Value_destruct(&iptr->info.value); PMIx_Value_load(&iptr->info.value, value, type); } return PMIX_SUCCESS; } } iptr = PMIX_NEW(pmix_infolist_t); if (NULL == iptr) { return PMIX_ERR_NOMEM; } PMIX_INFO_LOAD(&iptr->info, key, value, type); pmix_list_append(p, &iptr->super); return PMIX_SUCCESS; } PMIX_EXPORT pmix_status_t PMIx_Info_list_add_value(void *ptr, const char *key, const pmix_value_t *value) { pmix_list_t *p = (pmix_list_t *) ptr; pmix_infolist_t *iptr; pmix_status_t rc; iptr = PMIX_NEW(pmix_infolist_t); if (NULL == iptr) { return PMIX_ERR_NOMEM; } PMIX_LOAD_KEY(iptr->info.key, key); rc = PMIx_Value_xfer(&iptr->info.value, value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(iptr); return rc; } pmix_list_append(p, &iptr->super); return PMIX_SUCCESS; } PMIX_EXPORT pmix_status_t PMIx_Info_list_add_value_unique(void *ptr, const char *key, const pmix_value_t *value, bool overwrite) { pmix_list_t *p = (pmix_list_t *) ptr; pmix_infolist_t *iptr; pmix_status_t rc; // see if this key is already on the list PMIX_LIST_FOREACH(iptr, p, pmix_infolist_t) { if (PMIX_CHECK_KEY(&iptr->info, key)) { if (overwrite) { // replace with new value PMIx_Value_destruct(&iptr->info.value); PMIx_Value_xfer(&iptr->info.value, value); } return PMIX_SUCCESS; } } iptr = PMIX_NEW(pmix_infolist_t); if (NULL == iptr) { return PMIX_ERR_NOMEM; } PMIX_LOAD_KEY(iptr->info.key, key); rc = PMIx_Value_xfer(&iptr->info.value, value); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(iptr); return rc; } pmix_list_append(p, &iptr->super); return PMIX_SUCCESS; } pmix_status_t PMIx_Info_list_prepend(void *ptr, const char *key, const void *value, pmix_data_type_t type) { pmix_list_t *p = (pmix_list_t *) ptr; pmix_infolist_t *iptr; iptr = PMIX_NEW(pmix_infolist_t); if (NULL == iptr) { return PMIX_ERR_NOMEM; } PMIX_INFO_LOAD(&iptr->info, key, value, type); pmix_list_prepend(p, &iptr->super); return PMIX_SUCCESS; } PMIX_EXPORT pmix_status_t PMIx_Info_list_insert(void *ptr, pmix_info_t *info) { pmix_list_t *p = (pmix_list_t *) ptr; pmix_infolist_t *iptr; iptr = PMIX_NEW(pmix_infolist_t); if (NULL == iptr) { return PMIX_ERR_NOMEM; } /* we want to preserve any pointers in the provided * info struct so the result points to the same * memory location */ memcpy(&iptr->info, info, sizeof(pmix_info_t)); // mark that this value should not be released PMIX_INFO_SET_PERSISTENT(&iptr->info); pmix_list_append(p, &iptr->super); return PMIX_SUCCESS; } PMIX_EXPORT pmix_status_t PMIx_Info_list_xfer(void *ptr, const pmix_info_t *info) { pmix_list_t *p = (pmix_list_t *) ptr; pmix_infolist_t *iptr; iptr = PMIX_NEW(pmix_infolist_t); if (NULL == iptr) { return PMIX_ERR_NOMEM; } PMIx_Info_xfer(&iptr->info, info); pmix_list_append(p, &iptr->super); return PMIX_SUCCESS; } PMIX_EXPORT pmix_status_t PMIx_Info_list_xfer_unique(void *ptr, const pmix_info_t *info, bool overwrite) { pmix_list_t *p = (pmix_list_t *) ptr; pmix_infolist_t *iptr; pmix_status_t rc; // see if this key is already on the list PMIX_LIST_FOREACH(iptr, p, pmix_infolist_t) { if (PMIX_CHECK_KEY(&iptr->info, info->key)) { if (overwrite) { // replace with new value PMIx_Value_destruct(&iptr->info.value); PMIx_Value_xfer(&iptr->info.value, &info->value); } return PMIX_SUCCESS; } } iptr = PMIX_NEW(pmix_infolist_t); if (NULL == iptr) { return PMIX_ERR_NOMEM; } rc = PMIx_Info_xfer(&iptr->info, info); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(iptr); return rc; } pmix_list_append(p, &iptr->super); return PMIX_SUCCESS; } PMIX_EXPORT pmix_status_t PMIx_Info_list_convert(void *ptr, pmix_data_array_t *par) { pmix_list_t *p = (pmix_list_t *) ptr; size_t n; pmix_infolist_t *iptr; pmix_info_t *array; if (NULL == par || NULL == ptr) { return PMIX_ERR_BAD_PARAM; } PMIX_DATA_ARRAY_INIT(par, PMIX_INFO); n = pmix_list_get_size(p); if (0 == n) { return PMIX_ERR_EMPTY; } PMIX_INFO_CREATE(par->array, n); if (NULL == par->array) { return PMIX_ERR_NOMEM; } par->type = PMIX_INFO; par->size = n; array = (pmix_info_t *) par->array; /* transfer the elements across */ n = 0; PMIX_LIST_FOREACH (iptr, p, pmix_infolist_t) { PMIx_Info_xfer(&array[n], &iptr->info); ++n; } return PMIX_SUCCESS; } PMIX_EXPORT void PMIx_Info_list_release(void *ptr) { pmix_list_t *p = (pmix_list_t *) ptr; PMIX_LIST_RELEASE(p); } pmix_info_t* PMIx_Info_list_get_info(void *ptr, void *prev, void **next) { pmix_list_t *p = (pmix_list_t *) ptr; pmix_list_item_t *prv = (pmix_list_item_t*)prev; pmix_infolist_t *active; if (NULL == prev) { prv = pmix_list_get_first(p); active = (pmix_infolist_t*)prv; } else { active = (pmix_infolist_t*)prv; } if (prv == pmix_list_get_last(p)) { *next = NULL; } else { *next = (void*)pmix_list_get_next(prv); } return &active->info; } size_t PMIx_Info_list_get_size(void *ptr) { pmix_list_t *p = (pmix_list_t *) ptr; return pmix_list_get_size(p); } static pmix_status_t get_darray_size(pmix_data_array_t *array, size_t *sz) { pmix_status_t rc = PMIX_SUCCESS; size_t m, n, sz2; char **str; pmix_byte_object_t *bo; pmix_proc_info_t *pi; pmix_envar_t *en; pmix_coord_t *coord; pmix_topology_t *topo; pmix_cpuset_t *cset; pmix_geometry_t *geo; pmix_device_t *dev; pmix_device_distance_t *dd; pmix_endpoint_t *endpt; pmix_regattr_t *rg; pmix_data_buffer_t *db; pmix_info_t *iptr; pmix_node_pid_t *ndpd; switch (array->type) { case PMIX_UNDEF: rc = PMIX_ERR_UNKNOWN_DATA_TYPE; break; case PMIX_BOOL: case PMIX_BYTE: case PMIX_INT8: case PMIX_UINT8: *sz = array->size; break; case PMIX_STRING: *sz = array->size * sizeof(void*); str = (char**)array->array; for (n=0; n < array->size; n++) { *sz += 1; if (NULL != str[n]) { *sz += strlen(str[n]); } } break; case PMIX_SIZE: *sz = array->size * sizeof(size_t); break; case PMIX_PID: *sz = array->size * sizeof(pid_t); break; case PMIX_INT: case PMIX_UINT: *sz = array->size * sizeof(int); break; case PMIX_INT16: case PMIX_UINT16: case PMIX_STOR_ACCESS_TYPE: *sz = array->size * 2; break; case PMIX_INT32: case PMIX_UINT32: *sz = array->size * 4; break; case PMIX_INT64: case PMIX_UINT64: case PMIX_STOR_MEDIUM: case PMIX_STOR_ACCESS: case PMIX_STOR_PERSIST: *sz = array->size * 8; break; case PMIX_FLOAT: *sz = array->size * sizeof(float); break; case PMIX_DOUBLE: *sz = array->size * sizeof(double); break; case PMIX_TIMEVAL: *sz = array->size * sizeof(struct timeval); break; case PMIX_TIME: *sz = array->size * sizeof(time_t); break; case PMIX_STATUS: *sz = array->size * sizeof(pmix_status_t); break; case PMIX_PROC_RANK: *sz = array->size * sizeof(pmix_rank_t); break; case PMIX_PROC_NSPACE: *sz = array->size * PMIX_MAX_NSLEN; break; case PMIX_PROC: *sz = array->size * sizeof(pmix_proc_t); break; case PMIX_INFO: iptr = (pmix_info_t*)array->array; for (n=0; n < array->size; n++) { rc = PMIx_Info_get_size(&iptr[n], &sz2); if (PMIX_SUCCESS == rc) { *sz += sz2; } else { return rc; } } break; case PMIX_BYTE_OBJECT: *sz = array->size * sizeof(pmix_byte_object_t); bo = (pmix_byte_object_t*)array->array; for (n=0; n < array->size; n++) { *sz += bo[n].size; } break; case PMIX_COMPRESSED_STRING: *sz = array->size * sizeof(void*); bo = (pmix_byte_object_t*)array->array; for (n=0; n < array->size; n++) { *sz += pmix_compress.get_decompressed_strlen(&bo[n]); } break; case PMIX_COMPRESSED_BYTE_OBJECT: *sz = array->size * sizeof(void*); bo = (pmix_byte_object_t*)array->array; for (n=0; n < array->size; n++) { *sz += pmix_compress.get_decompressed_size(&bo[n]); } break; case PMIX_PERSIST: *sz = array->size * sizeof(pmix_persistence_t); break; case PMIX_SCOPE: *sz = array->size * sizeof(pmix_scope_t); break; case PMIX_DATA_RANGE: *sz = array->size * sizeof(pmix_data_range_t); break; case PMIX_PROC_STATE: *sz = array->size * sizeof(pmix_proc_state_t); break; case PMIX_PROC_INFO: *sz = array->size * sizeof(pmix_proc_info_t); pi = (pmix_proc_info_t*)array->array; for (n=0; n < array->size; n++) { *sz += 1; if (NULL != pi[n].hostname) { *sz += strlen(pi[n].hostname); } *sz += 1; if (NULL != pi[n].executable_name) { *sz += strlen(pi[n].executable_name); } } break; case PMIX_DATA_ARRAY: rc = PMIX_ERR_NOT_SUPPORTED; break; case PMIX_POINTER: *sz = array->size * sizeof(void *); break; case PMIX_ALLOC_DIRECTIVE: *sz = array->size * sizeof(pmix_alloc_directive_t); break; case PMIX_RESBLOCK_DIRECTIVE: *sz = array->size * sizeof(pmix_resource_block_directive_t); break; case PMIX_ENVAR: *sz = array->size * sizeof(pmix_envar_t); en = (pmix_envar_t*)array->array; for (n=0; n < array->size; n++) { *sz += 1; if (NULL != en[n].envar) { *sz += strlen(en[n].envar); } *sz += 1; if (NULL != en[n].value) { *sz += strlen(en[n].value); } } break; case PMIX_COORD: *sz = array->size * sizeof(pmix_coord_t); coord = (pmix_coord_t*)array->array; for (n=0; n < array->size; n++) { if (0 < coord[n].dims) { *sz += coord[n].dims * sizeof(uint32_t); } } break; case PMIX_LINK_STATE: *sz = array->size * sizeof(pmix_link_state_t); break; case PMIX_JOB_STATE: *sz = array->size * sizeof(pmix_job_state_t); break; case PMIX_TOPO: *sz = array->size * sizeof(pmix_topology_t); topo = (pmix_topology_t*)array->array; for (n=0; n < array->size; n++) { rc = pmix_hwloc_get_topology_size(&topo[n], &sz2); if (PMIX_SUCCESS == rc) { *sz += sz2; } else { return rc; } } break; case PMIX_PROC_CPUSET: *sz = array->size * sizeof(pmix_cpuset_t); cset = (pmix_cpuset_t*)array->array; for (n=0; n < array->size; n++) { rc = pmix_hwloc_get_cpuset_size(&cset[n], &sz2); if (PMIX_SUCCESS == rc) { *sz += sz2; } else { return rc; } } break; case PMIX_LOCTYPE: *sz = array->size * sizeof(pmix_locality_t); break; case PMIX_GEOMETRY: *sz = array->size * sizeof(pmix_geometry_t); geo = (pmix_geometry_t*)array->array; for (m=0; m < array->size; m++) { *sz += 1; if (NULL != geo[m].uuid) { *sz += strlen(geo[m].uuid); } *sz += 1; if (NULL != geo[m].osname) { *sz += strlen(geo[m].osname); } for (n=0; n < geo[m].ncoords; n++) { *sz += sizeof(pmix_coord_t); if (0 < geo[m].coordinates[n].dims) { *sz += geo[m].coordinates[n].dims * sizeof(uint32_t); } } } break; case PMIX_DEVTYPE: *sz = array->size * sizeof(pmix_device_type_t); break; case PMIX_DEVICE: *sz = array->size * sizeof(pmix_device_t); dev = (pmix_device_t*)array->array; for (n=0; n < array->size; n++) { *sz += 1; if (NULL != dev[n].uuid) { *sz += strlen(dev[n].uuid); } *sz += 1; if (NULL != dev[n].osname) { *sz += strlen(dev[n].osname); } } break; case PMIX_RESOURCE_UNIT: *sz = array->size * sizeof(pmix_resource_unit_t); break; case PMIX_DEVICE_DIST: *sz = array->size * sizeof(pmix_device_distance_t); dd = (pmix_device_distance_t*)array->array; for (n=0; n < array->size; n++) { *sz += 1; if (NULL != dd[n].uuid) { *sz += strlen(dd[n].uuid); } *sz += 1; if (NULL != dd[n].osname) { *sz += strlen(dd[n].osname); } } break; case PMIX_ENDPOINT: *sz = array->size * sizeof(pmix_endpoint_t); endpt = (pmix_endpoint_t*)array->array; for (n=0; n < array->size; n++) { *sz += 1; if (NULL != endpt[n].uuid) { *sz += strlen(endpt[n].uuid); } *sz += 1; if (NULL != endpt[n].osname) { *sz += strlen(endpt[n].osname); } *sz += endpt[n].endpt.size; } break; case PMIX_REGATTR: *sz = array->size * sizeof(pmix_regattr_t); rg = (pmix_regattr_t*)array->array; for (n=0; n < array->size; n++) { *sz += 1; if (NULL != rg[n].name) { *sz += strlen(rg[n].name); } if (NULL != rg[n].description) { for (m=0; NULL != rg[n].description[m]; m++) { *sz += 1; *sz += strlen(rg[n].description[m]); } } } break; case PMIX_REGEX: *sz = array->size * sizeof(pmix_byte_object_t); bo = (pmix_byte_object_t*)array->array; for (n=0; n < array->size; n++) { *sz += bo[n].size; } break; case PMIX_DATA_BUFFER: *sz = array->size * sizeof(pmix_data_buffer_t); db = (pmix_data_buffer_t*)array->array; for (n=0; n < array->size; n++) { *sz += db[n].bytes_used; } break; case PMIX_NODE_PID: *sz = array->size * sizeof(pmix_node_pid_t); ndpd = (pmix_node_pid_t*)array->array; for (n=0; n < array->size; n++) { if (NULL != ndpd[n].hostname) { *sz += strlen(ndpd[n].hostname) + 1; // account for NULL } } break; default: /* silence warnings */ break; } return PMIX_SUCCESS; } pmix_status_t PMIx_Value_get_size(const pmix_value_t *v, size_t *sz) { pmix_status_t rc = PMIX_SUCCESS; size_t n; pmix_regattr_t *regattr; pmix_node_pid_t *ndpd; switch (v->type) { case PMIX_UNDEF: rc = PMIX_ERR_UNKNOWN_DATA_TYPE; break; case PMIX_BOOL: case PMIX_BYTE: case PMIX_INT8: case PMIX_UINT8: *sz = 1; break; case PMIX_STRING: *sz = 1; if (NULL != v->data.string) { *sz += strlen(v->data.string); } break; case PMIX_SIZE: *sz = sizeof(size_t); break; case PMIX_PID: *sz = sizeof(pid_t); break; case PMIX_INT: case PMIX_UINT: *sz = sizeof(int); break; case PMIX_INT16: case PMIX_UINT16: case PMIX_STOR_ACCESS_TYPE: *sz = 2; break; case PMIX_INT32: case PMIX_UINT32: *sz = 4; break; case PMIX_INT64: case PMIX_UINT64: case PMIX_STOR_MEDIUM: case PMIX_STOR_ACCESS: case PMIX_STOR_PERSIST: *sz = 8; break; case PMIX_FLOAT: *sz = sizeof(float); break; case PMIX_DOUBLE: *sz = sizeof(double); break; case PMIX_TIMEVAL: *sz = sizeof(struct timeval); break; case PMIX_TIME: *sz = sizeof(time_t); break; case PMIX_STATUS: *sz = sizeof(pmix_status_t); break; case PMIX_PROC_RANK: *sz = sizeof(pmix_rank_t); break; case PMIX_PROC_NSPACE: *sz = PMIX_MAX_NSLEN; break; case PMIX_PROC: *sz = sizeof(pmix_proc_t); break; case PMIX_BYTE_OBJECT: *sz = sizeof(pmix_byte_object_t); if (NULL != v->data.bo.bytes) { *sz += v->data.bo.size; } break; case PMIX_COMPRESSED_STRING: *sz = pmix_compress.get_decompressed_strlen(&v->data.bo); break; case PMIX_COMPRESSED_BYTE_OBJECT: *sz = pmix_compress.get_decompressed_size(&v->data.bo); break; case PMIX_PERSIST: *sz = sizeof(pmix_persistence_t); break; case PMIX_SCOPE: *sz = sizeof(pmix_scope_t); break; case PMIX_DATA_RANGE: *sz = sizeof(pmix_data_range_t); break; case PMIX_PROC_STATE: *sz = sizeof(pmix_proc_state_t); break; case PMIX_PROC_INFO: *sz = sizeof(pmix_proc_info_t); *sz += 1; if (NULL != v->data.pinfo->hostname) { *sz += strlen(v->data.pinfo->hostname); } *sz += 1; if (NULL != v->data.pinfo->executable_name) { *sz += strlen(v->data.pinfo->executable_name); } break; case PMIX_DATA_ARRAY: rc = get_darray_size(v->data.darray, sz); if (PMIX_SUCCESS == rc) { *sz += sizeof(pmix_data_array_t); } break; case PMIX_POINTER: *sz = sizeof(void *); break; case PMIX_ALLOC_DIRECTIVE: *sz = sizeof(pmix_alloc_directive_t); break; case PMIX_RESBLOCK_DIRECTIVE: *sz = sizeof(pmix_resource_block_directive_t); break; case PMIX_ENVAR: *sz = sizeof(pmix_envar_t); *sz += 1; if (NULL != v->data.envar.envar) { *sz += strlen(v->data.envar.envar); } *sz += 1; if (NULL != v->data.envar.value) { *sz += strlen(v->data.envar.value); } break; case PMIX_COORD: *sz = sizeof(pmix_coord_t); if (0 < v->data.coord->dims) { *sz += v->data.coord->dims * sizeof(uint32_t); } break; case PMIX_LINK_STATE: *sz = sizeof(pmix_link_state_t); break; case PMIX_JOB_STATE: *sz = sizeof(pmix_job_state_t); break; case PMIX_TOPO: rc = pmix_hwloc_get_topology_size(v->data.topo, sz); if (PMIX_SUCCESS == rc) { *sz += sizeof(pmix_topology_t); } break; case PMIX_PROC_CPUSET: rc = pmix_hwloc_get_cpuset_size(v->data.cpuset, sz); if (PMIX_SUCCESS == rc) { *sz += sizeof(pmix_cpuset_t); } break; case PMIX_LOCTYPE: *sz = sizeof(pmix_locality_t); break; case PMIX_GEOMETRY: *sz = sizeof(pmix_geometry_t); *sz += 1; if (NULL != v->data.geometry->uuid) { *sz += strlen(v->data.geometry->uuid); } *sz += 1; if (NULL != v->data.geometry->osname) { *sz += strlen(v->data.geometry->osname); } for (n=0; n < v->data.geometry->ncoords; n++) { *sz += sizeof(pmix_coord_t); if (0 < v->data.geometry->coordinates[n].dims) { *sz += v->data.geometry->coordinates[n].dims * sizeof(uint32_t); } } break; case PMIX_DEVTYPE: *sz = sizeof(pmix_device_type_t); break; case PMIX_DEVICE: *sz = sizeof(pmix_device_t); *sz += 1; if (NULL != v->data.device->uuid) { *sz += strlen(v->data.device->uuid); } *sz += 1; if (NULL != v->data.device->osname) { *sz += strlen(v->data.device->osname); } break; case PMIX_RESOURCE_UNIT: *sz = sizeof(pmix_resource_unit_t); break; case PMIX_DEVICE_DIST: *sz = sizeof(pmix_device_distance_t); *sz += 1; if (NULL != v->data.devdist->uuid) { *sz += strlen(v->data.devdist->uuid); } *sz += 1; if (NULL != v->data.devdist->osname) { *sz += strlen(v->data.devdist->osname); } break; case PMIX_ENDPOINT: *sz = sizeof(pmix_endpoint_t); *sz += 1; if (NULL != v->data.endpoint->uuid) { *sz += strlen(v->data.endpoint->uuid); } *sz += 1; if (NULL != v->data.endpoint->osname) { *sz += strlen(v->data.endpoint->osname); } *sz += v->data.endpoint->endpt.size; break; case PMIX_REGATTR: *sz = sizeof(pmix_regattr_t); regattr = (pmix_regattr_t *)v->data.ptr; *sz += 1; if (NULL != regattr->name) { *sz += strlen(regattr->name); } if (NULL != regattr->description) { for (n=0; NULL != regattr->description[n]; n++) { *sz += 1; *sz += strlen(regattr->description[n]); } } break; case PMIX_REGEX: *sz = sizeof(pmix_byte_object_t); *sz += v->data.bo.size; break; case PMIX_DATA_BUFFER: *sz = sizeof(pmix_data_buffer_t); *sz += v->data.dbuf->bytes_used; break; case PMIX_NODE_PID: *sz = sizeof(pmix_node_pid_t); ndpd = (pmix_node_pid_t*)v->data.nodepid; if (NULL != ndpd->hostname) { *sz += strlen(ndpd->hostname) + 1; // account for NULL } break; default: /* silence warnings */ break; } /* account for the size of the pmix_value_t itself */ *sz += sizeof(pmix_value_t); return rc; } pmix_status_t PMIx_Info_get_size(const pmix_info_t *val, size_t *size) { pmix_status_t rc; size_t len; rc = PMIx_Value_get_size(&val->value, size); if (PMIX_SUCCESS != rc) { return rc; } len = strnlen(val->key, PMIX_MAX_KEYLEN); if (PMIX_MAX_KEYLEN == len) { *size += PMIX_MAX_KEYLEN; } else { *size += len + 1; } *size += sizeof(pmix_info_t); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_tma.h0000664000175000017500000035144315203536752022357 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022 IBM Corporation. All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * Houses infrastructure that supports custom memory allocators for bfrops. * If tma is NULL, then the default heap manager is used. */ #ifndef PMIX_BFROP_BASE_TMA_H #define PMIX_BFROP_BASE_TMA_H #include "src/include/pmix_config.h" #include "src/include/pmix_globals.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/preg/preg.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_printf.h" extern char **environ; static inline void pmix_bfrops_base_tma_value_destruct(pmix_value_t *v, pmix_tma_t *tma); static inline pmix_status_t pmix_bfrops_base_tma_value_xfer(pmix_value_t *p, const pmix_value_t *src, pmix_tma_t *tma); static inline char* pmix_bfrops_base_tma_buffer_extend(pmix_buffer_t *buffer, size_t bytes_to_add, pmix_tma_t *tma) { size_t required, to_alloc; size_t pack_offset, unpack_offset; /* Check to see if we have enough space already */ if (0 == bytes_to_add) { return buffer->pack_ptr; } if ((buffer->bytes_allocated - buffer->bytes_used) >= bytes_to_add) { return buffer->pack_ptr; } required = buffer->bytes_used + bytes_to_add; if (required >= pmix_bfrops_globals.threshold_size) { to_alloc = ((required + pmix_bfrops_globals.threshold_size - 1) / pmix_bfrops_globals.threshold_size) * pmix_bfrops_globals.threshold_size; } else { to_alloc = buffer->bytes_allocated; if (0 == to_alloc) { to_alloc = pmix_bfrops_globals.initial_size; } while (to_alloc < required) { to_alloc <<= 1; } } if (NULL != buffer->base_ptr) { pack_offset = ((char *) buffer->pack_ptr) - ((char *) buffer->base_ptr); unpack_offset = ((char *) buffer->unpack_ptr) - ((char *) buffer->base_ptr); buffer->base_ptr = (char *) pmix_tma_realloc(tma, buffer->base_ptr, to_alloc); memset(buffer->base_ptr + pack_offset, 0, to_alloc - buffer->bytes_allocated); } else { pack_offset = 0; unpack_offset = 0; buffer->bytes_used = 0; buffer->base_ptr = (char *)pmix_tma_malloc(tma, to_alloc); memset(buffer->base_ptr, 0, to_alloc); } if (NULL == buffer->base_ptr) { return NULL; } buffer->pack_ptr = ((char *) buffer->base_ptr) + pack_offset; buffer->unpack_ptr = ((char *) buffer->base_ptr) + unpack_offset; buffer->bytes_allocated = to_alloc; /* All done */ return buffer->pack_ptr; } static inline pmix_status_t pmix_bfrops_base_tma_copy_payload(pmix_buffer_t *dest, pmix_buffer_t *src, pmix_tma_t *tma) { size_t to_copy = 0; char *ptr; /* deal with buffer type */ if (NULL == dest->base_ptr) { /* destination buffer is empty - derive src buffer type */ dest->type = src->type; } else if (PMIX_UNLIKELY(dest->type != src->type)) { /* buffer types mismatch */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* if the src buffer is empty, then there is * nothing to do */ if (PMIX_BUFFER_IS_EMPTY(src)) { return PMIX_SUCCESS; } /* extend the dest if necessary */ to_copy = src->pack_ptr - src->unpack_ptr; if (NULL == (ptr = pmix_bfrops_base_tma_buffer_extend(dest, to_copy, tma))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return PMIX_ERR_OUT_OF_RESOURCE; } memcpy(ptr, src->unpack_ptr, to_copy); dest->bytes_used += to_copy; dest->pack_ptr += to_copy; return PMIX_SUCCESS; } static inline pmix_status_t pmix_bfrops_base_tma_embed_payload(pmix_buffer_t *dest, pmix_byte_object_t *src, pmix_tma_t *tma) { char *ptr; /* deal with buffer type */ if (NULL == dest->base_ptr) { /* destination buffer is empty - derive src buffer type */ dest->type = pmix_bfrops_globals.default_type; } /* if the src is empty, then there is * nothing to do */ if (NULL == src->bytes) { return PMIX_SUCCESS; } /* extend the dest if necessary */ if (NULL == (ptr = pmix_bfrops_base_tma_buffer_extend(dest, src->size, tma))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return PMIX_ERR_OUT_OF_RESOURCE; } memcpy(ptr, src->bytes, src->size); dest->bytes_used += src->size; dest->pack_ptr += src->size; return PMIX_SUCCESS; } static inline void pmix_bfrops_base_tma_load_key(pmix_key_t key, const char *src, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(key, 0, PMIX_MAX_KEYLEN + 1); if (NULL != src) { pmix_strncpy((char *)key, src, PMIX_MAX_KEYLEN); } } static inline bool pmix_bfrops_base_tma_check_key(const char *key, const char *str, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); if (0 == strncmp(key, str, PMIX_MAX_KEYLEN)) { return true; } return false; } static inline bool pmix_bfrops_base_tma_nspace_invalid(const char *nspace, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); if (NULL == nspace || 0 == pmix_nslen(nspace)) { return true; } return false; } static inline bool pmix_bfrops_base_tma_check_nspace(const char *nspace1, const char *nspace2, pmix_tma_t *tma) { if (pmix_bfrops_base_tma_nspace_invalid(nspace1, tma)) { return true; } if (pmix_bfrops_base_tma_nspace_invalid(nspace2, tma)) { return true; } if (0 == strncmp(nspace1, nspace2, PMIX_MAX_NSLEN)) { return true; } return false; } static inline bool pmix_bfrops_base_tma_check_reserved_key(const char *key, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); if (0 == strncmp(key, "pmix", 4)) { return true; } return false; } static inline void pmix_bfrops_base_tma_xfer_procid(pmix_proc_t *dst, const pmix_proc_t *src, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memcpy(dst, src, sizeof(pmix_proc_t)); } static inline bool pmix_bfrops_base_tma_check_rank(pmix_rank_t a, pmix_rank_t b, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); if (a == b) { return true; } if (PMIX_RANK_WILDCARD == a || PMIX_RANK_WILDCARD == b) { return true; } return false; } static inline bool pmix_bfrops_base_tma_rank_valid(pmix_rank_t a, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); if (a < PMIX_RANK_VALID) { return true; } return false; } static inline bool pmix_bfrops_base_tma_check_procid(const pmix_proc_t *a, const pmix_proc_t *b, pmix_tma_t *tma) { if (!pmix_bfrops_base_tma_check_nspace(a->nspace, b->nspace, tma)) { return false; } return pmix_bfrops_base_tma_check_rank(a->rank, b->rank, tma); } static inline bool pmix_bfrops_base_tma_procid_invalid(const pmix_proc_t *p, pmix_tma_t *tma) { if (pmix_bfrops_base_tma_nspace_invalid(p->nspace, tma)) { return true; } if (PMIX_RANK_INVALID == p->rank) { return true; } return false; } static inline void pmix_bfrops_base_tma_load_nspace(pmix_nspace_t nspace, const char *str, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(nspace, 0, PMIX_MAX_NSLEN + 1); if (NULL != str) { pmix_strncpy((char *)nspace, str, PMIX_MAX_NSLEN); } } static inline void pmix_bfrops_base_tma_load_procid(pmix_proc_t *p, const char *ns, pmix_rank_t rk, pmix_tma_t *tma) { pmix_bfrops_base_tma_load_nspace(p->nspace, ns, tma); p->rank = rk; } static inline void pmix_bfrops_base_tma_data_buffer_load(pmix_data_buffer_t *b, char *bytes, size_t sz, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); pmix_byte_object_t bo; bo.bytes = bytes; bo.size = sz; // TODO(skg) Add TMA support when necessary. PMIx_Data_load(b, &bo); } static inline void pmix_bfrops_base_tma_data_buffer_unload(pmix_data_buffer_t *b, char **bytes, size_t *sz, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); pmix_byte_object_t bo; pmix_status_t r; // TODO(skg) Add TMA support when necessary. r = PMIx_Data_unload(b, &bo); if (PMIX_SUCCESS == r) { *bytes = bo.bytes; *sz = bo.size; } else { *bytes = NULL; *sz = 0; } } static inline void pmix_bfrops_base_tma_proc_construct(pmix_proc_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(p, 0, sizeof(pmix_proc_t)); p->rank = PMIX_RANK_UNDEF; } static inline void pmix_bfrops_base_tma_proc_destruct(pmix_proc_t *p, pmix_tma_t *tma) { // Destruct in this case is only setting data members // to default values, so call proc_construct. pmix_bfrops_base_tma_proc_construct(p, tma); } static inline void pmix_bfrops_base_tma_proc_load(pmix_proc_t *p, const char *nspace, pmix_rank_t rank, pmix_tma_t *tma) { pmix_bfrops_base_tma_proc_construct(p, tma); pmix_bfrops_base_tma_load_procid(p, nspace, rank, tma); } static inline pmix_proc_t* pmix_bfrops_base_tma_proc_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_proc_t *p = (pmix_proc_t*)pmix_tma_malloc(tma, n * sizeof(pmix_proc_t)); if (PMIX_LIKELY(NULL != p)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_proc_construct(&p[m], tma); } } return p; } static inline void pmix_bfrops_base_tma_proc_free(pmix_proc_t *p, size_t n, pmix_tma_t *tma) { if (NULL != p && 0 < n) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_proc_destruct(&p[m], tma); } pmix_tma_free(tma, p); } } static inline void pmix_bfrops_base_tma_multicluster_nspace_construct(pmix_nspace_t target, pmix_nspace_t cluster, pmix_nspace_t nspace, pmix_tma_t *tma) { pmix_bfrops_base_tma_load_nspace(target, NULL, tma); size_t len = pmix_nslen(cluster); if ((len + pmix_nslen(nspace)) < PMIX_MAX_NSLEN) { pmix_strncpy((char*)target, cluster, PMIX_MAX_NSLEN); target[len] = ':'; pmix_strncpy((char*)&target[len+1], nspace, PMIX_MAX_NSLEN - len); } } static inline void pmix_bfrops_base_tma_multicluster_nspace_parse(pmix_nspace_t target, pmix_nspace_t cluster, pmix_nspace_t nspace, pmix_tma_t *tma) { size_t n, j; pmix_bfrops_base_tma_load_nspace(cluster, NULL, tma); for (n=0; '\0' != target[n] && ':' != target[n] && n < PMIX_MAX_NSLEN; n++) { cluster[n] = target[n]; } n++; for (j=0; n < PMIX_MAX_NSLEN && '\0' != target[n]; n++, j++) { nspace[j] = target[n]; } } static inline void pmix_bfrops_base_tma_proc_info_construct(pmix_proc_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(p, 0, sizeof(pmix_proc_info_t)); p->state = PMIX_PROC_STATE_UNDEF; } static inline void pmix_bfrops_base_tma_proc_info_destruct(pmix_proc_info_t *p, pmix_tma_t *tma) { if (NULL != p->hostname) { pmix_tma_free(tma, p->hostname); } if (NULL != p->executable_name) { pmix_tma_free(tma, p->executable_name); } pmix_bfrops_base_tma_proc_info_construct(p, tma); } static inline void pmix_bfrops_base_tma_proc_info_free(pmix_proc_info_t *p, size_t n, pmix_tma_t *tma) { if (NULL != p && 0 < n) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_proc_info_destruct(&p[m], tma); } pmix_tma_free(tma, p); } } static inline pmix_proc_info_t* pmix_bfrops_base_tma_proc_info_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_proc_info_t *p = (pmix_proc_info_t *)pmix_tma_malloc(tma, n * sizeof(pmix_proc_info_t)); if (PMIX_LIKELY(NULL != p)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_proc_info_construct(&p[m], tma); } } return p; } static inline pmix_status_t pmix_bfrops_base_tma_copy_pinfo(pmix_proc_info_t **dest, pmix_proc_info_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_proc_info_t *p = pmix_bfrops_base_tma_proc_info_create(1, tma); if (PMIX_UNLIKELY(NULL == p)) { return PMIX_ERR_NOMEM; } memcpy(&p->proc, &src->proc, sizeof(pmix_proc_t)); if (NULL != src->hostname) { p->hostname = pmix_tma_strdup(tma, src->hostname); } if (NULL != src->executable_name) { p->executable_name = pmix_tma_strdup(tma, src->executable_name); } memcpy(&p->pid, &src->pid, sizeof(pid_t)); memcpy(&p->exit_code, &src->exit_code, sizeof(int)); memcpy(&p->state, &src->state, sizeof(pmix_proc_state_t)); *dest = p; return PMIX_SUCCESS; } static inline void pmix_bfrops_base_tma_value_construct(pmix_value_t *val, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(val, 0, sizeof(pmix_value_t)); val->type = PMIX_UNDEF; } static inline pmix_value_t* pmix_bfrops_base_tma_value_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_value_t *v = (pmix_value_t *)pmix_tma_malloc(tma, n * sizeof(pmix_value_t)); if (PMIX_LIKELY(NULL != v)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_value_construct(&v[m], tma); } } return v; } static inline pmix_status_t pmix_bfrops_base_tma_value_load(pmix_value_t *v, const void *data, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); // TODO(skg) Add TMA support when necessary. pmix_bfrops_base_value_load(v, data, type); return PMIX_SUCCESS; } static inline pmix_boolean_t pmix_bfrops_base_tma_value_true(const pmix_value_t *value, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); char *ptr; if (PMIX_UNDEF == value->type) { return PMIX_BOOL_TRUE; // default to true } if (PMIX_BOOL == value->type) { if (value->data.flag) { return PMIX_BOOL_TRUE; } else { return PMIX_BOOL_FALSE; } } if (PMIX_STRING == value->type) { if (NULL == value->data.string) { return PMIX_BOOL_TRUE; } ptr = value->data.string; /* Trim leading whitespace */ while (isspace(*ptr)) { ++ptr; } if ('\0' == *ptr) { return PMIX_BOOL_TRUE; } if (isdigit(*ptr)) { if (0 == atoi(ptr)) { return PMIX_BOOL_FALSE; } else { return PMIX_BOOL_TRUE; } } else if (0 == strncasecmp(ptr, "yes", 3) || 0 == strncasecmp(ptr, "true", 4) || 0 == strcasecmp(ptr, "y") || 0 == strcasecmp(ptr, "t") || 0 == strncasecmp(ptr, "enable", 6)) { return PMIX_BOOL_TRUE; } else if (0 == strncasecmp(ptr, "no", 2) || 0 == strncasecmp(ptr, "false", 5) || 0 == strcasecmp(ptr, "n") || 0 == strcasecmp(ptr, "f") || 0 == strncasecmp(ptr, "disable", 7)) { return PMIX_BOOL_FALSE; } } return PMIX_NON_BOOL; } static inline bool pmix_bfrops_base_tma_info_is_persistent(const pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); return PMIX_CHECK_BIT_IS_SET(p->flags, PMIX_INFO_PERSISTENT); } static inline void pmix_bfrops_base_tma_info_destruct(pmix_info_t *p, pmix_tma_t *tma) { if (!pmix_bfrops_base_tma_info_is_persistent(p, tma)) { pmix_bfrops_base_tma_value_destruct(&p->value, tma); } } static inline void pmix_bfrops_base_tma_info_free(pmix_info_t *p, size_t n, pmix_tma_t *tma) { if (NULL != p && 0 < n) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_info_destruct(&p[m], tma); } pmix_tma_free(tma, p); } } static inline void pmix_bfrops_base_tma_info_construct(pmix_info_t *p, pmix_tma_t *tma) { pmix_bfrops_base_tma_load_key(p->key, NULL, tma); p->flags = 0; // default to non-persistent for historical reasons pmix_bfrops_base_tma_value_construct(&p->value, tma); } static inline pmix_info_t* pmix_bfrops_base_tma_info_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_info_t *i = (pmix_info_t *)pmix_tma_malloc(tma, n * sizeof(pmix_info_t)); if (PMIX_UNLIKELY(NULL == i)) { return NULL; } for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_info_construct(&i[m], tma); } return i; } static inline pmix_status_t pmix_bfrops_base_tma_info_load(pmix_info_t *info, const char *key, const void *data, pmix_data_type_t type, pmix_tma_t *tma) { pmix_bfrops_base_tma_info_construct(info, tma); if (NULL == key) { return PMIX_ERR_BAD_PARAM; } pmix_bfrops_base_tma_load_key(info->key, key, tma); return pmix_bfrops_base_tma_value_load(&info->value, data, type, tma); } static inline pmix_boolean_t pmix_bfrops_base_tma_info_true(const pmix_info_t *p, pmix_tma_t *tma) { return pmix_bfrops_base_tma_value_true(&p->value, tma); } static inline pmix_status_t pmix_bfrops_base_tma_fill_coord(pmix_coord_t *dst, pmix_coord_t *src, pmix_tma_t *tma) { dst->view = src->view; dst->dims = src->dims; if (0 < dst->dims) { dst->coord = (uint32_t *)pmix_tma_malloc(tma, dst->dims * sizeof(uint32_t)); if (PMIX_UNLIKELY(NULL == dst->coord)) { return PMIX_ERR_NOMEM; } memcpy(dst->coord, src->coord, dst->dims * sizeof(uint32_t)); } return PMIX_SUCCESS; } static inline void pmix_bfrops_base_tma_coord_destruct(pmix_coord_t *m, pmix_tma_t *tma) { if (NULL != m) { m->view = PMIX_COORD_VIEW_UNDEF; if (NULL != m->coord) { pmix_tma_free(tma, m->coord); m->coord = NULL; m->dims = 0; } } } static inline pmix_coord_t* pmix_bfrops_base_tma_coord_create(size_t dims, size_t number, pmix_tma_t *tma) { if (0 == number) { return NULL; } pmix_coord_t *m = (pmix_coord_t *)pmix_tma_malloc(tma, number * sizeof(pmix_coord_t)); if (PMIX_UNLIKELY(NULL == m)) { return NULL; } m->view = PMIX_COORD_VIEW_UNDEF; m->dims = dims; if (0 == dims) { m->coord = NULL; } else { m->coord = (uint32_t *)pmix_tma_malloc(tma, dims * sizeof(uint32_t)); if (PMIX_LIKELY(NULL != m->coord)) { memset(m->coord, 0, dims * sizeof(uint32_t)); } } return m; } static inline void pmix_bfrops_base_tma_coord_free(pmix_coord_t *m, size_t number, pmix_tma_t *tma) { if (NULL != m) { for (size_t n = 0; n < number; n++) { pmix_bfrops_base_tma_coord_destruct(&m[n], tma); } pmix_tma_free(tma, m); } } static inline void pmix_bfrops_base_tma_info_required(pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); PMIX_SET_BIT(p->flags, PMIX_INFO_REQD); } static inline bool pmix_bfrops_base_tma_info_is_required(const pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); return PMIX_CHECK_BIT_IS_SET(p->flags, PMIX_INFO_REQD); } static inline void pmix_bfrops_base_tma_info_optional(pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); PMIX_UNSET_BIT(p->flags, PMIX_INFO_REQD); } static inline bool pmix_bfrops_base_tma_info_is_optional(const pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); return PMIX_CHECK_BIT_NOT_SET(p->flags, PMIX_INFO_REQD); } static inline void pmix_bfrops_base_tma_info_processed(pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); PMIX_SET_BIT(p->flags, PMIX_INFO_REQD_PROCESSED); } static inline bool pmix_bfrops_base_tma_info_was_processed(const pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); return PMIX_CHECK_BIT_IS_SET(p->flags, PMIX_INFO_REQD_PROCESSED); } static inline void pmix_bfrops_base_tma_info_set_end(pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); PMIX_SET_BIT(p->flags, PMIX_INFO_ARRAY_END); } static inline bool pmix_bfrops_base_tma_info_is_end(const pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); return PMIX_CHECK_BIT_IS_SET(p->flags, PMIX_INFO_ARRAY_END); } static inline void pmix_bfrops_base_tma_info_qualifier(pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); PMIX_SET_BIT(p->flags, PMIX_INFO_QUALIFIER); } static inline bool pmix_bfrops_base_tma_info_is_qualifier(const pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); return PMIX_CHECK_BIT_IS_SET(p->flags, PMIX_INFO_QUALIFIER); } static inline void pmix_bfrops_base_tma_info_persistent(pmix_info_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); PMIX_SET_BIT(p->flags, PMIX_INFO_PERSISTENT); } static inline pmix_status_t pmix_bfrops_base_tma_info_xfer(pmix_info_t *dest, const pmix_info_t *src, pmix_tma_t *tma) { pmix_status_t rc; if (PMIX_UNLIKELY(NULL == dest || NULL == src)) { return PMIX_ERR_BAD_PARAM; } pmix_bfrops_base_tma_load_key(dest->key, src->key, tma); dest->flags = src->flags; if (pmix_bfrops_base_tma_info_is_persistent(src, tma)) { memcpy(&dest->value, &src->value, sizeof(pmix_value_t)); rc = PMIX_SUCCESS; } else { rc = pmix_bfrops_base_tma_value_xfer(&dest->value, &src->value, tma); } return rc; } static inline void pmix_bfrops_base_tma_coord_construct(pmix_coord_t *m, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); if (NULL == m) { return; } m->view = PMIX_COORD_VIEW_UNDEF; m->coord = NULL; m->dims = 0; } static inline pmix_status_t pmix_bfrops_base_tma_copy_coord(pmix_coord_t **dest, pmix_coord_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_coord_t *d = (pmix_coord_t *)pmix_tma_malloc(tma, sizeof(pmix_coord_t)); if (PMIX_UNLIKELY(NULL == d)) { return PMIX_ERR_NOMEM; } pmix_bfrops_base_tma_coord_construct(d, tma); pmix_status_t rc = pmix_bfrops_base_tma_fill_coord(d, src, tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { pmix_bfrops_base_tma_coord_destruct(d, tma); pmix_tma_free(tma, d); } else { *dest = d; } return rc; } static inline void pmix_bfrops_base_tma_topology_construct(pmix_topology_t *t, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(t, 0, sizeof(pmix_topology_t)); } static inline void pmix_bfrops_base_tma_topology_destruct(pmix_topology_t *t, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); // TODO(skg) Add TMA support when necessary. pmix_hwloc_destruct_topology(t); } static inline pmix_topology_t* pmix_bfrops_base_tma_topology_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_topology_t *t = (pmix_topology_t *)pmix_tma_malloc(tma, n * sizeof(pmix_topology_t)); if (PMIX_LIKELY(NULL != t)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_topology_construct(&t[m], tma); } } return t; } static inline pmix_status_t pmix_bfrops_base_tma_copy_topology(pmix_topology_t **dest, pmix_topology_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_topology_t *dst = pmix_bfrops_base_tma_topology_create(1, tma); if (PMIX_UNLIKELY(NULL == dst)) { return PMIX_ERR_NOMEM; } // TODO(skg) Add TMA support when necessary. pmix_status_t rc = pmix_hwloc_copy_topology(dst, src); if (PMIX_SUCCESS == rc) { *dest = dst; } else { pmix_tma_free(tma, dst); } return rc; } static inline void pmix_bfrops_base_tma_topology_free(pmix_topology_t *t, size_t n, pmix_tma_t *tma) { if (NULL != t) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_topology_destruct(&t[m], tma); } pmix_tma_free(tma, t); } } static inline void pmix_bfrops_base_tma_cpuset_construct(pmix_cpuset_t *c, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(c, 0, sizeof(pmix_cpuset_t)); } static inline void pmix_bfrops_base_tma_cpuset_destruct(pmix_cpuset_t *c, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); // TODO(skg) Add TMA support when necessary. pmix_hwloc_destruct_cpuset(c); } static inline void pmix_bfrops_base_tma_cpuset_free(pmix_cpuset_t *c, size_t n, pmix_tma_t *tma) { if (NULL != c) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_cpuset_destruct(&c[m], tma); } pmix_tma_free(tma, c); } } static inline pmix_cpuset_t* pmix_bfrops_base_tma_cpuset_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_cpuset_t *c = (pmix_cpuset_t *)pmix_tma_malloc(tma, n * sizeof(pmix_cpuset_t)); if (PMIX_LIKELY(NULL != c)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_cpuset_construct(&c[m], tma); } } return c; } static inline pmix_status_t pmix_bfrops_base_tma_copy_cpuset(pmix_cpuset_t **dest, pmix_cpuset_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_cpuset_t *dst = pmix_bfrops_base_tma_cpuset_create(1, tma); if (PMIX_UNLIKELY(NULL == dst)) { return PMIX_ERR_NOMEM; } // TODO(skg) Add TMA support when necessary. pmix_status_t rc = pmix_hwloc_copy_cpuset(dst, src); if (PMIX_SUCCESS == rc) { *dest = dst; } else { pmix_tma_free(tma, dst); } return rc; } static inline void pmix_bfrops_base_tma_geometry_construct(pmix_geometry_t *g, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(g, 0, sizeof(pmix_geometry_t)); } static inline pmix_geometry_t* pmix_bfrops_base_tma_geometry_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_geometry_t *g = (pmix_geometry_t *)pmix_tma_malloc(tma, n * sizeof(pmix_geometry_t)); if (PMIX_LIKELY(NULL != g)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_geometry_construct(&g[m], tma); } } return g; } static inline void pmix_bfrops_base_tma_geometry_destruct(pmix_geometry_t *g, pmix_tma_t *tma) { if (NULL != g->uuid) { pmix_tma_free(tma, g->uuid); g->uuid = NULL; } if (NULL != g->osname) { pmix_tma_free(tma, g->osname); g->osname = NULL; } if (NULL != g->coordinates) { pmix_bfrops_base_tma_coord_free(g->coordinates, g->ncoords, tma); } } static inline void pmix_bfrops_base_tma_geometry_free(pmix_geometry_t *g, size_t n, pmix_tma_t *tma) { if (NULL != g) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_geometry_destruct(&g[m], tma); } pmix_tma_free(tma, g); } } static inline pmix_status_t pmix_bfrops_base_tma_copy_geometry(pmix_geometry_t **dest, pmix_geometry_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_geometry_t *dst = pmix_bfrops_base_tma_geometry_create(1, tma); if (PMIX_UNLIKELY(NULL == dst)) { return PMIX_ERR_NOMEM; } dst->fabric = src->fabric; if (NULL != src->uuid) { dst->uuid = pmix_tma_strdup(tma, src->uuid); } if (NULL != src->osname) { dst->osname = pmix_tma_strdup(tma, src->osname); } if (NULL != src->coordinates) { dst->ncoords = src->ncoords; dst->coordinates = (pmix_coord_t *)pmix_tma_calloc(tma, dst->ncoords, sizeof(pmix_coord_t)); for (size_t n = 0; n < dst->ncoords; n++) { pmix_status_t rc = pmix_bfrops_base_tma_fill_coord(&dst->coordinates[n], &src->coordinates[n], tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_GEOMETRY_FREE(dst, 1); return rc; } } } *dest = dst; return PMIX_SUCCESS; } static inline pmix_status_t pmix_bfrops_base_tma_copy_nspace(pmix_nspace_t **dest, pmix_nspace_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_nspace_t *dst = (pmix_nspace_t *)pmix_tma_malloc(tma, sizeof(pmix_nspace_t)); if (PMIX_UNLIKELY(NULL == dst)) { return PMIX_ERR_NOMEM; } pmix_bfrops_base_tma_load_nspace(*dst, (char *)src, tma); *dest = dst; return PMIX_SUCCESS; } static inline void pmix_bfrops_base_tma_device_destruct(pmix_device_t *d, pmix_tma_t *tma) { if (NULL != (d->uuid)) { pmix_tma_free(tma, d->uuid); } if (NULL != (d->osname)) { pmix_tma_free(tma, d->osname); } } static inline void pmix_bfrops_base_tma_device_free(pmix_device_t *d, size_t n, pmix_tma_t *tma) { if (NULL != d) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_device_destruct(&d[m], tma); } pmix_tma_free(tma, d); } } static inline void pmix_bfrops_base_tma_device_construct(pmix_device_t *d, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(d, 0, sizeof(pmix_device_t)); d->type = PMIX_DEVTYPE_UNKNOWN; } static inline pmix_device_t* pmix_bfrops_base_tma_device_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_device_t *d = (pmix_device_t *)pmix_tma_malloc(tma, n * sizeof(pmix_device_t)); if (PMIX_LIKELY(NULL != d)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_device_construct(&d[m], tma); } } return d; } static inline pmix_status_t pmix_bfrops_base_tma_copy_device(pmix_device_t **dest, pmix_device_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_device_t *dst = pmix_bfrops_base_tma_device_create(1, tma); if (PMIX_UNLIKELY(NULL == dst)) { return PMIX_ERR_NOMEM; } if (NULL != src->uuid) { dst->uuid = pmix_tma_strdup(tma, src->uuid); } if (NULL != src->osname) { dst->osname = pmix_tma_strdup(tma, src->osname); } dst->type = src->type; *dest = dst; return PMIX_SUCCESS; } static inline void pmix_bfrops_base_tma_node_pid_construct(pmix_node_pid_t *d, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); d->hostname = NULL; d->nodeid = UINT32_MAX; d->pid = -1; } static inline void pmix_bfrops_base_tma_node_pid_destruct(pmix_node_pid_t *d, pmix_tma_t *tma) { if (NULL != d->hostname) { pmix_tma_free(tma, d->hostname); } } static inline pmix_node_pid_t* pmix_bfrops_base_tma_node_pid_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_node_pid_t *d = (pmix_node_pid_t *)pmix_tma_malloc(tma, n * sizeof(pmix_node_pid_t)); if (PMIX_LIKELY(NULL != d)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_node_pid_construct(&d[m], tma); } } return d; } static inline void pmix_bfrops_base_tma_node_pid_free(pmix_node_pid_t *d, size_t n, pmix_tma_t *tma) { if (NULL != d) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_node_pid_destruct(&d[m], tma); } pmix_tma_free(tma, d); } } static inline pmix_status_t pmix_bfrops_base_tma_copy_nodepid(pmix_node_pid_t **dest, pmix_node_pid_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_node_pid_t *p = pmix_bfrops_base_tma_node_pid_create(1, tma); if (PMIX_UNLIKELY(NULL == p)) { return PMIX_ERR_NOMEM; } *dest = p; if (NULL != src->hostname) { p->hostname = pmix_tma_strdup(tma, src->hostname); } p->nodeid = src->nodeid; p->pid = src->pid; return PMIX_SUCCESS; } static inline void pmix_bfrops_base_tma_resource_unit_destruct(pmix_resource_unit_t *d, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(d, tma); } static inline void pmix_bfrops_base_tma_resource_unit_free(pmix_resource_unit_t *d, size_t n, pmix_tma_t *tma) { if (NULL != d) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_resource_unit_destruct(&d[m], tma); } pmix_tma_free(tma, d); } } static inline void pmix_bfrops_base_tma_resource_unit_construct(pmix_resource_unit_t *d, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(d, 0, sizeof(pmix_resource_unit_t)); d->type = PMIX_DEVTYPE_UNKNOWN; } static inline pmix_resource_unit_t* pmix_bfrops_base_tma_resource_unit_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_resource_unit_t *d = (pmix_resource_unit_t *)pmix_tma_malloc(tma, n * sizeof(pmix_resource_unit_t)); if (PMIX_LIKELY(NULL != d)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_resource_unit_construct(&d[m], tma); } } return d; } static inline pmix_status_t pmix_bfrops_base_tma_copy_resource_unit(pmix_resource_unit_t **dest, pmix_resource_unit_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_resource_unit_t *dst = pmix_bfrops_base_tma_resource_unit_create(1, tma); if (PMIX_UNLIKELY(NULL == dst)) { return PMIX_ERR_NOMEM; } memcpy(dst, src, sizeof(pmix_resource_unit_t)); *dest = dst; return PMIX_SUCCESS; } static inline void pmix_bfrops_base_tma_device_distance_destruct(pmix_device_distance_t *d, pmix_tma_t *tma) { if (NULL != (d->uuid)) { pmix_tma_free(tma, d->uuid); } if (NULL != (d->osname)) { pmix_tma_free(tma, d->osname); } } static inline void pmix_bfrops_base_tma_device_distance_free(pmix_device_distance_t *d, size_t n, pmix_tma_t *tma) { if (NULL != d) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_device_distance_destruct(&d[m], tma); } pmix_tma_free(tma, d); } } static inline void pmix_bfrops_base_tma_device_distance_construct(pmix_device_distance_t *d, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(d, 0, sizeof(pmix_device_distance_t)); d->type = PMIX_DEVTYPE_UNKNOWN; d->mindist = UINT16_MAX; d->maxdist = UINT16_MAX; } static inline pmix_device_distance_t* pmix_bfrops_base_tma_device_distance_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_device_distance_t *d = (pmix_device_distance_t *)pmix_tma_malloc(tma, n * sizeof(pmix_device_distance_t)); if (PMIX_LIKELY(NULL != d)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_device_distance_construct(&d[m], tma); } } return d; } static inline pmix_status_t pmix_bfrops_base_tma_copy_devdist(pmix_device_distance_t **dest, pmix_device_distance_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_device_distance_t *dst = pmix_bfrops_base_tma_device_distance_create(1, tma); if (PMIX_UNLIKELY(NULL == dst)) { return PMIX_ERR_NOMEM; } if (NULL != src->uuid) { dst->uuid = pmix_tma_strdup(tma, src->uuid); } if (NULL != src->osname) { dst->osname = pmix_tma_strdup(tma, src->osname); } dst->type = src->type; dst->mindist = src->mindist; dst->maxdist = src->maxdist; *dest = dst; return PMIX_SUCCESS; } static inline void pmix_bfrops_base_tma_byte_object_construct(pmix_byte_object_t *b, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); b->bytes = NULL; b->size = 0; } static inline void pmix_bfrops_base_tma_byte_object_destruct(pmix_byte_object_t *b, pmix_tma_t *tma) { if (NULL != b->bytes) { pmix_tma_free(tma, b->bytes); } b->bytes = NULL; b->size = 0; } static inline pmix_byte_object_t* pmix_bfrops_base_tma_byte_object_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_byte_object_t *b = (pmix_byte_object_t *)pmix_tma_malloc(tma, n * sizeof(pmix_byte_object_t)); if (PMIX_LIKELY(NULL != b)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_byte_object_construct(&b[m], tma); } } return b; } static inline void pmix_bfrops_base_tma_byte_object_free(pmix_byte_object_t *b, size_t n, pmix_tma_t *tma) { if (NULL != b) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_byte_object_destruct(&b[m], tma); } pmix_tma_free(tma, b); } } static inline void pmix_bfrops_base_tma_endpoint_construct(pmix_endpoint_t *e, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(e, 0, sizeof(pmix_endpoint_t)); } static inline void pmix_bfrops_base_tma_endpoint_destruct(pmix_endpoint_t *e, pmix_tma_t *tma) { if (NULL != e->uuid) { pmix_tma_free(tma, e->uuid); } if (NULL != e->osname) { pmix_tma_free(tma, e->osname); } if (NULL != e->endpt.bytes) { pmix_tma_free(tma, e->endpt.bytes); } } static inline void pmix_bfrops_base_tma_endpoint_free(pmix_endpoint_t *e, size_t n, pmix_tma_t *tma) { if (NULL != e) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_endpoint_destruct(&e[m], tma); } pmix_tma_free(tma, e); } } static inline pmix_endpoint_t* pmix_bfrops_base_tma_endpoint_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_endpoint_t *e = (pmix_endpoint_t *)pmix_tma_malloc(tma, n * sizeof(pmix_endpoint_t)); if (PMIX_LIKELY(NULL != e)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_endpoint_construct(&e[m], tma); } } return e; } static inline pmix_status_t pmix_bfrops_base_tma_copy_endpoint(pmix_endpoint_t **dest, pmix_endpoint_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_endpoint_t *dst = pmix_bfrops_base_tma_endpoint_create(1, tma); if (PMIX_UNLIKELY(NULL == dst)) { return PMIX_ERR_NOMEM; } if (NULL != src->uuid) { dst->uuid = pmix_tma_strdup(tma, src->uuid); } if (NULL != src->osname) { dst->osname = pmix_tma_strdup(tma, src->osname); } if (NULL != src->endpt.bytes) { dst->endpt.bytes = (char *)pmix_tma_malloc(tma, src->endpt.size); memcpy(dst->endpt.bytes, src->endpt.bytes, src->endpt.size); dst->endpt.size = src->endpt.size; } *dest = dst; return PMIX_SUCCESS; } static inline int pmix_bfrops_base_tma_argv_count(char **argv, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); char **p; int i; if (NULL == argv) return 0; for (i = 0, p = argv; *p; i++, p++) continue; return i; } static inline pmix_status_t pmix_bfrops_base_tma_argv_append_nosize(char ***argv, const char *arg, pmix_tma_t *tma) { int argc; /* Create new argv. */ if (NULL == *argv) { *argv = (char **)pmix_tma_malloc(tma, 2 * sizeof(char *)); if (NULL == *argv) { return PMIX_ERR_OUT_OF_RESOURCE; } argc = 0; (*argv)[0] = NULL; (*argv)[1] = NULL; } /* Extend existing argv. */ else { /* count how many entries currently exist */ argc = pmix_bfrops_base_tma_argv_count(*argv, tma); *argv = (char **)pmix_tma_realloc(tma, *argv, (argc + 2) * sizeof(char *)); if (NULL == *argv) { return PMIX_ERR_OUT_OF_RESOURCE; } } /* Set the newest element to point to a copy of the arg string */ (*argv)[argc] = pmix_tma_strdup(tma, arg); if (NULL == (*argv)[argc]) { return PMIX_ERR_OUT_OF_RESOURCE; } argc = argc + 1; (*argv)[argc] = NULL; return PMIX_SUCCESS; } static inline pmix_status_t pmix_bfrops_base_tma_argv_prepend_nosize(char ***argv, const char *arg, pmix_tma_t *tma) { int argc; int i; /* Create new argv. */ if (NULL == *argv) { *argv = (char **)pmix_tma_malloc(tma, 2 * sizeof(char *)); if (NULL == *argv) { return PMIX_ERR_OUT_OF_RESOURCE; } (*argv)[0] = pmix_tma_strdup(tma, arg); (*argv)[1] = NULL; } else { /* count how many entries currently exist */ argc = pmix_bfrops_base_tma_argv_count(*argv, tma); *argv = (char **)pmix_tma_realloc(tma, *argv, (argc + 2) * sizeof(char *)); if (NULL == *argv) { return PMIX_ERR_OUT_OF_RESOURCE; } (*argv)[argc + 1] = NULL; /* shift all existing elements down 1 */ for (i = argc; 0 < i; i--) { (*argv)[i] = (*argv)[i - 1]; } (*argv)[0] = pmix_tma_strdup(tma, arg); } return PMIX_SUCCESS; } static inline pmix_status_t pmix_bfrops_base_tma_argv_append_unique_nosize(char ***argv, const char *arg, pmix_tma_t *tma) { int i; /* if the provided array is NULL, then the arg cannot be present, * so just go ahead and append */ if (NULL == *argv) { return pmix_bfrops_base_tma_argv_append_nosize(argv, arg, tma); } /* see if this arg is already present in the array */ for (i = 0; NULL != (*argv)[i]; i++) { if (0 == strcmp(arg, (*argv)[i])) { /* already exists */ return PMIX_SUCCESS; } } /* we get here if the arg is not in the array - so add it */ return pmix_bfrops_base_tma_argv_append_nosize(argv, arg, tma); } static inline void pmix_bfrops_base_tma_argv_free(char **argv, pmix_tma_t *tma) { if (NULL != argv) { for (char **p = argv; NULL != *p; ++p) { pmix_tma_free(tma, *p); } pmix_tma_free(tma, argv); } } static inline char** pmix_bfrops_base_tma_argv_split_inter(const char *src_string, int delimiter, bool include_empty, pmix_tma_t *tma) { char arg[512]; char **argv = NULL; const char *p; char *argtemp; size_t arglen; while (src_string && *src_string) { p = src_string; arglen = 0; while (('\0' != *p) && (*p != delimiter)) { ++p; ++arglen; } /* zero length argument, skip */ if (src_string == p) { if (include_empty) { arg[0] = '\0'; if (PMIX_SUCCESS != pmix_bfrops_base_tma_argv_append_nosize(&argv, arg, NULL)) { return NULL; } } src_string = p + 1; continue; } /* tail argument, add straight from the original string */ else if ('\0' == *p) { if (PMIX_SUCCESS != pmix_bfrops_base_tma_argv_append_nosize(&argv, src_string, tma)) { return NULL; } src_string = p; continue; } /* long argument, malloc buffer, copy and add */ else if (arglen > 511) { argtemp = (char *)pmix_tma_malloc(tma, arglen + 1); if (NULL == argtemp) return NULL; pmix_strncpy(argtemp, src_string, arglen); argtemp[arglen] = '\0'; if (PMIX_SUCCESS != pmix_bfrops_base_tma_argv_append_nosize(&argv, argtemp, tma)) { pmix_tma_free(tma, argtemp); return NULL; } pmix_tma_free(tma, argtemp); } /* short argument, copy to buffer and add */ else { pmix_strncpy(arg, src_string, arglen); arg[arglen] = '\0'; if (PMIX_SUCCESS != pmix_bfrops_base_tma_argv_append_nosize(&argv, arg, tma)) { return NULL; } } src_string = p + 1; } /* All done */ return argv; } static inline char** pmix_bfrops_base_tma_argv_split_with_empty(const char *src_string, int delimiter, pmix_tma_t *tma) { return pmix_bfrops_base_tma_argv_split_inter(src_string, delimiter, true, tma); } static inline char** pmix_bfrops_base_tma_argv_split(const char *src_string, int delimiter, pmix_tma_t *tma) { return pmix_bfrops_base_tma_argv_split_inter(src_string, delimiter, false, tma); } static inline char* pmix_bfrops_base_tma_argv_join(char **argv, int delimiter, pmix_tma_t *tma) { char **p; char *pp; char *str; size_t str_len = 0; size_t i; /* Bozo case */ if (NULL == argv || NULL == argv[0]) { return pmix_tma_strdup(tma, ""); } /* Find the total string length in argv including delimiters. The last delimiter is replaced by the NULL character. */ for (p = argv; *p; ++p) { str_len += strlen(*p) + 1; } /* Allocate the string. */ if (NULL == (str = (char *)pmix_tma_malloc(tma, str_len))) return NULL; /* Loop filling in the string. */ str[--str_len] = '\0'; p = argv; pp = *p; for (i = 0; i < str_len; ++i) { if ('\0' == *pp) { /* End of a string, fill in a delimiter and go to the next string. */ str[i] = (char) delimiter; ++p; pp = *p; } else { str[i] = *pp++; } } /* All done */ return str; } static inline char** pmix_bfrops_base_tma_argv_copy(char **argv, pmix_tma_t *tma) { if (NULL == argv) { return NULL; } /* create an "empty" list, so that we return something valid if we were passed a valid list with no contained elements */ char **dupv = (char **)pmix_tma_malloc(tma, sizeof(char *)); dupv[0] = NULL; while (NULL != *argv) { if (PMIX_SUCCESS != pmix_bfrops_base_tma_argv_append_nosize(&dupv, *argv, tma)) { pmix_bfrops_base_tma_argv_free(dupv, tma); return NULL; } ++argv; } /* All done */ return dupv; } static inline void pmix_bfrops_base_tma_query_destruct(pmix_query_t *p, pmix_tma_t *tma) { if (NULL != p->keys) { pmix_bfrops_base_tma_argv_free(p->keys, tma); p->keys = NULL; } if (NULL != p->qualifiers) { pmix_bfrops_base_tma_info_free(p->qualifiers, p->nqual, tma); p->qualifiers = NULL; p->nqual = 0; } } static inline void pmix_bfrops_base_tma_query_free(pmix_query_t *p, size_t n, pmix_tma_t *tma) { if (NULL != p && 0 < n) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_query_destruct(&p[m], tma); } pmix_tma_free(tma, p); } } static inline void pmix_bfrops_base_tma_query_release(pmix_query_t *p, pmix_tma_t *tma) { pmix_bfrops_base_tma_query_free(p, 1, tma); } static inline void pmix_bfrops_base_tma_pdata_construct(pmix_pdata_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(p, 0, sizeof(pmix_pdata_t)); p->value.type = PMIX_UNDEF; } static inline void pmix_bfrops_base_tma_pdata_destruct(pmix_pdata_t *p, pmix_tma_t *tma) { pmix_bfrops_base_tma_value_destruct(&p->value, tma); } static inline pmix_pdata_t* pmix_bfrops_base_tma_pdata_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_pdata_t *p = (pmix_pdata_t *)pmix_tma_malloc(tma, n * sizeof(pmix_pdata_t)); if (PMIX_LIKELY(NULL != p)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_pdata_construct(&p[m], tma); } } return p; } static inline void pmix_bfrops_base_tma_pdata_load(pmix_pdata_t *dest, const pmix_proc_t *p, const char *key, const void *data, pmix_data_type_t type, pmix_tma_t *tma) { memset(dest, 0, sizeof(pmix_pdata_t)); pmix_bfrops_base_tma_load_procid(&dest->proc, p->nspace, p->rank, tma); pmix_bfrops_base_tma_load_key(dest->key, key, tma); pmix_bfrops_base_tma_value_load(&(dest->value), data, type, tma); } static inline void pmix_bfrops_base_tma_pdata_xfer(pmix_pdata_t *dest, const pmix_pdata_t *src, pmix_tma_t *tma) { if (NULL != dest) { memset(dest, 0, sizeof(*dest)); pmix_bfrops_base_tma_load_procid(&dest->proc, src->proc.nspace, src->proc.rank, tma); pmix_bfrops_base_tma_load_key(dest->key, src->key, tma); pmix_bfrops_base_tma_value_xfer(&dest->value, &src->value, tma); } } static inline void pmix_bfrops_base_tma_pdata_free(pmix_pdata_t *p, size_t n, pmix_tma_t *tma) { if (NULL != p && 0 < n) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_pdata_destruct(&p[m], tma); } pmix_tma_free(tma, p); } } static inline void pmix_bfrops_base_tma_app_destruct(pmix_app_t *p, pmix_tma_t *tma) { if (NULL != p->cmd) { pmix_tma_free(tma, p->cmd); p->cmd = NULL; } if (NULL != p->argv) { pmix_bfrops_base_tma_argv_free(p->argv, tma); p->argv = NULL; } if (NULL != p->env) { pmix_bfrops_base_tma_argv_free(p->env, tma); p->env = NULL; } if (NULL != p->cwd) { pmix_tma_free(tma, p->cwd); p->cwd = NULL; } if (NULL != p->info && 0 < p->ninfo) { pmix_bfrops_base_tma_info_free(p->info, p->ninfo, tma); p->info = NULL; p->ninfo = 0; } } static inline void pmix_bfrops_base_tma_app_construct(pmix_app_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(p, 0, sizeof(pmix_app_t)); } static inline pmix_app_t* pmix_bfrops_base_tma_app_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_app_t *p = (pmix_app_t *)pmix_tma_malloc(tma, n * sizeof(pmix_app_t)); if (PMIX_LIKELY(NULL != p)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_app_construct(&p[m], tma); } } return p; } static inline void pmix_bfrops_base_tma_app_info_create(pmix_app_t *p, size_t n, pmix_tma_t *tma) { p->ninfo = n; p->info = pmix_bfrops_base_tma_info_create(n, tma); } static inline void pmix_bfrops_base_tma_app_free(pmix_app_t *p, size_t n, pmix_tma_t *tma) { if (NULL != p && 0 < n) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_app_destruct(&p[m], tma); } pmix_tma_free(tma, p); } } static inline void pmix_bfrops_base_tma_app_release(pmix_app_t *p, pmix_tma_t *tma) { pmix_bfrops_base_tma_app_free(p, 1, tma); } static inline void pmix_bfrops_base_tma_query_construct(pmix_query_t *p, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(p, 0, sizeof(pmix_query_t)); } static inline pmix_query_t* pmix_bfrops_base_tma_query_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_query_t *p = (pmix_query_t *)pmix_tma_malloc(tma, n * sizeof(pmix_query_t)); if (PMIX_LIKELY(NULL != p)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_query_construct(&p[m], tma); } } return p; } static inline void pmix_bfrops_base_tma_query_qualifiers_create(pmix_query_t *p, size_t n, pmix_tma_t *tma) { p->nqual = n; p->qualifiers = pmix_bfrops_base_tma_info_create(n, tma); } static inline void pmix_bfrops_base_tma_regattr_destruct(pmix_regattr_t *p, pmix_tma_t *tma) { if (NULL != p) { if (NULL != p->name) { pmix_tma_free(tma, p->name); p->name = NULL; } if (NULL != p->description) { pmix_bfrops_base_tma_argv_free(p->description, tma); p->description = NULL; } } } static inline void pmix_bfrops_base_tma_regattr_free(pmix_regattr_t *p, size_t n, pmix_tma_t *tma) { if (NULL != p && 0 < n) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_regattr_destruct(&p[m], tma); } pmix_tma_free(tma, p); } } static inline void pmix_bfrops_base_tma_regattr_construct(pmix_regattr_t *p, pmix_tma_t *tma) { p->name = NULL; pmix_bfrops_base_tma_load_key(p->string, NULL, tma); p->type = PMIX_UNDEF; p->description = NULL; } static inline pmix_regattr_t* pmix_bfrops_base_tma_regattr_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_regattr_t *p = (pmix_regattr_t*)pmix_tma_malloc(tma, n * sizeof(pmix_regattr_t)); if (PMIX_LIKELY(NULL != p)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_regattr_construct(&p[m], tma); } } return p; } static inline void pmix_bfrops_base_tma_regattr_load(pmix_regattr_t *p, const char *name, const char *key, pmix_data_type_t type, const char *description, pmix_tma_t *tma) { if (NULL != name) { p->name = pmix_tma_strdup(tma, name); } if (NULL != key) { pmix_bfrops_base_tma_load_key(p->string, key, tma); } p->type = type; if (NULL != description) { pmix_bfrops_base_tma_argv_append_nosize(&p->description, description, tma); } } static inline void pmix_bfrops_base_tma_regattr_xfer(pmix_regattr_t *dest, const pmix_regattr_t *src, pmix_tma_t *tma) { pmix_bfrops_base_tma_regattr_construct(dest, tma); if (NULL != (src->name)) { dest->name = pmix_tma_strdup(tma, src->name); } pmix_bfrops_base_tma_load_key(dest->string, src->string, tma); dest->type = src->type; if (NULL != src->description) { dest->description = pmix_bfrops_base_tma_argv_copy(src->description, tma); } } static inline pmix_status_t pmix_bfrops_base_tma_setenv(const char *name, const char *value, bool overwrite, char ***env, pmix_tma_t *tma) { // Note to developers: we don't use the TMA here because the values we // allocate on the heap are values that are inconsequential to the way we // currently use the TMA. PMIX_HIDE_UNUSED_PARAMS(tma); /* Check the bozo case */ if (NULL == env) { return PMIX_ERR_BAD_PARAM; } /* If this is the "environ" array, use setenv */ if (*env == environ) { if (NULL == value) { /* this is actually an unsetenv request */ unsetenv(name); } else { setenv(name, value, overwrite); } return PMIX_SUCCESS; } /* Make the new value */ char *newvalue = NULL; if (NULL == value) { pmix_asprintf(&newvalue, "%s=", name); } else { pmix_asprintf(&newvalue, "%s=%s", name, value); } if (NULL == newvalue) { return PMIX_ERR_OUT_OF_RESOURCE; } if (NULL == *env) { pmix_bfrops_base_tma_argv_append_nosize(env, newvalue, NULL); free(newvalue); return PMIX_SUCCESS; } /* Make something easy to compare to */ char *compare = NULL; pmix_asprintf(&compare, "%s=", name); if (NULL == compare) { free(newvalue); return PMIX_ERR_OUT_OF_RESOURCE; } /* Look for a duplicate that's already set in the env */ const size_t len = strlen(compare); for (int i = 0; (*env)[i] != NULL; ++i) { if (0 == strncmp((*env)[i], compare, len)) { if (overwrite) { free((*env)[i]); (*env)[i] = newvalue; free(compare); return PMIX_SUCCESS; } else { free(compare); free(newvalue); return PMIX_ERR_EXISTS; } } } /* If we found no match, append this value */ pmix_bfrops_base_tma_argv_append_nosize(env, newvalue, NULL); /* All done */ free(compare); free(newvalue); return PMIX_SUCCESS; } static inline void pmix_bfrops_base_tma_data_array_init(pmix_data_array_t *p, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); p->array = NULL; p->type = type; p->size = 0; } static inline void pmix_bfrops_base_tma_data_buffer_construct(pmix_data_buffer_t *b, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); memset(b, 0, sizeof(pmix_data_buffer_t)); } static inline pmix_data_buffer_t* pmix_bfrops_base_tma_data_buffer_create(pmix_tma_t *tma) { pmix_data_buffer_t *b = (pmix_data_buffer_t *)pmix_tma_malloc(tma, sizeof(pmix_data_buffer_t)); if (PMIX_LIKELY(NULL != b)) { pmix_bfrops_base_tma_data_buffer_construct(b, tma); } return b; } static inline void pmix_bfrops_base_tma_data_buffer_destruct(pmix_data_buffer_t *b, pmix_tma_t *tma) { if (NULL != b->base_ptr) { pmix_tma_free(tma, b->base_ptr); b->base_ptr = NULL; } b->pack_ptr = NULL; b->unpack_ptr = NULL; b->bytes_allocated = 0; b->bytes_used = 0; } static inline void pmix_bfrops_base_tma_data_buffer_release(pmix_data_buffer_t *b, pmix_tma_t *tma) { if (NULL != b) { pmix_bfrops_base_tma_data_buffer_destruct(b, tma); pmix_tma_free(tma, b); } } static inline pmix_status_t pmix_bfrops_base_tma_copy_dbuf(pmix_data_buffer_t **dest, pmix_data_buffer_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_data_buffer_t *p = pmix_bfrops_base_tma_data_buffer_create(tma); if (PMIX_UNLIKELY(NULL == p)) { return PMIX_ERR_NOMEM; } *dest = p; // TODO(skg) Add TMA support when necessary. return PMIx_Data_copy_payload(p, src); } static inline void pmix_bfrops_base_tma_value_free(pmix_value_t *v, size_t n, pmix_tma_t *tma) { if (NULL != v) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_value_destruct(&v[m], tma); } pmix_tma_free(tma, v); } } static inline pmix_status_t pmix_bfrops_base_tma_value_unload(pmix_value_t *kv, void **data, size_t *sz, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); // TODO(skg) Add TMA support when necessary. return pmix_bfrops_base_value_unload(kv, data, sz); } static inline pmix_status_t pmix_bfrops_base_tma_copy_regattr(pmix_regattr_t **dest, pmix_regattr_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = pmix_bfrops_base_tma_regattr_create(1, tma); if (PMIX_UNLIKELY(NULL == (*dest))) { return PMIX_ERR_NOMEM; } if (NULL != src->name) { (*dest)->name = pmix_tma_strdup(tma, src->name); } pmix_bfrops_base_tma_load_key((*dest)->string, src->string, tma); (*dest)->type = src->type; (*dest)->description = pmix_bfrops_base_tma_argv_copy(src->description, tma); return PMIX_SUCCESS; } static inline void pmix_bfrops_base_tma_envar_construct(pmix_envar_t *e, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); e->envar = NULL; e->value = NULL; e->separator = '\0'; } static inline void pmix_bfrops_base_tma_envar_destruct(pmix_envar_t *e, pmix_tma_t *tma) { if (NULL != e->envar) { pmix_tma_free(tma, e->envar); e->envar = NULL; } if (NULL != e->value) { pmix_tma_free(tma, e->value); e->value = NULL; } } static inline pmix_envar_t* pmix_bfrops_base_tma_envar_create(size_t n, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_envar_t *e = (pmix_envar_t *)pmix_tma_malloc(tma, n * sizeof(pmix_envar_t)); if (PMIX_LIKELY(NULL != e)) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_envar_construct(&e[m], tma); } } return e; } static inline void pmix_bfrops_base_tma_envar_free(pmix_envar_t *e, size_t n, pmix_tma_t *tma) { if (NULL != e) { for (size_t m = 0; m < n; m++) { pmix_bfrops_base_tma_envar_destruct(&e[m], tma); } pmix_tma_free(tma, e); } } static inline void pmix_bfrops_base_tma_envar_load(pmix_envar_t *e, char *var, char *value, char separator, pmix_tma_t *tma) { if (NULL != var) { e->envar = pmix_tma_strdup(tma, var); } if (NULL != value) { e->value = pmix_tma_strdup(tma, value); } e->separator = separator; } static inline pmix_value_cmp_t pmix_bfrops_base_tma_value_compare(pmix_value_t *v1, pmix_value_t *v2, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(tma); // Note: No need for TMA here because no heap management, just comparisons. return pmix_bfrops_base_value_cmp(v1, v2); } /* * The pmix_data_array_t is a little different in that it is an array of values, * and so we cannot just copy one value at a time. So handle all value types * here. */ static inline pmix_status_t pmix_bfrops_base_tma_copy_darray(pmix_data_array_t **dest, pmix_data_array_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); pmix_status_t rc = PMIX_SUCCESS; *dest = NULL; pmix_data_array_t *p = (pmix_data_array_t *)pmix_tma_calloc(tma, 1, sizeof(pmix_data_array_t)); if (PMIX_UNLIKELY(NULL == p)) { return PMIX_ERR_NOMEM; } p->type = src->type; p->size = src->size; if (0 == p->size || NULL == src->array) { *dest = p; return PMIX_SUCCESS; } /* process based on type of array element */ switch (src->type) { case PMIX_UINT8: case PMIX_INT8: case PMIX_BYTE: p->array = pmix_tma_malloc(tma, src->size); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size); break; case PMIX_UINT16: case PMIX_INT16: p->array = pmix_tma_malloc(tma, src->size * sizeof(uint16_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(uint16_t)); break; case PMIX_UINT32: case PMIX_INT32: p->array = pmix_tma_malloc(tma, src->size * sizeof(uint32_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(uint32_t)); break; case PMIX_UINT64: case PMIX_INT64: p->array = pmix_tma_malloc(tma, src->size * sizeof(uint64_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(uint64_t)); break; case PMIX_BOOL: p->array = pmix_tma_malloc(tma, src->size * sizeof(bool)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(bool)); break; case PMIX_SIZE: p->array = (char *)pmix_tma_malloc(tma, src->size * sizeof(size_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(size_t)); break; case PMIX_PID: p->array = pmix_tma_malloc(tma, src->size * sizeof(pid_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(pid_t)); break; case PMIX_STRING: { p->array = pmix_tma_malloc(tma, src->size * sizeof(char *)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } char **prarray = (char **)p->array; char **strarray = (char **)src->array; for (size_t n = 0; n < src->size; n++) { if (NULL != strarray[n]) { prarray[n] = pmix_tma_strdup(tma, strarray[n]); } } break; } case PMIX_INT: case PMIX_UINT: p->array = pmix_tma_malloc(tma, src->size * sizeof(int)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(int)); break; case PMIX_FLOAT: p->array = pmix_tma_malloc(tma, src->size * sizeof(float)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(float)); break; case PMIX_DOUBLE: p->array = pmix_tma_malloc(tma, src->size * sizeof(double)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(double)); break; case PMIX_TIMEVAL: p->array = pmix_tma_malloc(tma, src->size * sizeof(struct timeval)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(struct timeval)); break; case PMIX_TIME: p->array = pmix_tma_malloc(tma, src->size * sizeof(time_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(time_t)); break; case PMIX_STATUS: p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_status_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(pmix_status_t)); break; case PMIX_VALUE: { p->array = pmix_bfrops_base_tma_value_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_value_t *const pv = (pmix_value_t *)p->array; pmix_value_t *const sv = (pmix_value_t *)src->array; for (size_t n = 0; n < src->size; n++) { if (PMIX_SUCCESS != (rc = pmix_bfrops_base_value_xfer(&pv[n], &sv[n]))) { pmix_bfrops_base_tma_value_free(pv, src->size, tma); break; } } break; } case PMIX_PROC: p->array = pmix_bfrops_base_tma_proc_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(pmix_proc_t)); break; case PMIX_PROC_RANK: p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_rank_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(pmix_rank_t)); break; case PMIX_APP: { p->array = pmix_bfrops_base_tma_app_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_app_t *const pa = (pmix_app_t *)p->array; pmix_app_t *const sa = (pmix_app_t *)src->array; for (size_t n = 0; n < src->size; n++) { if (NULL != sa[n].cmd) { pa[n].cmd = pmix_tma_strdup(tma, sa[n].cmd); } if (NULL != sa[n].argv) { pa[n].argv = pmix_bfrops_base_tma_argv_copy(sa[n].argv, tma); } if (NULL != sa[n].env) { pa[n].env = pmix_bfrops_base_tma_argv_copy(sa[n].env, tma); } if (NULL != sa[n].cwd) { pa[n].cwd = pmix_tma_strdup(tma, sa[n].cwd); } pa[n].maxprocs = sa[n].maxprocs; if (0 < sa[n].ninfo && NULL != sa[n].info) { pa[n].info = pmix_bfrops_base_tma_info_create(sa[n].ninfo, tma); if (PMIX_UNLIKELY(NULL == pa[n].info)) { pmix_bfrops_base_tma_app_free(pa, p->size, tma); rc = PMIX_ERR_NOMEM; break; } pa[n].ninfo = sa[n].ninfo; for (size_t m = 0; m < pa[n].ninfo; m++) { pmix_bfrops_base_tma_info_xfer( &pa[n].info[m], &sa[n].info[m], tma ); } } } break; } case PMIX_INFO: { p->array = pmix_bfrops_base_tma_info_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_info_t *const p1 = (pmix_info_t *)p->array; pmix_info_t *const s1 = (pmix_info_t *)src->array; for (size_t n = 0; n < src->size; n++) { pmix_bfrops_base_tma_info_xfer(&p1[n], &s1[n], tma); } break; } case PMIX_PDATA: { p->array = pmix_bfrops_base_tma_pdata_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_pdata_t *const pd = (pmix_pdata_t *)p->array; pmix_pdata_t *const sd = (pmix_pdata_t *)src->array; for (size_t n = 0; n < src->size; n++) { pmix_bfrops_base_tma_pdata_xfer(&pd[n], &sd[n], tma); } break; } case PMIX_BUFFER: { p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_buffer_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_buffer_t *const pb = (pmix_buffer_t *)p->array; pmix_buffer_t *const sb = (pmix_buffer_t *)src->array; for (size_t n = 0; n < src->size; n++) { PMIX_CONSTRUCT(&pb[n], pmix_buffer_t, tma); pmix_bfrops_base_tma_copy_payload(&pb[n], &sb[n], tma); } break; } case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: { p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_byte_object_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_byte_object_t *const pbo = (pmix_byte_object_t *)p->array; pmix_byte_object_t *const sbo = (pmix_byte_object_t *)src->array; for (size_t n = 0; n < src->size; n++) { if (NULL != sbo[n].bytes && 0 < sbo[n].size) { pbo[n].size = sbo[n].size; pbo[n].bytes = (char *)pmix_tma_malloc(tma, pbo[n].size); memcpy(pbo[n].bytes, sbo[n].bytes, pbo[n].size); } else { pbo[n].bytes = NULL; pbo[n].size = 0; } } break; } case PMIX_KVAL: { p->array = pmix_tma_calloc(tma, src->size, sizeof(pmix_kval_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_kval_t *const pk = (pmix_kval_t *)p->array; pmix_kval_t *const sk = (pmix_kval_t *)src->array; for (size_t n = 0; n < src->size; n++) { if (NULL != sk[n].key) { pk[n].key = pmix_tma_strdup(tma, sk[n].key); } if (NULL != sk[n].value) { pk[n].value = pmix_bfrops_base_tma_value_create(1, tma); if (PMIX_UNLIKELY(NULL == pk[n].value)) { rc = PMIX_ERR_NOMEM; break; } rc = pmix_bfrops_base_tma_value_xfer(pk[n].value, sk[n].value, tma); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { pmix_bfrops_base_tma_value_free(pk[n].value, 1, tma); rc = PMIX_ERR_NOMEM; break; } } } break; } case PMIX_PERSIST: p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_persistence_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(pmix_persistence_t)); break; case PMIX_POINTER: { p->array = pmix_tma_malloc(tma, src->size * sizeof(char *)); char **prarray = (char **)p->array; char **strarray = (char **)src->array; for (size_t n = 0; n < src->size; n++) { prarray[n] = strarray[n]; } break; } case PMIX_SCOPE: p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_scope_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(pmix_scope_t)); break; case PMIX_DATA_RANGE: p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_data_range_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(pmix_data_range_t)); break; case PMIX_COMMAND: p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_cmd_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(pmix_cmd_t)); break; case PMIX_INFO_DIRECTIVES: p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_info_directives_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } memcpy(p->array, src->array, src->size * sizeof(pmix_info_directives_t)); break; case PMIX_PROC_INFO: { p->array = pmix_bfrops_base_tma_proc_info_create( src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_proc_info_t *const pi = (pmix_proc_info_t *)p->array; pmix_proc_info_t *const si = (pmix_proc_info_t *)src->array; for (size_t n = 0; n < src->size; n++) { memcpy(&pi[n].proc, &si[n].proc, sizeof(pmix_proc_t)); if (NULL != si[n].hostname) { pi[n].hostname = pmix_tma_strdup(tma, si[n].hostname); } else { pi[n].hostname = NULL; } if (NULL != si[n].executable_name) { pi[n].executable_name = pmix_tma_strdup(tma, si[n].executable_name); } else { pi[n].executable_name = NULL; } pi[n].pid = si[n].pid; pi[n].exit_code = si[n].exit_code; pi[n].state = si[n].state; } break; } case PMIX_DATA_ARRAY: rc = PMIX_ERR_NOT_SUPPORTED; // don't support iterative arrays break; case PMIX_QUERY: { p->array = pmix_bfrops_base_tma_query_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_query_t *const pq = (pmix_query_t *)p->array; pmix_query_t *const sq = (pmix_query_t *)src->array; for (size_t n = 0; n < src->size; n++) { if (NULL != sq[n].keys) { pq[n].keys = pmix_bfrops_base_tma_argv_copy(sq[n].keys, tma); } if (NULL != sq[n].qualifiers && 0 < sq[n].nqual) { pq[n].qualifiers = pmix_bfrops_base_tma_info_create(sq[n].nqual, tma); if (NULL == pq[n].qualifiers) { rc = PMIX_ERR_NOMEM; break; } for (size_t m = 0; m < sq[n].nqual; m++) { pmix_bfrops_base_tma_info_xfer( &pq[n].qualifiers[m], &sq[n].qualifiers[m], tma ); } pq[n].nqual = sq[n].nqual; } else { pq[n].qualifiers = NULL; pq[n].nqual = 0; } } break; } case PMIX_ENVAR: { p->array = pmix_bfrops_base_tma_envar_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_envar_t *const pe = (pmix_envar_t *)p->array; pmix_envar_t *const se = (pmix_envar_t *)src->array; for (size_t n = 0; n < src->size; n++) { if (NULL != se[n].envar) { pe[n].envar = pmix_tma_strdup(tma, se[n].envar); } if (NULL != se[n].value) { pe[n].value = pmix_tma_strdup(tma, se[n].value); } pe[n].separator = se[n].separator; } break; } case PMIX_COORD: { p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_coord_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_coord_t *const pc = (pmix_coord_t *)p->array; pmix_coord_t *const sc = (pmix_coord_t *)src->array; for (size_t n = 0; n < src->size; n++) { rc = pmix_bfrops_base_tma_fill_coord(&pc[n], &sc[n], tma); if (PMIX_SUCCESS != rc) { pmix_bfrops_base_tma_coord_free(pc, src->size, tma); break; } } break; } case PMIX_REGATTR: { p->array = pmix_bfrops_base_tma_regattr_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_regattr_t *const pr = (pmix_regattr_t *)p->array; pmix_regattr_t *const sr = (pmix_regattr_t *)src->array; for (size_t n = 0; n < src->size; n++) { if (NULL != sr[n].name) { pr[n].name = pmix_tma_strdup(tma, sr[n].name); } pmix_bfrops_base_tma_load_key(pr[n].string, sr[n].string, tma); pr[n].type = sr[n].type; pr[n].description = pmix_bfrops_base_tma_argv_copy(sr[n].description, tma); } break; } case PMIX_PROC_CPUSET: { p->array = pmix_bfrops_base_tma_cpuset_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_cpuset_t *const pcpuset = (pmix_cpuset_t *)p->array; pmix_cpuset_t *const scpuset = (pmix_cpuset_t *)src->array; for (size_t n = 0; n < src->size; n++) { // TODO(skg) Add TMA support when necessary. rc = pmix_hwloc_copy_cpuset(&pcpuset[n], &scpuset[n]); if (PMIX_SUCCESS != rc) { // TODO(skg) Add TMA support when necessary. pmix_hwloc_release_cpuset(pcpuset, src->size); pmix_tma_free(tma, p->array); break; } } break; } case PMIX_GEOMETRY: { p->array = pmix_bfrops_base_tma_geometry_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_geometry_t *const pgeoset = (pmix_geometry_t *)p->array; pmix_geometry_t *const sgeoset = (pmix_geometry_t *)src->array; for (size_t n = 0; n < src->size; n++) { pgeoset[n].fabric = sgeoset[n].fabric; if (NULL != sgeoset[n].uuid) { pgeoset[n].uuid = pmix_tma_strdup(tma, sgeoset[n].uuid); } if (NULL != sgeoset[n].osname) { pgeoset[n].osname = pmix_tma_strdup(tma, sgeoset[n].osname); } if (NULL != sgeoset[n].coordinates) { pgeoset[n].ncoords = sgeoset[n].ncoords; pgeoset[n].coordinates = (pmix_coord_t *)pmix_tma_malloc(tma, pgeoset[n].ncoords * sizeof(pmix_coord_t)); if (PMIX_UNLIKELY(NULL == pgeoset[n].coordinates)) { rc = PMIX_ERR_NOMEM; break; } for (size_t m = 0; m < pgeoset[n].ncoords; m++) { rc = pmix_bfrops_base_tma_fill_coord( &pgeoset[n].coordinates[m], &sgeoset[n].coordinates[m], tma ); if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { pmix_bfrops_base_tma_geometry_free(pgeoset, src->size, tma); break; } } } if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { break; } } break; } case PMIX_DEVICE: { p->array = pmix_bfrops_base_tma_device_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_device_t *const pdev = (pmix_device_t *)p->array; pmix_device_t *const sdev = (pmix_device_t *)src->array; for (size_t n = 0; n < src->size; n++) { if (NULL != sdev[n].uuid) { pdev[n].uuid = pmix_tma_strdup(tma, sdev[n].uuid); } if (NULL != sdev[n].osname) { pdev[n].osname = pmix_tma_strdup(tma, sdev[n].osname); } pdev[n].type = sdev[n].type; } break; } case PMIX_RESOURCE_UNIT: { p->array = pmix_bfrops_base_tma_resource_unit_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_resource_unit_t *const pdev = (pmix_resource_unit_t *)p->array; pmix_resource_unit_t *const sdev = (pmix_resource_unit_t *)src->array; for (size_t n = 0; n < src->size; n++) { memcpy(&pdev[n], &sdev[n], sizeof(pmix_resource_unit_t)); } break; } case PMIX_DEVICE_DIST: { p->array = pmix_bfrops_base_tma_device_distance_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_device_distance_t *const pdevdist = (pmix_device_distance_t *)p->array; pmix_device_distance_t *const sdevdist = (pmix_device_distance_t *)src->array; for (size_t n = 0; n < src->size; n++) { if (NULL != sdevdist[n].uuid) { pdevdist[n].uuid = pmix_tma_strdup(tma, sdevdist[n].uuid); } if (NULL != sdevdist[n].osname) { pdevdist[n].osname = pmix_tma_strdup(tma, sdevdist[n].osname); } pdevdist[n].type = sdevdist[n].type; pdevdist[n].mindist = sdevdist[n].mindist; pdevdist[n].maxdist = sdevdist[n].maxdist; } break; } case PMIX_ENDPOINT: { p->array = pmix_bfrops_base_tma_endpoint_create(src->size, tma); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } pmix_endpoint_t *const pendpt = (pmix_endpoint_t *)p->array; pmix_endpoint_t *const sendpt = (pmix_endpoint_t *)src->array; for (size_t n = 0; n < src->size; n++) { if (NULL != sendpt[n].uuid) { pendpt[n].uuid = pmix_tma_strdup(tma, sendpt[n].uuid); } if (NULL != sendpt[n].osname) { pendpt[n].osname = pmix_tma_strdup(tma, sendpt[n].osname); } if (NULL != sendpt[n].endpt.bytes) { pendpt[n].endpt.bytes = (char *)pmix_tma_malloc(tma, sendpt[n].endpt.size); memcpy(pendpt[n].endpt.bytes, sendpt[n].endpt.bytes, sendpt[n].endpt.size); pendpt[n].endpt.size = sendpt[n].endpt.size; } } break; } case PMIX_PROC_NSPACE: { p->array = pmix_tma_malloc(tma, src->size * sizeof(pmix_nspace_t)); if (PMIX_UNLIKELY(NULL == p->array)) { rc = PMIX_ERR_NOMEM; break; } p->size = src->size; pmix_nspace_t *const pns = (pmix_nspace_t *)p->array; pmix_nspace_t *const sns = (pmix_nspace_t *)src->array; for (size_t n = 0; n < src->size; n++) { pmix_bfrops_base_tma_load_nspace(pns[n], sns[n], tma); } break; } default: rc = PMIX_ERR_UNKNOWN_DATA_TYPE; } if (PMIX_UNLIKELY(PMIX_SUCCESS != rc)) { PMIX_ERROR_LOG(rc); pmix_tma_free(tma, p); p = NULL; } *dest = p; return rc; } static inline pmix_status_t pmix_bfrops_base_tma_value_xfer(pmix_value_t *p, const pmix_value_t *src, pmix_tma_t *tma) { pmix_status_t rc; /* copy the right field */ p->type = src->type; switch (src->type) { case PMIX_UNDEF: break; case PMIX_BOOL: p->data.flag = src->data.flag; break; case PMIX_BYTE: p->data.byte = src->data.byte; break; case PMIX_STRING: if (NULL != src->data.string) { p->data.string = pmix_tma_strdup(tma, src->data.string); } else { p->data.string = NULL; } break; case PMIX_SIZE: p->data.size = src->data.size; break; case PMIX_PID: p->data.pid = src->data.pid; break; case PMIX_INT: /* to avoid alignment issues */ memcpy(&p->data.integer, &src->data.integer, sizeof(int)); break; case PMIX_INT8: p->data.int8 = src->data.int8; break; case PMIX_INT16: /* to avoid alignment issues */ memcpy(&p->data.int16, &src->data.int16, 2); break; case PMIX_INT32: /* to avoid alignment issues */ memcpy(&p->data.int32, &src->data.int32, 4); break; case PMIX_INT64: /* to avoid alignment issues */ memcpy(&p->data.int64, &src->data.int64, 8); break; case PMIX_UINT: /* to avoid alignment issues */ memcpy(&p->data.uint, &src->data.uint, sizeof(unsigned int)); break; case PMIX_UINT8: p->data.uint8 = src->data.uint8; break; case PMIX_UINT16: case PMIX_STOR_ACCESS_TYPE: /* to avoid alignment issues */ memcpy(&p->data.uint16, &src->data.uint16, 2); break; case PMIX_UINT32: /* to avoid alignment issues */ memcpy(&p->data.uint32, &src->data.uint32, 4); break; case PMIX_UINT64: case PMIX_STOR_MEDIUM: case PMIX_STOR_ACCESS: case PMIX_STOR_PERSIST: /* to avoid alignment issues */ memcpy(&p->data.uint64, &src->data.uint64, 8); break; case PMIX_FLOAT: p->data.fval = src->data.fval; break; case PMIX_DOUBLE: p->data.dval = src->data.dval; break; case PMIX_TIMEVAL: memcpy(&p->data.tv, &src->data.tv, sizeof(struct timeval)); break; case PMIX_TIME: memcpy(&p->data.time, &src->data.time, sizeof(time_t)); break; case PMIX_STATUS: memcpy(&p->data.status, &src->data.status, sizeof(pmix_status_t)); break; case PMIX_PROC_RANK: memcpy(&p->data.rank, &src->data.rank, sizeof(pmix_rank_t)); break; case PMIX_PROC_NSPACE: return pmix_bfrops_base_tma_copy_nspace(&p->data.nspace, src->data.nspace, PMIX_PROC_NSPACE, tma); case PMIX_PROC: p->data.proc = pmix_bfrops_base_tma_proc_create(1, tma); if (PMIX_UNLIKELY(NULL == p->data.proc)) { return PMIX_ERR_NOMEM; } memcpy(p->data.proc, src->data.proc, sizeof(pmix_proc_t)); break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: case PMIX_REGEX: case PMIX_COMPRESSED_BYTE_OBJECT: memset(&p->data.bo, 0, sizeof(pmix_byte_object_t)); if (NULL != src->data.bo.bytes && 0 < src->data.bo.size) { p->data.bo.bytes = pmix_tma_malloc(tma, src->data.bo.size); memcpy(p->data.bo.bytes, src->data.bo.bytes, src->data.bo.size); p->data.bo.size = src->data.bo.size; } else { p->data.bo.bytes = NULL; p->data.bo.size = 0; } break; case PMIX_PERSIST: memcpy(&p->data.persist, &src->data.persist, sizeof(pmix_persistence_t)); break; case PMIX_SCOPE: memcpy(&p->data.scope, &src->data.scope, sizeof(pmix_scope_t)); break; case PMIX_DATA_RANGE: memcpy(&p->data.range, &src->data.range, sizeof(pmix_data_range_t)); break; case PMIX_PROC_STATE: memcpy(&p->data.state, &src->data.state, sizeof(pmix_proc_state_t)); break; case PMIX_PROC_INFO: return pmix_bfrops_base_tma_copy_pinfo(&p->data.pinfo, src->data.pinfo, PMIX_PROC_INFO, tma); case PMIX_DATA_ARRAY: return pmix_bfrops_base_tma_copy_darray(&p->data.darray, src->data.darray, PMIX_DATA_ARRAY, tma); case PMIX_POINTER: p->data.ptr = src->data.ptr; break; case PMIX_ALLOC_DIRECTIVE: memcpy(&p->data.adir, &src->data.adir, sizeof(pmix_alloc_directive_t)); break; case PMIX_RESBLOCK_DIRECTIVE: memcpy(&p->data.rbdir, &src->data.rbdir, sizeof(pmix_resource_block_directive_t)); break; case PMIX_ENVAR: pmix_bfrops_base_tma_envar_construct(&p->data.envar, tma); if (NULL != src->data.envar.envar) { p->data.envar.envar = pmix_tma_strdup(tma, src->data.envar.envar); } if (NULL != src->data.envar.value) { p->data.envar.value = pmix_tma_strdup(tma, src->data.envar.value); } p->data.envar.separator = src->data.envar.separator; break; case PMIX_COORD: return pmix_bfrops_base_tma_copy_coord(&p->data.coord, src->data.coord, PMIX_COORD, tma); case PMIX_LINK_STATE: memcpy(&p->data.linkstate, &src->data.linkstate, sizeof(pmix_link_state_t)); break; case PMIX_JOB_STATE: memcpy(&p->data.jstate, &src->data.jstate, sizeof(pmix_job_state_t)); break; case PMIX_TOPO: rc = pmix_bfrops_base_tma_copy_topology(&p->data.topo, src->data.topo, PMIX_TOPO, tma); if (PMIX_ERR_INIT == rc || PMIX_ERR_NOT_SUPPORTED == rc) { /* we are being asked to do this before init, so * just copy the pointer across */ p->data.topo = src->data.topo; } break; case PMIX_PROC_CPUSET: rc = pmix_bfrops_base_tma_copy_cpuset(&p->data.cpuset, src->data.cpuset, PMIX_PROC_CPUSET, tma); if (PMIX_ERR_INIT == rc || PMIX_ERR_NOT_SUPPORTED == rc) { /* we are being asked to do this before init, so * just copy the pointer across */ p->data.cpuset = src->data.cpuset; } break; case PMIX_LOCTYPE: memcpy(&p->data.locality, &src->data.locality, sizeof(pmix_locality_t)); break; case PMIX_GEOMETRY: return pmix_bfrops_base_tma_copy_geometry(&p->data.geometry, src->data.geometry, PMIX_GEOMETRY, tma); case PMIX_DEVTYPE: memcpy(&p->data.devtype, &src->data.devtype, sizeof(pmix_device_type_t)); break; case PMIX_DEVICE: return pmix_bfrops_base_tma_copy_device(&p->data.device, src->data.device, PMIX_DEVICE, tma); case PMIX_RESOURCE_UNIT: return pmix_bfrops_base_tma_copy_resource_unit(&p->data.resunit, src->data.resunit, PMIX_RESOURCE_UNIT, tma); case PMIX_DEVICE_DIST: return pmix_bfrops_base_tma_copy_devdist(&p->data.devdist, src->data.devdist, PMIX_DEVICE_DIST, tma); case PMIX_ENDPOINT: return pmix_bfrops_base_tma_copy_endpoint(&p->data.endpoint, src->data.endpoint, PMIX_ENDPOINT, tma); case PMIX_REGATTR: return pmix_bfrops_base_tma_copy_regattr((pmix_regattr_t **) &p->data.ptr, src->data.ptr, PMIX_REGATTR, tma); case PMIX_DATA_BUFFER: return pmix_bfrops_base_tma_copy_dbuf(&p->data.dbuf, src->data.dbuf, PMIX_DATA_BUFFER, tma); default: pmix_output(0, "PMIX-XFER-VALUE: UNSUPPORTED TYPE %d", (int) src->type); return PMIX_ERROR; } return PMIX_SUCCESS; } static inline pmix_status_t pmix_bfrops_base_tma_copy_value(pmix_value_t **dest, pmix_value_t *src, pmix_data_type_t type, pmix_tma_t *tma) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_value_t *)pmix_tma_malloc(tma, sizeof(pmix_value_t)); if (PMIX_UNLIKELY(NULL == *dest)) { return PMIX_ERR_OUT_OF_RESOURCE; } pmix_value_t *p = *dest; /* copy the type */ p->type = src->type; /* copy the data */ return pmix_bfrops_base_tma_value_xfer(p, src, tma); } static inline void pmix_bfrops_base_tma_data_array_destruct(pmix_data_array_t *d, pmix_tma_t *tma) { switch (d->type) { case PMIX_STRING: { char **s = (char**)d->array; for (size_t n = 0; n < d->size; n++) { if (NULL != s[n]) { pmix_tma_free(tma, s[n]); } } pmix_tma_free(tma, d->array); break; } case PMIX_VALUE: pmix_bfrops_base_tma_value_free(d->array, d->size, tma); break; case PMIX_APP: pmix_bfrops_base_tma_app_free(d->array, d->size, tma); break; case PMIX_INFO: pmix_bfrops_base_tma_info_free(d->array, d->size, tma); break; case PMIX_PDATA: pmix_bfrops_base_tma_pdata_free(d->array, d->size, tma); break; case PMIX_BUFFER: { pmix_buffer_t *const pb = (pmix_buffer_t *)d->array; for (size_t n = 0; n < d->size; n++) { PMIX_DESTRUCT(&pb[n]); } pmix_tma_free(tma, d->array); break; } case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: case PMIX_COMPRESSED_BYTE_OBJECT: { pmix_byte_object_t *const bo = (pmix_byte_object_t *)d->array; for (size_t n = 0; n < d->size; n++) { if (NULL != bo[n].bytes) { pmix_tma_free(tma, bo[n].bytes); } } pmix_tma_free(tma, d->array); break; } case PMIX_KVAL: { pmix_kval_t *const kv = (pmix_kval_t *)d->array; for (size_t n = 0; n < d->size; n++) { if (NULL != kv[n].key) { pmix_tma_free(tma, kv[n].key); } if (NULL != kv[n].value) { pmix_bfrops_base_tma_value_free(kv[n].value, 1, tma); } } pmix_tma_free(tma, d->array); break; } case PMIX_PROC_INFO: pmix_bfrops_base_tma_proc_info_free(d->array, d->size, tma); break; case PMIX_DATA_ARRAY: pmix_bfrops_base_tma_data_array_destruct(d->array, tma); break; case PMIX_QUERY: pmix_bfrops_base_tma_query_free(d->array, d->size, tma); break; case PMIX_ENVAR: pmix_bfrops_base_tma_envar_free(d->array, d->size, tma); break; case PMIX_COORD: pmix_bfrops_base_tma_coord_free(d->array, d->size, tma); break; case PMIX_REGATTR: pmix_bfrops_base_tma_regattr_free(d->array, d->size, tma); break; case PMIX_PROC_CPUSET: // TODO(skg) Add TMA support when necessary. pmix_hwloc_release_cpuset(d->array, d->size); break; case PMIX_TOPO: // TODO(skg) Add TMA support when necessary. pmix_hwloc_release_topology(d->array, d->size); break; case PMIX_GEOMETRY: pmix_bfrops_base_tma_geometry_free(d->array, d->size, tma); break; case PMIX_DEVICE: pmix_bfrops_base_tma_device_free(d->array, d->size, tma); break; case PMIX_RESOURCE_UNIT: pmix_bfrops_base_tma_resource_unit_free(d->array, d->size, tma); break; case PMIX_DEVICE_DIST: pmix_bfrops_base_tma_device_distance_free(d->array, d->size, tma); break; case PMIX_ENDPOINT: pmix_bfrops_base_tma_endpoint_free(d->array, d->size, tma); break; case PMIX_REGEX: { pmix_byte_object_t *const bo = (pmix_byte_object_t *)d->array; for (size_t n = 0; n < d->size; n++) { if (NULL != bo[n].bytes) { // TODO(skg) Add TMA support when necessary. pmix_preg.release(bo[n].bytes); } } pmix_tma_free(tma, d->array); break; } case PMIX_DATA_BUFFER: { pmix_data_buffer_t *const db = (pmix_data_buffer_t *)d->array; for (size_t n = 0; n < d->size; n++) { pmix_bfrops_base_tma_data_buffer_destruct(&db[n], tma); } pmix_tma_free(tma, d->array); break; } default: if (NULL != d->array) { pmix_tma_free(tma, d->array); } break; } d->array = NULL; d->type = PMIX_UNDEF; d->size = 0; } static inline void pmix_bfrops_base_tma_data_array_free(pmix_data_array_t *p, pmix_tma_t *tma) { if (NULL != p) { pmix_bfrops_base_tma_data_array_destruct(p, tma); pmix_tma_free(tma, p); } } static inline void pmix_bfrops_base_tma_data_array_construct(pmix_data_array_t *p, size_t num, pmix_data_type_t type, pmix_tma_t *tma) { p->type = type; p->size = num; if (0 < num) { if (PMIX_INFO == type) { p->array = pmix_bfrops_base_tma_info_create(num, tma); } else if (PMIX_PROC == type) { p->array = pmix_bfrops_base_tma_proc_create(num, tma); } else if (PMIX_PROC_INFO == type) { p->array = pmix_bfrops_base_tma_proc_info_create(num, tma); } else if (PMIX_ENVAR == type) { p->array = pmix_bfrops_base_tma_envar_create(num, tma); } else if (PMIX_VALUE == type) { p->array = pmix_bfrops_base_tma_value_create(num, tma); } else if (PMIX_PDATA == type) { p->array = pmix_bfrops_base_tma_pdata_create(num, tma); } else if (PMIX_QUERY == type) { p->array = pmix_bfrops_base_tma_query_create(num, tma); } else if (PMIX_APP == type) { p->array = pmix_bfrops_base_tma_app_create(num, tma); } else if (PMIX_BYTE_OBJECT == type || PMIX_COMPRESSED_STRING == type) { p->array = pmix_bfrops_base_tma_byte_object_create(num, tma); } else if (PMIX_ALLOC_DIRECTIVE == type || PMIX_PROC_STATE == type || PMIX_PERSIST == type || PMIX_SCOPE == type || PMIX_DATA_RANGE == type || PMIX_BYTE == type || PMIX_INT8 == type || PMIX_UINT8 == type || PMIX_POINTER == type) { p->array = pmix_tma_malloc(tma, num * sizeof(int8_t)); memset(p->array, 0, num * sizeof(int8_t)); } else if (PMIX_STRING == type) { p->array = pmix_tma_malloc(tma, num * sizeof(char*)); memset(p->array, 0, num * sizeof(char*)); } else if (PMIX_SIZE == type) { p->array = pmix_tma_malloc(tma, num * sizeof(size_t)); memset(p->array, 0, num * sizeof(size_t)); } else if (PMIX_PID == type) { p->array = pmix_tma_malloc(tma, num * sizeof(pid_t)); memset(p->array, 0, num * sizeof(pid_t)); } else if (PMIX_INT == type || PMIX_UINT == type || PMIX_STATUS == type) { p->array = pmix_tma_malloc(tma, num * sizeof(int)); memset(p->array, 0, num * sizeof(int)); } else if (PMIX_IOF_CHANNEL == type || PMIX_DATA_TYPE == type || PMIX_INT16 == type || PMIX_UINT16 == type) { p->array = pmix_tma_malloc(tma, num * sizeof(int16_t)); memset(p->array, 0, num * sizeof(int16_t)); } else if (PMIX_PROC_RANK == type || PMIX_INFO_DIRECTIVES == type || PMIX_INT32 == type || PMIX_UINT32 == type) { p->array = pmix_tma_malloc(tma, num * sizeof(int32_t)); memset(p->array, 0, num * sizeof(int32_t)); } else if (PMIX_INT64 == type || PMIX_UINT64 == type) { p->array = pmix_tma_malloc(tma, num * sizeof(int64_t)); memset(p->array, 0, num * sizeof(int64_t)); } else if (PMIX_FLOAT == type) { p->array = pmix_tma_malloc(tma, num * sizeof(float)); memset(p->array, 0, num * sizeof(float)); } else if (PMIX_DOUBLE == type) { p->array = pmix_tma_malloc(tma, num * sizeof(double)); memset(p->array, 0, num * sizeof(double)); } else if (PMIX_TIMEVAL == type) { p->array = pmix_tma_malloc(tma, num * sizeof(struct timeval)); memset(p->array, 0, num * sizeof(struct timeval)); } else if (PMIX_TIME == type) { p->array = pmix_tma_malloc(tma, num * sizeof(time_t)); memset(p->array, 0, num * sizeof(time_t)); } else if (PMIX_REGATTR == type) { p->array = pmix_bfrops_base_tma_regattr_create(num, tma); } else if (PMIX_BOOL == type) { p->array = pmix_tma_malloc(tma, num * sizeof(bool)); memset(p->array, 0, num * sizeof(bool)); } else if (PMIX_COORD == type) { /* cannot use PMIx_Coord_create as we do not * know the number of dimensions */ p->array = pmix_tma_malloc(tma, num * sizeof(pmix_coord_t)); memset(p->array, 0, num * sizeof(pmix_coord_t)); } else if (PMIX_LINK_STATE == type) { p->array = pmix_tma_malloc(tma, num * sizeof(pmix_link_state_t)); memset(p->array, 0, num * sizeof(pmix_link_state_t)); } else if (PMIX_ENDPOINT == type) { p->array = pmix_bfrops_base_tma_endpoint_create(num, tma); } else if (PMIX_PROC_NSPACE == type) { p->array = pmix_tma_malloc(tma, num * sizeof(pmix_nspace_t)); memset(p->array, 0, num * sizeof(pmix_nspace_t)); } else if (PMIX_DEVICE == type) { p->array = pmix_bfrops_base_tma_device_create(num, tma); } else if (PMIX_RESOURCE_UNIT == type) { p->array = pmix_bfrops_base_tma_resource_unit_create(num, tma); } else if (PMIX_DEVICE_DIST == type) { p->array = pmix_bfrops_base_tma_device_distance_create(num, tma); } else if (PMIX_GEOMETRY == type) { p->array = pmix_bfrops_base_tma_geometry_create(num, tma); } else if (PMIX_PROC_CPUSET == type) { p->array = pmix_bfrops_base_tma_cpuset_create(num, tma); } else { p->array = NULL; p->size = 0; } } else { p->array = NULL; } } static inline pmix_data_array_t* pmix_bfrops_base_tma_data_array_create(size_t n, pmix_data_type_t type, pmix_tma_t *tma) { if (0 == n) { return NULL; } pmix_data_array_t *p = (pmix_data_array_t *)pmix_tma_malloc(tma, sizeof(pmix_data_array_t)); if (PMIX_LIKELY(NULL != p)) { pmix_bfrops_base_tma_data_array_construct(p, n, type, tma); } return p; } // Note **v to maintain sematics of PMIX_VALUE_RELEASE(). static inline void pmix_bfrops_base_tma_value_release(pmix_value_t **v, pmix_tma_t *tma) { pmix_bfrops_base_tma_value_destruct(*v, tma); pmix_tma_free(tma, *v); *v = NULL; } static inline void pmix_bfrops_base_tma_value_destruct(pmix_value_t *v, pmix_tma_t *tma) { switch (v->type) { case PMIX_STRING: if (NULL != v->data.string) { pmix_tma_free(tma, v->data.string); } break; case PMIX_PROC: if (NULL != v->data.proc) { pmix_bfrops_base_tma_proc_free(v->data.proc, 1, tma); } break; case PMIX_BYTE_OBJECT: case PMIX_COMPRESSED_STRING: case PMIX_COMPRESSED_BYTE_OBJECT: if (NULL != v->data.bo.bytes) { pmix_tma_free(tma, v->data.bo.bytes); } break; case PMIX_PROC_INFO: if (NULL != v->data.pinfo) { pmix_bfrops_base_tma_proc_info_free(v->data.pinfo, 1, tma); } break; case PMIX_DATA_ARRAY: if (NULL != v->data.darray) { pmix_bfrops_base_tma_data_array_free(v->data.darray, tma); } break; case PMIX_ENVAR: if (NULL != v->data.envar.envar) { pmix_tma_free(tma, v->data.envar.envar); } if (NULL != v->data.envar.value) { pmix_tma_free(tma, v->data.envar.value); } break; case PMIX_COORD: if (NULL != v->data.coord) { pmix_bfrops_base_tma_coord_free(v->data.coord, 1, tma); } break; case PMIX_TOPO: if (NULL != v->data.topo) { pmix_bfrops_base_tma_topology_free(v->data.topo, 1, tma); } break; case PMIX_PROC_CPUSET: if (NULL != v->data.cpuset) { // TODO(skg) Add TMA support when necessary. pmix_hwloc_release_cpuset(v->data.cpuset, 1); } break; case PMIX_GEOMETRY: if (NULL != v->data.geometry) { pmix_bfrops_base_tma_geometry_free(v->data.geometry, 1, tma); } break; case PMIX_DEVICE: if (NULL != v->data.device) { pmix_bfrops_base_tma_device_free(v->data.device, 1, tma); } break; case PMIX_RESOURCE_UNIT: if (NULL != v->data.resunit) { pmix_bfrops_base_tma_resource_unit_free(v->data.resunit, 1, tma); } break; case PMIX_DEVICE_DIST: if (NULL != v->data.devdist) { pmix_bfrops_base_tma_device_distance_free(v->data.devdist, 1, tma); } break; case PMIX_ENDPOINT: if (NULL != v->data.endpoint) { pmix_bfrops_base_tma_endpoint_free(v->data.endpoint, 1, tma); } break; case PMIX_REGATTR: if (NULL != v->data.ptr) { pmix_bfrops_base_tma_regattr_free(v->data.ptr, 1, tma); } break; case PMIX_REGEX: if (NULL != v->data.bo.bytes) { // TODO(skg) Add TMA support when necessary. pmix_preg.release(v->data.bo.bytes); } break; case PMIX_DATA_BUFFER: if (NULL != v->data.dbuf) { pmix_bfrops_base_tma_data_buffer_release(v->data.dbuf, tma); } break; default: /* silence warnings */ break; } // mark the value as no longer defined memset(v, 0, sizeof(pmix_value_t)); v->type = PMIX_UNDEF; return; } #endif pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_print.c0000664000175000017500000021246015203536752022720 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_stdint.h" #include #ifdef HAVE_TIME_H # include #endif #include "src/include/pmix_globals.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_printf.h" char* PMIx_Info_string(const pmix_info_t *info) { pmix_status_t rc; char *output , *tmp; rc = pmix_bfrops_base_print_info(&tmp, NULL, (void*)info, PMIX_INFO); if (PMIX_SUCCESS != rc) { return NULL; } pmix_asprintf(&output, "%s\n", tmp); free(tmp); return output; } char* PMIx_Value_string(const pmix_value_t *value) { pmix_status_t rc; char *output = NULL; rc = pmix_bfrops_base_print_value(&output, NULL, (void*)value, PMIX_VALUE); if (PMIX_SUCCESS != rc) { return NULL; } return output; } pmix_status_t pmix_bfrops_base_print(pmix_pointer_array_t *regtypes, char **output, char *prefix, void *src, pmix_data_type_t type) { pmix_bfrop_type_info_t *info; /* check for error */ if (NULL == output || NULL == src) { return PMIX_ERR_BAD_PARAM; } /* Lookup the print function for this type and call it */ if (NULL == (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(regtypes, type))) { return PMIX_ERR_UNKNOWN_DATA_TYPE; } return info->odti_print_fn(output, prefix, src, type); } /* * STANDARD PRINT FUNCTIONS FOR SYSTEM TYPES */ int pmix_bfrops_base_print_bool(char **output, char *prefix, bool *src, pmix_data_type_t type) { int ret; if (PMIX_BOOL != type) { return PMIX_ERR_BAD_PARAM; } /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_BOOL\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_BOOL\tValue: %s", (NULL == prefix) ? " " : prefix, (*src) ? "TRUE" : "FALSE"); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_byte(char **output, char *prefix, uint8_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_BYTE\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_BYTE\tValue: %x", (NULL == prefix) ? " " : prefix, *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_string(char **output, char *prefix, char *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_STRING\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_STRING\tValue: %s", (NULL == prefix) ? " " : prefix, src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_size(char **output, char *prefix, size_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_SIZE\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_SIZE\tValue: %lu", (NULL == prefix) ? " " : prefix, (unsigned long) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_pid(char **output, char *prefix, pid_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_PID\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_PID\tValue: %lu", (NULL == prefix) ? " " : prefix, (unsigned long) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_int(char **output, char *prefix, int *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_INT\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_INT\tValue: %ld", (NULL == prefix) ? " " : prefix, (long) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_uint(char **output, char *prefix, uint *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_UINT\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_UINT\tValue: %lu", (NULL == prefix) ? " " : prefix, (unsigned long) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_uint8(char **output, char *prefix, uint8_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_UINT8\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_UINT8\tValue: %u", (NULL == prefix) ? " " : prefix, (unsigned int) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_uint16(char **output, char *prefix, uint16_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_UINT16\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_UINT16\tValue: %u", (NULL == prefix) ? " " : prefix, (unsigned int) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_uint32(char **output, char *prefix, uint32_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_UINT32\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_UINT32\tValue: %u", (NULL == prefix) ? " " : prefix, (unsigned int) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_int8(char **output, char *prefix, int8_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_INT8\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_INT8\tValue: %d", (NULL == prefix) ? " " : prefix, (int) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_int16(char **output, char *prefix, int16_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_INT16\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_INT16\tValue: %d", (NULL == prefix) ? " " : prefix, (int) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_int32(char **output, char *prefix, int32_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_INT32\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_INT32\tValue: %d", (NULL == prefix) ? " " : prefix, (int) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_uint64(char **output, char *prefix, uint64_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_UINT64\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_UINT64\tValue: %lu", (NULL == prefix) ? " " : prefix, (unsigned long) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_int64(char **output, char *prefix, int64_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_INT64\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_INT64\tValue: %ld", (NULL == prefix) ? " " : prefix, (long) *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_float(char **output, char *prefix, float *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_FLOAT\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_FLOAT\tValue: %f", (NULL == prefix) ? " " : prefix, *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_double(char **output, char *prefix, double *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_DOUBLE\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_DOUBLE\tValue: %f", (NULL == prefix) ? " " : prefix, *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_time(char **output, char *prefix, time_t *src, pmix_data_type_t type) { char *t; int ret; struct tm *local; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_TIME\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } local = localtime(src); t = asctime(local); t[strlen(t) - 1] = '\0'; // remove trailing newline ret = asprintf(output, "%sData type: PMIX_TIME\tValue: %s", (NULL == prefix) ? " " : prefix, t); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_timeval(char **output, char *prefix, struct timeval *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_TIMEVAL\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_TIMEVAL\tValue: %lu.%lu", (NULL == prefix) ? " " : prefix, (unsigned long)src->tv_sec, (unsigned long)src->tv_usec); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_status(char **output, char *prefix, pmix_status_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_STATUS\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_STATUS\tValue: %s", (NULL == prefix) ? " " : prefix, PMIx_Error_string(*src)); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } /* PRINT FUNCTIONS FOR GENERIC PMIX TYPES */ static int print_val(char **output, pmix_value_t *src) { int rc; char *tp; switch (src->type) { case PMIX_UNDEF: tp = strdup(" Data type: PMIX_UNDEF"); rc = PMIX_SUCCESS; break; case PMIX_BOOL: rc = pmix_bfrops_base_print_bool(&tp, NULL, &src->data.flag, PMIX_BOOL); break; case PMIX_BYTE: rc = pmix_bfrops_base_print_byte(&tp, NULL, &src->data.byte, PMIX_STRING); break; case PMIX_STRING: rc = pmix_bfrops_base_print_string(&tp, NULL, src->data.string, PMIX_STRING); break; case PMIX_SIZE: rc = pmix_bfrops_base_print_size(&tp, NULL, &src->data.size, PMIX_SIZE); break; case PMIX_PID: rc = pmix_bfrops_base_print_pid(&tp, NULL, &src->data.pid, PMIX_PID); break; case PMIX_INT: rc = pmix_bfrops_base_print_int(&tp, NULL, &src->data.integer, PMIX_INT); break; case PMIX_INT8: rc = pmix_bfrops_base_print_int8(&tp, NULL, &src->data.int8, PMIX_INT8); break; case PMIX_INT16: rc = pmix_bfrops_base_print_int16(&tp, NULL, &src->data.int16, PMIX_INT16); break; case PMIX_INT32: rc = pmix_bfrops_base_print_int32(&tp, NULL, &src->data.int32, PMIX_INT32); break; case PMIX_INT64: rc = pmix_bfrops_base_print_int64(&tp, NULL, &src->data.int64, PMIX_INT64); break; case PMIX_UINT: rc = pmix_bfrops_base_print_uint(&tp, NULL, &src->data.uint, PMIX_UINT); break; case PMIX_UINT8: rc = pmix_bfrops_base_print_uint8(&tp, NULL, &src->data.uint8, PMIX_UINT8); break; case PMIX_UINT16: rc = pmix_bfrops_base_print_uint16(&tp, NULL, &src->data.uint16, PMIX_UINT16); break; case PMIX_UINT32: rc = pmix_bfrops_base_print_uint32(&tp, NULL, &src->data.uint32, PMIX_UINT32); break; case PMIX_UINT64: rc = pmix_bfrops_base_print_uint64(&tp, NULL, &src->data.uint64, PMIX_UINT64); break; case PMIX_FLOAT: rc = pmix_bfrops_base_print_float(&tp, NULL, &src->data.fval, PMIX_FLOAT); break; case PMIX_DOUBLE: rc = pmix_bfrops_base_print_double(&tp, NULL, &src->data.dval, PMIX_DOUBLE); break; case PMIX_TIMEVAL: rc = pmix_bfrops_base_print_timeval(&tp, NULL, &src->data.tv, PMIX_TIMEVAL); break; case PMIX_TIME: rc = pmix_bfrops_base_print_time(&tp, NULL, &src->data.time, PMIX_TIME); break; case PMIX_STATUS: rc = pmix_bfrops_base_print_status(&tp, NULL, &src->data.status, PMIX_STATUS); break; case PMIX_PROC_RANK: rc = pmix_bfrops_base_print_rank(&tp, NULL, &src->data.rank, PMIX_PROC_RANK); break; case PMIX_PROC_NSPACE: rc = pmix_bfrops_base_print_nspace(&tp, NULL, src->data.nspace, PMIX_PROC_NSPACE); break; case PMIX_PROC: rc = pmix_bfrops_base_print_proc(&tp, NULL, src->data.proc, PMIX_PROC); break; case PMIX_BYTE_OBJECT: rc = pmix_bfrops_base_print_bo(&tp, NULL, &src->data.bo, PMIX_BYTE_OBJECT); break; case PMIX_PERSIST: rc = pmix_bfrops_base_print_persist(&tp, NULL, &src->data.persist, PMIX_PERSIST); break; case PMIX_SCOPE: rc = pmix_bfrops_base_print_scope(&tp, NULL, &src->data.scope, PMIX_SCOPE); break; case PMIX_DATA_RANGE: rc = pmix_bfrops_base_print_range(&tp, NULL, &src->data.range, PMIX_DATA_RANGE); break; case PMIX_PROC_STATE: rc = pmix_bfrops_base_print_pstate(&tp, NULL, &src->data.state, PMIX_PROC_STATE); break; case PMIX_PROC_INFO: rc = pmix_bfrops_base_print_pinfo(&tp, NULL, src->data.pinfo, PMIX_PROC_INFO); break; case PMIX_DATA_ARRAY: rc = pmix_bfrops_base_print_darray(&tp, NULL, src->data.darray, PMIX_DATA_ARRAY); break; case PMIX_REGATTR: rc = pmix_bfrops_base_print_regattr(&tp, NULL, src->data.ptr, PMIX_REGATTR); break; case PMIX_ALLOC_DIRECTIVE: rc = pmix_bfrops_base_print_alloc_directive(&tp, NULL, &src->data.adir, PMIX_ALLOC_DIRECTIVE); break; case PMIX_RESBLOCK_DIRECTIVE: rc = pmix_bfrops_base_print_resblock_directive(&tp, NULL, &src->data.adir, PMIX_RESBLOCK_DIRECTIVE); break; case PMIX_ENVAR: rc = pmix_bfrops_base_print_envar(&tp, NULL, &src->data.envar, PMIX_ENVAR); break; case PMIX_COORD: rc = pmix_bfrops_base_print_coord(&tp, NULL, src->data.coord, PMIX_COORD); break; case PMIX_LINK_STATE: rc = pmix_bfrops_base_print_linkstate(&tp, NULL, &src->data.linkstate, PMIX_LINK_STATE); break; case PMIX_JOB_STATE: rc = pmix_bfrops_base_print_jobstate(&tp, NULL, &src->data.jstate, PMIX_JOB_STATE); break; case PMIX_TOPO: rc = pmix_bfrops_base_print_topology(&tp, NULL, src->data.topo, PMIX_TOPO); break; case PMIX_PROC_CPUSET: rc = pmix_bfrops_base_print_cpuset(&tp, NULL, src->data.cpuset, PMIX_PROC_CPUSET); break; case PMIX_LOCTYPE: rc = pmix_bfrops_base_print_locality(&tp, NULL, &src->data.locality, PMIX_LOCTYPE); break; case PMIX_GEOMETRY: rc = pmix_bfrops_base_print_geometry(&tp, NULL, src->data.geometry, PMIX_GEOMETRY); break; case PMIX_DEVTYPE: rc = pmix_bfrops_base_print_devtype(&tp, NULL, &src->data.devtype, PMIX_DEVTYPE); break; case PMIX_DEVICE: rc = pmix_bfrops_base_print_device(&tp, NULL, src->data.device, PMIX_DEVICE); break; case PMIX_DEVICE_DIST: rc = pmix_bfrops_base_print_devdist(&tp, NULL, src->data.devdist, PMIX_DEVICE_DIST); break; case PMIX_ENDPOINT: rc = pmix_bfrops_base_print_endpoint(&tp, NULL, src->data.endpoint, PMIX_ENDPOINT); break; case PMIX_STOR_MEDIUM: rc = pmix_bfrops_base_print_smed(&tp, NULL, &src->data.uint64, PMIX_STOR_MEDIUM); break; case PMIX_STOR_ACCESS: rc = pmix_bfrops_base_print_sacc(&tp, NULL, &src->data.uint64, PMIX_STOR_ACCESS); break; case PMIX_STOR_PERSIST: rc = pmix_bfrops_base_print_spers(&tp, NULL, &src->data.uint64, PMIX_STOR_PERSIST); break; case PMIX_STOR_ACCESS_TYPE: rc = pmix_bfrops_base_print_satyp(&tp, NULL, &src->data.uint16, PMIX_STOR_ACCESS_TYPE); break; case PMIX_NODE_PID: rc = pmix_bfrops_base_print_nodepid(&tp, NULL, src->data.nodepid, PMIX_NODE_PID); break; default: pmix_asprintf(&tp, " Data type: %s(%d)\tValue: UNPRINTABLE", PMIx_Data_type_string(src->type), (int)(src->type)); rc = PMIX_SUCCESS; break; } *output = tp; return rc; } /* * PMIX_VALUE */ int pmix_bfrops_base_print_value(char **output, char *prefix, pmix_value_t *src, pmix_data_type_t type) { int rc; char *tp; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { pmix_asprintf(output, "%sData type: PMIX_VALUE\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); return PMIX_SUCCESS; } rc = print_val(&tp, src); if (PMIX_SUCCESS == rc) { rc = asprintf(output, "%sPMIX_VALUE: %s", (NULL == prefix) ? " " : prefix, tp); free(tp); } if (0 > rc) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_info(char **output, char *prefix, pmix_info_t *src, pmix_data_type_t type) { char *tmp = NULL, *tmp2 = NULL; int ret; PMIX_HIDE_UNUSED_PARAMS(type); pmix_bfrops_base_print_value(&tmp, prefix, &src->value, PMIX_VALUE); pmix_bfrops_base_print_info_directives(&tmp2, prefix, &src->flags, PMIX_INFO_DIRECTIVES); ret = asprintf(output, "%sKEY: %s\n%s\t%s\n%s\t%s", (NULL == prefix) ? " " : prefix, PMIx_Get_attribute_name(src->key), (NULL == prefix) ? " " : prefix, tmp2, (NULL == prefix) ? " " : prefix, tmp); free(tmp); free(tmp2); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_pdata(char **output, char *prefix, pmix_pdata_t *src, pmix_data_type_t type) { char *tmp1, *tmp2; int ret; PMIX_HIDE_UNUSED_PARAMS(type); pmix_bfrops_base_print_proc(&tmp1, prefix, &src->proc, PMIX_PROC); pmix_bfrops_base_print_value(&tmp2, prefix, &src->value, PMIX_VALUE); ret = asprintf(output, "%s %s KEY: %s %s", (NULL == prefix) ? " " : prefix, tmp1, PMIx_Get_attribute_name(src->key), (NULL == tmp2) ? "NULL" : tmp2); if (NULL != tmp1) { free(tmp1); } if (NULL != tmp2) { free(tmp2); } if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_buf(char **output, char *prefix, pmix_buffer_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } int pmix_bfrops_base_print_app(char **output, char *prefix, pmix_app_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } int pmix_bfrops_base_print_proc(char **output, char *prefix, pmix_proc_t *src, pmix_data_type_t type) { int rc; PMIX_HIDE_UNUSED_PARAMS(type); if (NULL == src){ *output = strdup("%sPROC: NULL"); rc = PMIX_SUCCESS; } else { switch (src->rank) { case PMIX_RANK_UNDEF: rc = asprintf(output, "%sPROC: %s:PMIX_RANK_UNDEF", (NULL == prefix) ? " " : prefix, src->nspace); break; case PMIX_RANK_WILDCARD: rc = asprintf(output, "%sPROC: %s:PMIX_RANK_WILDCARD", (NULL == prefix) ? " " : prefix, src->nspace); break; case PMIX_RANK_LOCAL_NODE: rc = asprintf(output, "%sPROC: %s:PMIX_RANK_LOCAL_NODE", (NULL == prefix) ? " " : prefix, src->nspace); break; default: rc = asprintf(output, "%sPROC: %s:%lu", (NULL == prefix) ? " " : prefix , src->nspace, (unsigned long) (src->rank)); } } if (0 > rc) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } int pmix_bfrops_base_print_kval(char **output, char *prefix, pmix_kval_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } int pmix_bfrops_base_print_persist(char **output, char *prefix, pmix_persistence_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_PERSIST\tValue: NULL pointer", (NULL == prefix) ? " " : prefix)) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_PERSIST\tValue: %ld", (NULL == prefix) ? " " : prefix, (long) *src)) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_print_scope(char **output, char *prefix, pmix_scope_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); if (0 > asprintf(output, "%sData type: PMIX_SCOPE\tValue: %s", (NULL == prefix) ? " " : prefix, PMIx_Scope_string(*src))) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_print_range(char **output, char *prefix, pmix_data_range_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); if (0 > asprintf(output, "%sData type: PMIX_DATA_RANGE\tValue: %s", (NULL == prefix) ? " " : prefix, PMIx_Data_range_string(*src))) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_print_cmd(char **output, char *prefix, pmix_cmd_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); if (0 > asprintf(output, "%sData type: PMIX_COMMAND\tValue: %s", (NULL == prefix) ? " " : prefix, pmix_command_string(*src))) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_print_info_directives(char **output, char *prefix, pmix_info_directives_t *src, pmix_data_type_t type) { char *tmp; PMIX_HIDE_UNUSED_PARAMS(type); tmp = PMIx_Info_directives_string(*src); if (0 > asprintf(output, "%sPMIX_INFO_DIRECTIVES\tValue: %s", (NULL == prefix) ? " " : prefix, tmp)) { free(tmp); return PMIX_ERR_NOMEM; } free(tmp); return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_print_datatype(char **output, char *prefix, pmix_data_type_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: PMIX_DATA_TYPE\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: PMIX_DATA_TYPE\tValue: %s", (NULL == prefix) ? " " : prefix, PMIx_Data_type_string(*src)); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_bo(char **output, char *prefix, pmix_byte_object_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { ret = asprintf(output, "%sData type: %s\tValue: NULL pointer", (NULL == prefix) ? " " : prefix, (PMIX_COMPRESSED_BYTE_OBJECT == type) ? "PMIX_COMPRESSED_BYTE_OBJECT" : "PMIX_BYTE_OBJECT"); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } ret = asprintf(output, "%sData type: %s\tSize: %ld", (NULL == prefix) ? " " : prefix, (PMIX_COMPRESSED_BYTE_OBJECT == type) ? "PMIX_COMPRESSED_BYTE_OBJECT" : "PMIX_BYTE_OBJECT", (long) src->size); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } int pmix_bfrops_base_print_ptr(char **output, char *prefix, void *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_POINTER\tAddress: %p", (NULL == prefix) ? " " : prefix, src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_pstate(char **output, char *prefix, pmix_proc_state_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_PROC_STATE\tValue: %s", (NULL == prefix) ? " " : prefix, PMIx_Proc_state_string(*src)); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_pinfo(char **output, char *prefix, pmix_proc_info_t *src, pmix_data_type_t type) { pmix_status_t rc = PMIX_SUCCESS; char *p2, *tmp; PMIX_HIDE_UNUSED_PARAMS(type); if (0 > asprintf(&p2, "%s\t", (NULL == prefix) ? " " : prefix)) { rc = PMIX_ERR_NOMEM; goto done; } if (PMIX_SUCCESS != (rc = pmix_bfrops_base_print_proc(&tmp, p2, &src->proc, PMIX_PROC))) { free(p2); goto done; } if (0 > asprintf(output, "%sData type: PMIX_PROC_INFO\tValue:\n%s\n%sHostname: %s\tExecutable: " "%s\n%sPid: %lu\tExit code: %d\tState: %s", (NULL == prefix) ? " " : prefix, tmp, p2, (NULL == src->hostname) ? "NULL" : src->hostname, (NULL == src->executable_name) ? "NULL" : src->executable_name, p2, (unsigned long) src->pid, src->exit_code, PMIx_Proc_state_string(src->state))) { free(p2); rc = PMIX_ERR_NOMEM; } done: return rc; } pmix_status_t pmix_bfrops_base_print_darray(char **output, char *prefix, pmix_data_array_t *src, pmix_data_type_t type) { char *tp, *tp2=NULL, *tp3; pmix_status_t rc = PMIX_ERR_BAD_PARAM; size_t n; bool *bptr; uint8_t *u8ptr; int8_t *i8ptr; uint16_t *u16ptr; int16_t *i16ptr; uint32_t *u32ptr; int32_t *i32ptr; uint64_t *u64ptr; int64_t *i64ptr; char **strings; size_t *szptr; pid_t *pidptr; unsigned int *uintptr; int *intptr; float *fltptr; double *dblptr; struct timeval *tvlptr; time_t *tmptr; pmix_status_t *stptr; pmix_rank_t *rkptr; pmix_nspace_t *nsptr; pmix_proc_t *procptr; pmix_info_t *iptr; pmix_byte_object_t *boptr; pmix_persistence_t *prstptr; pmix_scope_t *scptr; pmix_data_range_t *drptr; pmix_proc_state_t *psptr; pmix_proc_info_t *piptr; pmix_data_array_t *daptr; pmix_regattr_t *rgptr; pmix_alloc_directive_t *adptr; pmix_resource_block_directive_t *rbptr; pmix_envar_t *evptr; pmix_coord_t *coptr; pmix_link_state_t *lkptr; pmix_job_state_t *jsptr; pmix_topology_t *tptr; pmix_cpuset_t *cpsptr; pmix_locality_t *lcptr; pmix_geometry_t *geoptr; pmix_device_type_t *dvptr; pmix_device_t *dev; pmix_resource_unit_t *resunit; pmix_device_distance_t *ddptr; pmix_endpoint_t *endptr; pmix_storage_medium_t *smptr; pmix_storage_accessibility_t *saptr; pmix_storage_persistence_t *spptr; pmix_storage_access_type_t *satptr; pmix_node_pid_t *ndpidptr; PMIX_HIDE_UNUSED_PARAMS(type); for (n=0; n < src->size; n++) { tp = NULL; switch (src->type) { case PMIX_BOOL: bptr = (bool*)src->array; rc = pmix_bfrops_base_print_bool(&tp, prefix, &bptr[n], PMIX_BOOL); break; case PMIX_BYTE: u8ptr = (uint8_t*)src->array; rc = pmix_bfrops_base_print_byte(&tp, prefix, &u8ptr[n], PMIX_STRING); break; case PMIX_STRING: strings = (char**)src->array; rc = pmix_bfrops_base_print_string(&tp, prefix, strings[n], PMIX_STRING); break; case PMIX_SIZE: szptr = (size_t*)src->array; rc = pmix_bfrops_base_print_size(&tp, prefix, &szptr[n], PMIX_SIZE); break; case PMIX_PID: pidptr = (pid_t*)src->array; rc = pmix_bfrops_base_print_pid(&tp, prefix, &pidptr[n], PMIX_PID); break; case PMIX_INT: intptr = (int*)src->array; rc = pmix_bfrops_base_print_int(&tp, prefix, &intptr[n], PMIX_INT); break; case PMIX_INT8: i8ptr = (int8_t*)src->array; rc = pmix_bfrops_base_print_int8(&tp, prefix, &i8ptr[n], PMIX_INT8); break; case PMIX_INT16: i16ptr = (int16_t*)src->array; rc = pmix_bfrops_base_print_int16(&tp, prefix, &i16ptr[n], PMIX_INT16); break; case PMIX_INT32: i32ptr = (int32_t*)src->array; rc = pmix_bfrops_base_print_int32(&tp, prefix, &i32ptr[n], PMIX_INT32); break; case PMIX_INT64: i64ptr = (int64_t*)src->array; rc = pmix_bfrops_base_print_int64(&tp, prefix, &i64ptr[n], PMIX_INT64); break; case PMIX_UINT: uintptr = (unsigned int*)src->array; rc = pmix_bfrops_base_print_uint(&tp, prefix, &uintptr[n], PMIX_UINT); break; case PMIX_UINT8: u8ptr = (uint8_t*)src->array; rc = pmix_bfrops_base_print_uint8(&tp, prefix, &u8ptr[n], PMIX_UINT8); break; case PMIX_UINT16: u16ptr = (uint16_t*)src->array; rc = pmix_bfrops_base_print_uint16(&tp, prefix, &u16ptr[n], PMIX_UINT16); break; case PMIX_UINT32: u32ptr = (uint32_t*)src->array; rc = pmix_bfrops_base_print_uint32(&tp, prefix, &u32ptr[n], PMIX_UINT32); break; case PMIX_UINT64: u64ptr = (uint64_t*)src->array; rc = pmix_bfrops_base_print_uint64(&tp, prefix, &u64ptr[n], PMIX_UINT64); break; case PMIX_FLOAT: fltptr = (float*)src->array; rc = pmix_bfrops_base_print_float(&tp, prefix, &fltptr[n], PMIX_FLOAT); break; case PMIX_DOUBLE: dblptr = (double*)src->array; rc = pmix_bfrops_base_print_double(&tp, prefix, &dblptr[n], PMIX_DOUBLE); break; case PMIX_TIMEVAL: tvlptr = (struct timeval*)src->array; rc = pmix_bfrops_base_print_timeval(&tp, prefix, &tvlptr[n], PMIX_TIMEVAL); break; case PMIX_TIME: tmptr = (time_t*)src->array; rc = pmix_bfrops_base_print_time(&tp, prefix, &tmptr[n], PMIX_TIME); break; case PMIX_STATUS: stptr = (pmix_status_t*)src->array; rc = pmix_bfrops_base_print_status(&tp, prefix, &stptr[n], PMIX_STATUS); break; case PMIX_PROC_RANK: rkptr = (pmix_rank_t*)src->array; rc = pmix_bfrops_base_print_rank(&tp, prefix, &rkptr[n], PMIX_PROC_RANK); break; case PMIX_PROC_NSPACE: nsptr = (pmix_nspace_t*)src->array; rc = pmix_bfrops_base_print_nspace(&tp, prefix, &nsptr[n], PMIX_PROC_NSPACE); break; case PMIX_PROC: procptr = (pmix_proc_t*)src->array; rc = pmix_bfrops_base_print_proc(&tp, prefix, &procptr[n], PMIX_PROC); break; case PMIX_INFO: iptr = (pmix_info_t*)src->array; rc = pmix_bfrops_base_print_info(&tp, prefix, &iptr[n], PMIX_INFO); break; case PMIX_BYTE_OBJECT: boptr = (pmix_byte_object_t*)src->array; rc = pmix_bfrops_base_print_bo(&tp, prefix, &boptr[n], PMIX_BYTE_OBJECT); break; case PMIX_PERSIST: prstptr = (pmix_persistence_t*)src->array; rc = pmix_bfrops_base_print_persist(&tp, prefix, &prstptr[n], PMIX_PERSIST); break; case PMIX_SCOPE: scptr = (pmix_scope_t*)src->array; rc = pmix_bfrops_base_print_scope(&tp, prefix, &scptr[n], PMIX_SCOPE); break; case PMIX_DATA_RANGE: drptr = (pmix_data_range_t*)src->array; rc = pmix_bfrops_base_print_range(&tp, prefix, &drptr[n], PMIX_DATA_RANGE); break; case PMIX_PROC_STATE: psptr = (pmix_proc_state_t*)src->array; rc = pmix_bfrops_base_print_pstate(&tp, prefix, &psptr[n], PMIX_PROC_STATE); break; case PMIX_PROC_INFO: piptr = (pmix_proc_info_t*)src->array; rc = pmix_bfrops_base_print_pinfo(&tp, prefix, &piptr[n], PMIX_PROC_INFO); break; case PMIX_DATA_ARRAY: daptr = (pmix_data_array_t*)src->array; rc = pmix_bfrops_base_print_darray(&tp, prefix, &daptr[n], PMIX_DATA_ARRAY); break; case PMIX_REGATTR: rgptr = (pmix_regattr_t*)src->array; rc = pmix_bfrops_base_print_regattr(&tp, prefix, &rgptr[n], PMIX_REGATTR); break; case PMIX_ALLOC_DIRECTIVE: adptr = (pmix_alloc_directive_t*)src->array; rc = pmix_bfrops_base_print_alloc_directive(&tp, prefix, &adptr[n], PMIX_ALLOC_DIRECTIVE); break; case PMIX_RESBLOCK_DIRECTIVE: rbptr = (pmix_resource_block_directive_t*)src->array; rc = pmix_bfrops_base_print_resblock_directive(&tp, prefix, &rbptr[n], PMIX_RESBLOCK_DIRECTIVE); break; case PMIX_ENVAR: evptr = (pmix_envar_t*)src->array; rc = pmix_bfrops_base_print_envar(&tp, prefix, &evptr[n], PMIX_ENVAR); break; case PMIX_COORD: coptr = (pmix_coord_t*)src->array; rc = pmix_bfrops_base_print_coord(&tp, prefix, &coptr[n], PMIX_COORD); break; case PMIX_LINK_STATE: lkptr = (pmix_link_state_t*)src->array; rc = pmix_bfrops_base_print_linkstate(&tp, prefix, &lkptr[n], PMIX_LINK_STATE); break; case PMIX_JOB_STATE: jsptr = (pmix_job_state_t*)src->array; rc = pmix_bfrops_base_print_jobstate(&tp, prefix, &jsptr[n], PMIX_JOB_STATE); break; case PMIX_TOPO: tptr = (pmix_topology_t*)src->array; rc = pmix_bfrops_base_print_topology(&tp, prefix, &tptr[n], PMIX_TOPO); break; case PMIX_PROC_CPUSET: cpsptr = (pmix_cpuset_t*)src->array; rc = pmix_bfrops_base_print_cpuset(&tp, prefix, &cpsptr[n], PMIX_PROC_CPUSET); break; case PMIX_LOCTYPE: lcptr = (pmix_locality_t*)src->array; rc = pmix_bfrops_base_print_locality(&tp, prefix, &lcptr[n], PMIX_LOCTYPE); break; case PMIX_GEOMETRY: geoptr = (pmix_geometry_t*)src->array; rc = pmix_bfrops_base_print_geometry(&tp, prefix, &geoptr[n], PMIX_GEOMETRY); break; case PMIX_DEVTYPE: dvptr = (pmix_device_type_t*)src->array; rc = pmix_bfrops_base_print_devtype(&tp, prefix, &dvptr[n], PMIX_DEVTYPE); break; case PMIX_DEVICE: dev = (pmix_device_t*)src->array; rc = pmix_bfrops_base_print_device(&tp, prefix, &dev[n], PMIX_DEVICE); break; case PMIX_RESOURCE_UNIT: resunit = (pmix_resource_unit_t*)src->array; rc = pmix_bfrops_base_print_resunit(&tp, prefix, &resunit[n], PMIX_RESOURCE_UNIT); break; case PMIX_DEVICE_DIST: ddptr = (pmix_device_distance_t*)src->array; rc = pmix_bfrops_base_print_devdist(&tp, prefix, &ddptr[n], PMIX_DEVICE_DIST); break; case PMIX_ENDPOINT: endptr = (pmix_endpoint_t*)src->array; rc = pmix_bfrops_base_print_endpoint(&tp, prefix, &endptr[n], PMIX_ENDPOINT); break; case PMIX_STOR_MEDIUM: smptr = (pmix_storage_medium_t*)src->array; rc = pmix_bfrops_base_print_smed(&tp, prefix, &smptr[n], PMIX_STOR_MEDIUM); break; case PMIX_STOR_ACCESS: saptr = (pmix_storage_accessibility_t*)src->array; rc = pmix_bfrops_base_print_sacc(&tp, prefix, &saptr[n], PMIX_STOR_ACCESS); break; case PMIX_STOR_PERSIST: spptr = (pmix_storage_persistence_t*)src->array; rc = pmix_bfrops_base_print_spers(&tp, prefix, &spptr[n], PMIX_STOR_PERSIST); break; case PMIX_STOR_ACCESS_TYPE: satptr = (pmix_storage_access_type_t*)src->array; rc = pmix_bfrops_base_print_satyp(&tp, prefix, &satptr[n], PMIX_STOR_ACCESS_TYPE); break; case PMIX_NODE_PID: ndpidptr = (pmix_node_pid_t*)src->array; rc = pmix_bfrops_base_print_nodepid(&tp, prefix, &ndpidptr[n], PMIX_NODE_PID); break; default: pmix_asprintf(&tp, " Data type: %s(%d)\tValue: UNPRINTABLE", PMIx_Data_type_string(src->type), (int)(src->type)); rc = PMIX_SUCCESS; break; } if (NULL != tp) { if (NULL == tp2) { tp2 = strdup(tp); } else { pmix_asprintf(&tp3, "%s\n%s%s", tp2, (NULL == prefix) ? " " : prefix, tp); free(tp2); tp2 = tp3; } free(tp); } } pmix_asprintf(output, "%sData type: PMIX_DATA_ARRAY\tType: %s\tSize: %lu\n%s%s", (NULL == prefix) ? " " : prefix, PMIx_Data_type_string(src->type), (unsigned long) src->size, (NULL == prefix) ? " " : prefix, (NULL == tp2) ? "NULL" : tp2); free(tp2); return rc; } pmix_status_t pmix_bfrops_base_print_query(char **output, char *prefix, pmix_query_t *src, pmix_data_type_t type) { char *p2; pmix_status_t rc = PMIX_SUCCESS; char *tmp, *t2, *t3; size_t n; PMIX_HIDE_UNUSED_PARAMS(type); if (0 > asprintf(&p2, "%s\t", (NULL == prefix) ? " " : prefix)) { rc = PMIX_ERR_NOMEM; goto done; } if (0 > asprintf(&tmp, "%sData type: PMIX_QUERY\tValue:", (NULL == prefix) ? " " : prefix)) { free(p2); rc = PMIX_ERR_NOMEM; goto done; } /* print out the keys */ if (NULL != src->keys) { for (n = 0; NULL != src->keys[n]; n++) { if (0 > asprintf(&t2, "%s\n%sKey: %s", tmp, p2, src->keys[n])) { free(p2); free(tmp); rc = PMIX_ERR_NOMEM; goto done; } free(tmp); tmp = t2; } } /* now print the qualifiers */ if (0 < src->nqual) { for (n = 0; n < src->nqual; n++) { if (PMIX_SUCCESS != (rc = pmix_bfrops_base_print_info(&t2, p2, &src->qualifiers[n], PMIX_PROC))) { free(p2); free(tmp); goto done; } if (0 > asprintf(&t3, "%s\n%s", tmp, t2)) { free(p2); free(tmp); free(t2); rc = PMIX_ERR_NOMEM; goto done; } free(tmp); free(t2); tmp = t3; } } *output = tmp; free(p2); done: return rc; } pmix_status_t pmix_bfrops_base_print_rank(char **output, char *prefix, pmix_rank_t *src, pmix_data_type_t type) { int rc; PMIX_HIDE_UNUSED_PARAMS(type); switch (*src) { case PMIX_RANK_UNDEF: rc = asprintf(output, "%sData type: PMIX_PROC_RANK\tValue: PMIX_RANK_UNDEF", (NULL == prefix) ? " " : prefix); break; case PMIX_RANK_WILDCARD: rc = asprintf(output, "%sData type: PMIX_PROC_RANK\tValue: PMIX_RANK_WILDCARD", (NULL == prefix) ? " " : prefix); break; case PMIX_RANK_LOCAL_NODE: rc = asprintf(output, "%sData type: PMIX_PROC_RANK\tValue: PMIX_RANK_LOCAL_NODE", (NULL == prefix) ? " " : prefix); break; default: rc = asprintf(output, "%sData type: PMIX_PROC_RANK\tValue: %lu", (NULL == prefix) ? " " : prefix, (unsigned long) (*src)); } if (0 > rc) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_print_alloc_directive(char **output, char *prefix, pmix_alloc_directive_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_ALLOC_DIRECTIVE\tValue: %s", (NULL == prefix) ? " " : prefix, PMIx_Alloc_directive_string(*src)); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_resblock_directive(char **output, char *prefix, pmix_resource_block_directive_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_RESBLOCK_DIRECTIVE\tValue: %s", (NULL == prefix) ? " " : prefix, PMIx_Resource_block_directive_string(*src)); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_iof_channel(char **output, char *prefix, pmix_iof_channel_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_IOF_CHANNEL\tValue: %s", (NULL == prefix) ? " " : prefix, PMIx_IOF_channel_string(*src)); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_envar(char **output, char *prefix, pmix_envar_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_ENVAR\tName: %s\tValue: %s\tSeparator: %c", (NULL == prefix) ? " " : prefix, (NULL == src->envar) ? "NULL" : src->envar, (NULL == src->value) ? "NULL" : src->value, ('\0' == src->separator) ? ' ' : src->separator); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_coord(char **output, char *prefix, pmix_coord_t *src, pmix_data_type_t type) { int ret; char *tp; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_COORD_VIEW_UNDEF == src->view) { tp = "UNDEF"; } else if (PMIX_COORD_LOGICAL_VIEW == src->view) { tp = "LOGICAL"; } else if (PMIX_COORD_PHYSICAL_VIEW == src->view) { tp = "PHYSICAL"; } else { tp = "UNRECOGNIZED"; } ret = asprintf(output, "%sData type: PMIX_COORD\tView: %s\tDims: %lu", (NULL == prefix) ? " " : prefix, tp, (unsigned long) src->dims); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_regattr(char **output, char *prefix, pmix_regattr_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_REGATTR\tName: %s\tString: %s", (NULL == prefix) ? " " : prefix, (NULL == src->name) ? "NULL" : src->name, (0 == strlen(src->string)) ? "NULL" : src->string); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_regex(char **output, char *prefix, char *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_REGEX\tName: %s", (NULL == prefix) ? " " : prefix, src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_jobstate(char **output, char *prefix, pmix_job_state_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_JOB_STATE\tValue: %s", (NULL == prefix) ? " " : prefix, PMIx_Job_state_string(*src)); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_linkstate(char **output, char *prefix, pmix_link_state_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_LINK_STATE\tValue: %s", (NULL == prefix) ? " " : prefix, PMIx_Link_state_string(*src)); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_cpuset(char **output, char *prefix, pmix_cpuset_t *src, pmix_data_type_t type) { char *string; int ret; PMIX_HIDE_UNUSED_PARAMS(type); string = pmix_hwloc_print_cpuset(src); if (NULL == string) { return PMIX_ERR_NOT_SUPPORTED; } ret = asprintf(output, "%sData type: PMIX_CPUSET\tValue: %s", (NULL == prefix) ? " " : prefix, string); free(string); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_geometry(char **output, char *prefix, pmix_geometry_t *src, pmix_data_type_t type) { char *tmp, **result = NULL; int ret; size_t n; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(&tmp, "%sData type: PMIX_GEOMETRY\tValue: Fabric: %" PRIsize_t " UUID: %s OSName: %s", (NULL == prefix) ? " " : prefix, src->fabric, (NULL == src->uuid) ? "NULL" : src->uuid, (NULL == src->osname) ? "NULL" : src->osname); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } PMIx_Argv_append_nosize(&result, tmp); free(tmp); for (n = 0; n < src->ncoords; n++) { ret = pmix_bfrops_base_print_coord(&tmp, prefix, &src->coordinates[n], PMIX_COORD); if (PMIX_SUCCESS != ret) { if (NULL != result) { PMIx_Argv_free(result); } return ret; } PMIx_Argv_append_nosize(&result, tmp); free(tmp); } *output = PMIx_Argv_join(result, '\n'); PMIx_Argv_free(result); return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_print_device(char **output, char *prefix, pmix_device_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_DEVICE\tValue: UUID: %s OSName: %s Type: %s", (NULL == prefix) ? " " : prefix, (NULL == src->uuid) ? "NULL" : src->uuid, (NULL == src->osname) ? "NULL" : src->osname, PMIx_Device_type_string(src->type)); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_resunit(char **output, char *prefix, pmix_resource_unit_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_RESOURCE_UNIT\tValue: Type: %s Count: %" PRIsize_t "", (NULL == prefix) ? " " : prefix, PMIx_Device_type_string(src->type), src->count); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_devdist(char **output, char *prefix, pmix_device_distance_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_DEVICE_DIST\tValue: UUID: %s OSName: %s Type: %s Min: %u Max: %u", (NULL == prefix) ? " " : prefix, (NULL == src->uuid) ? "NULL" : src->uuid, (NULL == src->osname) ? "NULL" : src->osname, PMIx_Device_type_string(src->type), (unsigned) src->mindist, (unsigned) src->maxdist); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_endpoint(char **output, char *prefix, pmix_endpoint_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_ENDPOINT\tValue: %s(%s) #bytes: %" PRIsize_t, (NULL == prefix) ? " " : prefix, (NULL == src->uuid) ? "NULL" : src->uuid, (NULL == src->osname) ? "NULL" : src->osname, src->endpt.size); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_topology(char **output, char *prefix, pmix_topology_t *src, pmix_data_type_t type) { char *string; int ret; PMIX_HIDE_UNUSED_PARAMS(type); string = pmix_hwloc_print_topology(src); if (NULL == string) { return PMIX_ERR_NOT_SUPPORTED; } ret = asprintf(output, "%sData type: PMIX_TOPO\tValue: %s", (NULL == prefix) ? " " : prefix, string); free(string); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_devtype(char **output, char *prefix, pmix_device_type_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_DEVICE_TYPE\tValue: 0x%" PRIx64, (NULL == prefix) ? " " : prefix, (uint64_t) src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_locality(char **output, char *prefix, pmix_locality_t *src, pmix_data_type_t type) { char **tmp = NULL, *str; int ret; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_LOCALITY_UNKNOWN == *src) { str = strdup("UNKNOWN"); } else if (PMIX_LOCALITY_NONLOCAL == *src) { str = strdup("NONLOCAL"); } else { if (PMIX_LOCALITY_SHARE_HWTHREAD & *src) { PMIx_Argv_append_nosize(&tmp, "HWTHREAD"); } if (PMIX_LOCALITY_SHARE_CORE & *src) { PMIx_Argv_append_nosize(&tmp, "CORE"); } if (PMIX_LOCALITY_SHARE_L1CACHE & *src) { PMIx_Argv_append_nosize(&tmp, "L1"); } if (PMIX_LOCALITY_SHARE_L2CACHE & *src) { PMIx_Argv_append_nosize(&tmp, "L2"); } if (PMIX_LOCALITY_SHARE_L3CACHE & *src) { PMIx_Argv_append_nosize(&tmp, "L3"); } if (PMIX_LOCALITY_SHARE_PACKAGE & *src) { PMIx_Argv_append_nosize(&tmp, "CORE"); } if (PMIX_LOCALITY_SHARE_NUMA & *src) { PMIx_Argv_append_nosize(&tmp, "NUMA"); } if (PMIX_LOCALITY_SHARE_NODE & *src) { PMIx_Argv_append_nosize(&tmp, "NODE"); } str = PMIx_Argv_join(tmp, ':'); PMIx_Argv_free(tmp); } ret = asprintf(output, "%sData type: PMIX_LOCALITY\tValue: %s", (NULL == prefix) ? " " : prefix, str); free(str); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_nspace(char **output, char *prefix, pmix_nspace_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_PROC_NSPACE\tValue: %s", (NULL == prefix) ? " " : prefix, *src); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_dbuf(char **output, char *prefix, pmix_data_buffer_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); /* if src is NULL, just print data type and return */ if (NULL == src) { pmix_asprintf(output, "%sData type: PMIX_DATA_BUFFER\tValue: NULL pointer", (NULL == prefix) ? " " : prefix); return PMIX_SUCCESS; } pmix_asprintf(output, "%sPMIX_DATA_BUFFER NumBytesUsed: %" PRIsize_t "", (NULL == prefix) ? " " : prefix, src->bytes_used); return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_print_smed(char **output, char *prefix, pmix_storage_medium_t *src, pmix_data_type_t type) { char **tmp = NULL, *str; int ret; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_STORAGE_MEDIUM_UNKNOWN & *src) { str = strdup("UNKNOWN"); } else { if (PMIX_STORAGE_MEDIUM_TAPE & *src) { PMIx_Argv_append_nosize(&tmp, "TAPE"); } if (PMIX_STORAGE_MEDIUM_HDD & *src) { PMIx_Argv_append_nosize(&tmp, "HDD"); } if (PMIX_STORAGE_MEDIUM_SSD & *src) { PMIx_Argv_append_nosize(&tmp, "SSD"); } if (PMIX_STORAGE_MEDIUM_NVME & *src) { PMIx_Argv_append_nosize(&tmp, "NVME"); } if (PMIX_STORAGE_MEDIUM_PMEM & *src) { PMIx_Argv_append_nosize(&tmp, "PMEM"); } if (PMIX_STORAGE_MEDIUM_RAM & *src) { PMIx_Argv_append_nosize(&tmp, "RAM"); } str = PMIx_Argv_join(tmp, ':'); PMIx_Argv_free(tmp); } ret = asprintf(output, "%sData type: PMIX_STOR_MEDIUM\tValue: %s", (NULL == prefix) ? " " : prefix, str); free(str); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_sacc(char **output, char *prefix, pmix_storage_accessibility_t *src, pmix_data_type_t type) { char **tmp = NULL, *str; int ret; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_STORAGE_ACCESSIBILITY_NODE & *src) { PMIx_Argv_append_nosize(&tmp, "NODE"); } if (PMIX_STORAGE_ACCESSIBILITY_SESSION & *src) { PMIx_Argv_append_nosize(&tmp, "SESSION"); } if (PMIX_STORAGE_ACCESSIBILITY_JOB & *src) { PMIx_Argv_append_nosize(&tmp, "JOB"); } if (PMIX_STORAGE_ACCESSIBILITY_RACK & *src) { PMIx_Argv_append_nosize(&tmp, "RACK"); } if (PMIX_STORAGE_ACCESSIBILITY_CLUSTER & *src) { PMIx_Argv_append_nosize(&tmp, "CLUSTER"); } if (PMIX_STORAGE_ACCESSIBILITY_REMOTE & *src) { PMIx_Argv_append_nosize(&tmp, "REMOTE"); } str = PMIx_Argv_join(tmp, ':'); PMIx_Argv_free(tmp); ret = asprintf(output, "%sData type: PMIX_STOR_ACCESS\tValue: %s", (NULL == prefix) ? " " : prefix, str); free(str); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_spers(char **output, char *prefix, pmix_storage_persistence_t *src, pmix_data_type_t type) { char **tmp = NULL, *str; int ret; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_STORAGE_PERSISTENCE_TEMPORARY & *src) { PMIx_Argv_append_nosize(&tmp, "TEMPORARY"); } if (PMIX_STORAGE_PERSISTENCE_NODE & *src) { PMIx_Argv_append_nosize(&tmp, "NODE"); } if (PMIX_STORAGE_PERSISTENCE_SESSION & *src) { PMIx_Argv_append_nosize(&tmp, "SESSION"); } if (PMIX_STORAGE_PERSISTENCE_JOB & *src) { PMIx_Argv_append_nosize(&tmp, "JOB"); } if (PMIX_STORAGE_PERSISTENCE_SCRATCH & *src) { PMIx_Argv_append_nosize(&tmp, "SCRATCH"); } if (PMIX_STORAGE_PERSISTENCE_PROJECT & *src) { PMIx_Argv_append_nosize(&tmp, "PROJECT"); } if (PMIX_STORAGE_PERSISTENCE_ARCHIVE & *src) { PMIx_Argv_append_nosize(&tmp, "ARCHIVE"); } str = PMIx_Argv_join(tmp, ':'); PMIx_Argv_free(tmp); ret = asprintf(output, "%sData type: PMIX_STOR_PERSIST\tValue: %s", (NULL == prefix) ? " " : prefix, str); free(str); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_satyp(char **output, char *prefix, pmix_storage_access_type_t *src, pmix_data_type_t type) { char **tmp = NULL, *str; int ret; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_STORAGE_ACCESS_RD & *src) { PMIx_Argv_append_nosize(&tmp, "READ"); } if (PMIX_STORAGE_ACCESS_WR & *src) { PMIx_Argv_append_nosize(&tmp, "WRITE"); } str = PMIx_Argv_join(tmp, ':'); PMIx_Argv_free(tmp); ret = asprintf(output, "%sData type: PMIX_STOR_ACCESS_TYPE\tValue: %s", (NULL == prefix) ? " " : prefix, str); free(str); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } else { return PMIX_SUCCESS; } } pmix_status_t pmix_bfrops_base_print_nodepid(char **output, char *prefix, pmix_node_pid_t *src, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); ret = asprintf(output, "%sData type: PMIX_NODE_PID\tValue: Host %s(%u) PID %d", (NULL == prefix) ? " " : prefix, (NULL == src->hostname) ? "NULL" : src->hostname, src->nodeid, src->pid); return ret; } pmix-6.1.1~rc2/src/mca/bfrops/base/base.h0000664000175000017500000022710215203536752020320 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_BFROP_BASE_H_ #define PMIX_BFROP_BASE_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_pointer_array.h" #include "src/include/pmix_globals.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/mca.h" BEGIN_C_DECLS /* * MCA Framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_bfrops_base_framework; /** * BFROP select function * * Cycle across available components and construct the list * of active modules */ PMIX_EXPORT pmix_status_t pmix_bfrop_base_select(void); /** * Track an active component / module */ struct pmix_bfrops_base_active_module_t { pmix_list_item_t super; pmix_status_t pri; pmix_bfrops_module_t *module; pmix_bfrops_base_component_t *component; }; typedef struct pmix_bfrops_base_active_module_t pmix_bfrops_base_active_module_t; PMIX_CLASS_DECLARATION(pmix_bfrops_base_active_module_t); /* framework globals */ struct pmix_bfrops_globals_t { pmix_list_t actives; bool initialized; bool selected; size_t initial_size; size_t threshold_size; pmix_bfrop_buffer_type_t default_type; }; typedef struct pmix_bfrops_globals_t pmix_bfrops_globals_t; PMIX_EXPORT extern pmix_bfrops_globals_t pmix_bfrops_globals; /* * The default starting chunk size */ #define PMIX_BFROP_DEFAULT_INITIAL_SIZE 128 /* * The default threshold size when we switch from doubling the * buffer size to additively increasing it */ #define PMIX_BFROP_DEFAULT_THRESHOLD_SIZE 1024 /* * Internal type corresponding to size_t. Do not use this in * interface calls - use PMIX_SIZE instead. */ #if SIZEOF_SIZE_T == 1 # define BFROP_TYPE_SIZE_T PMIX_UINT8 #elif SIZEOF_SIZE_T == 2 # define BFROP_TYPE_SIZE_T PMIX_UINT16 #elif SIZEOF_SIZE_T == 4 # define BFROP_TYPE_SIZE_T PMIX_UINT32 #elif SIZEOF_SIZE_T == 8 # define BFROP_TYPE_SIZE_T PMIX_UINT64 #else # error Unsupported size_t size! #endif /* * Internal type corresponding to bool. Do not use this in interface * calls - use PMIX_BOOL instead. */ #if SIZEOF__BOOL == 1 # define BFROP_TYPE_BOOL PMIX_UINT8 #elif SIZEOF__BOOL == 2 # define BFROP_TYPE_BOOL PMIX_UINT16 #elif SIZEOF__BOOL == 4 # define BFROP_TYPE_BOOL PMIX_UINT32 #elif SIZEOF__BOOL == 8 # define BFROP_TYPE_BOOL PMIX_UINT64 #else # error Unsupported bool size! #endif /* * Internal type corresponding to int and unsigned int. Do not use * this in interface calls - use PMIX_INT / PMIX_UINT instead. */ #if SIZEOF_INT == 1 # define BFROP_TYPE_INT PMIX_INT8 # define BFROP_TYPE_UINT PMIX_UINT8 #elif SIZEOF_INT == 2 # define BFROP_TYPE_INT PMIX_INT16 # define BFROP_TYPE_UINT PMIX_UINT16 #elif SIZEOF_INT == 4 # define BFROP_TYPE_INT PMIX_INT32 # define BFROP_TYPE_UINT PMIX_UINT32 #elif SIZEOF_INT == 8 # define BFROP_TYPE_INT PMIX_INT64 # define BFROP_TYPE_UINT PMIX_UINT64 #else # error Unsupported INT size! #endif /* * Internal type corresponding to pid_t. Do not use this in interface * calls - use PMIX_PID instead. */ #if SIZEOF_PID_T == 1 # define BFROP_TYPE_PID_T PMIX_UINT8 #elif SIZEOF_PID_T == 2 # define BFROP_TYPE_PID_T PMIX_UINT16 #elif SIZEOF_PID_T == 4 # define BFROP_TYPE_PID_T PMIX_UINT32 #elif SIZEOF_PID_T == 8 # define BFROP_TYPE_PID_T PMIX_UINT64 #else # error Unsupported pid_t size! #endif /* Unpack generic size macros */ #define PMIX_BFROP_UNPACK_SIZE_MISMATCH(reg_types, unpack_type, remote_type, ret) \ do { \ switch (remote_type) { \ case PMIX_UINT8: \ PMIX_BFROP_UNPACK_SIZE_MISMATCH_FOUND(reg_types, unpack_type, uint8_t, remote_type); \ break; \ case PMIX_INT8: \ PMIX_BFROP_UNPACK_SIZE_MISMATCH_FOUND(reg_types, unpack_type, int8_t, remote_type); \ break; \ case PMIX_UINT16: \ PMIX_BFROP_UNPACK_SIZE_MISMATCH_FOUND(reg_types, unpack_type, uint16_t, remote_type); \ break; \ case PMIX_INT16: \ PMIX_BFROP_UNPACK_SIZE_MISMATCH_FOUND(reg_types, unpack_type, int16_t, remote_type); \ break; \ case PMIX_UINT32: \ PMIX_BFROP_UNPACK_SIZE_MISMATCH_FOUND(reg_types, unpack_type, uint32_t, remote_type); \ break; \ case PMIX_INT32: \ PMIX_BFROP_UNPACK_SIZE_MISMATCH_FOUND(reg_types, unpack_type, int32_t, remote_type); \ break; \ case PMIX_UINT64: \ PMIX_BFROP_UNPACK_SIZE_MISMATCH_FOUND(reg_types, unpack_type, uint64_t, remote_type); \ break; \ case PMIX_INT64: \ PMIX_BFROP_UNPACK_SIZE_MISMATCH_FOUND(reg_types, unpack_type, int64_t, remote_type); \ break; \ default: \ ret = PMIX_ERR_NOT_FOUND; \ } \ } while (0) #define PMIX_BFROPS_PACK_TYPE(r, b, s, n, t, arr) \ do { \ pmix_bfrop_type_info_t *__info; \ /* Lookup the pack function for this type and call it */ \ __info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item((arr), (t)); \ if (NULL == __info) { \ (r) = PMIX_ERR_UNKNOWN_DATA_TYPE; \ } else { \ (r) = __info->odti_pack_fn(arr, b, s, n, t); \ } \ } while (0) #define PMIX_BFROPS_UNPACK_TYPE(r, b, d, n, t, arr) \ do { \ pmix_bfrop_type_info_t *__info; \ /* Lookup the unpack function for this type and call it */ \ __info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item((arr), (t)); \ if (NULL == __info) { \ (r) = PMIX_ERR_UNKNOWN_DATA_TYPE; \ } else { \ (r) = __info->odti_unpack_fn(arr, b, d, n, t); \ } \ } while (0) /* NOTE: do not need to deal with endianness here, as the unpacking of the underling sender-side type will do that for us. Repeat: the data in tmpbuf[] is already in host byte order. */ #define PMIX_BFROP_UNPACK_SIZE_MISMATCH_FOUND(reg_types, unpack_type, tmptype, tmpbfroptype) \ do { \ int32_t i; \ tmptype *tmpbuf = (tmptype *) calloc(*num_vals, sizeof(tmptype)); \ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, tmpbuf, num_vals, tmpbfroptype, reg_types); \ if (PMIX_ERR_UNKNOWN_DATA_TYPE != ret) { \ for (i = 0; i < *num_vals; ++i) { \ ((unpack_type *) dest)[i] = (unpack_type)(tmpbuf[i]); \ } \ } \ free(tmpbuf); \ } while (0) /* for backwards compatibility */ typedef struct pmix_info_array { size_t size; pmix_info_t *array; } pmix_info_array_t; typedef pmix_status_t (*pmix_bfrop_internal_pack_fn_t)(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_values, pmix_data_type_t type); typedef pmix_status_t (*pmix_bfrop_internal_unpack_fn_t)(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *max_num_values, pmix_data_type_t type); /** * Internal struct used for holding registered bfrop functions */ typedef struct { pmix_object_t super; /* type identifier */ pmix_data_type_t odti_type; /** Debugging string name */ char *odti_name; /** Pack function */ pmix_bfrop_internal_pack_fn_t odti_pack_fn; /** Unpack function */ pmix_bfrop_internal_unpack_fn_t odti_unpack_fn; /** copy function */ pmix_bfrop_copy_fn_t odti_copy_fn; /** prpmix_status_t function */ pmix_bfrop_print_fn_t odti_print_fn; } pmix_bfrop_type_info_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_bfrop_type_info_t); /* macro for registering data types - overwrite an existing * duplicate one based on type name */ #define PMIX_REGISTER_TYPE(n, t, p, u, c, pr, arr) \ do { \ pmix_bfrop_type_info_t *_info; \ _info = PMIX_NEW(pmix_bfrop_type_info_t); \ _info->odti_name = strdup((n)); \ _info->odti_type = (t); \ _info->odti_pack_fn = (pmix_bfrop_internal_pack_fn_t)(p); \ _info->odti_unpack_fn = (pmix_bfrop_internal_unpack_fn_t)(u); \ _info->odti_copy_fn = (pmix_bfrop_copy_fn_t)(c); \ _info->odti_print_fn = (pmix_bfrop_print_fn_t)(pr); \ pmix_pointer_array_set_item((arr), (t), _info); \ } while (0) /** * Sizeof by PMIx type integer values. * * r - return status code * t - type (pmix_data_type_t) of integer value * s - size of type in bytes * (see a comment to `pmix_bfrops_pack_flex` for additional details) */ #define PMIX_SQUASH_TYPE_SIZEOF(r, t, s) \ do { \ (r) = PMIX_SUCCESS; \ switch (t) { \ case PMIX_INT16: \ case PMIX_UINT16: \ (s) = SIZEOF_SHORT; \ break; \ case PMIX_INT: \ case PMIX_INT32: \ case PMIX_UINT: \ case PMIX_UINT32: \ (s) = SIZEOF_INT; \ break; \ case PMIX_INT64: \ case PMIX_UINT64: \ (s) = SIZEOF_LONG; \ break; \ case PMIX_SIZE: \ (s) = SIZEOF_SIZE_T; \ break; \ default: \ (r) = PMIX_ERR_BAD_PARAM; \ } \ } while (0) /* API Stub functions */ PMIX_EXPORT char *pmix_bfrops_stub_get_available_modules(void); PMIX_EXPORT pmix_status_t pmix_bfrops_stub_assign_module(struct pmix_peer_t *peer, const char *version); PMIX_EXPORT pmix_buffer_t *pmix_bfrops_stub_create_buffer(struct pmix_peer_t *pr); PMIX_EXPORT void pmix_bfrops_construct_buffer(struct pmix_peer_t *pr, pmix_buffer_t *buf); PMIX_EXPORT pmix_status_t pmix_bfrops_stub_pack(struct pmix_peer_t *peer, pmix_buffer_t *buffer, const void *src, int32_t num_values, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_stub_unpack(struct pmix_peer_t *peer, pmix_buffer_t *buffer, void *dest, int32_t *max_num_values, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_stub_copy(struct pmix_peer_t *peer, void **dest, void *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_stub_print(struct pmix_peer_t *peer, char **output, char *prefix, void *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_stub_copy_payload(struct pmix_peer_t *peer, pmix_buffer_t *dest, pmix_buffer_t *src); PMIX_EXPORT pmix_status_t pmix_bfrops_stub_value_xfer(struct pmix_peer_t *peer, pmix_value_t *dest, const pmix_value_t *src); PMIX_EXPORT void pmix_bfrops_stub_value_load(struct pmix_peer_t *peer, pmix_value_t *v, void *data, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_stub_value_unload(struct pmix_peer_t *peer, pmix_value_t *kv, void **data, size_t *sz); PMIX_EXPORT pmix_value_cmp_t pmix_bfrops_stub_value_cmp(struct pmix_peer_t *peer, pmix_value_t *p1, pmix_value_t *p2); PMIX_EXPORT pmix_status_t pmix_bfrops_stub_register_type( struct pmix_peer_t *peer, const char *name, pmix_data_type_t type, pmix_bfrop_pack_fn_t pack, pmix_bfrop_unpack_fn_t unpack, pmix_bfrop_copy_fn_t copy, pmix_bfrop_print_fn_t print); /* data type string function */ PMIX_EXPORT const char *pmix_bfrops_base_data_type_string(pmix_pointer_array_t *regtypes, pmix_data_type_t type); /* * "Standard" pack functions */ PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_general_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_modex(pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_info_directives(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_pstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_pinfo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_val(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_value_t *p); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_alloc_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_resblock_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_iof_channel(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_envar(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_coord(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_regattr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_regex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_jobstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_linkstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_cpuset(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_geometry(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_device(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_resunit(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_devdist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_endpoint(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_topology(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_devtype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_locality(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_nspace(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_pstats(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_dkstats(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_netstats(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_ndstats(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_dbuf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_smed(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_sacc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_spers(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_satyp(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_pack_nodepid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); /* * "Standard" unpack functions */ PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dst, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_general_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_val(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_value_t *val); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_info_directives(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_pstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_pinfo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_alloc_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_resblock_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_iof_channel(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_envar(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_coord(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_regattr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_regex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_jobstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_linkstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_cpuset(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_geometry(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_device(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_resunit(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_devdist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_endpoint(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_topology(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_devtype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_locality(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_nspace(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_pstats(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_dkstats(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_netstats(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_ndstats(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_dbuf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_smed(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_sacc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_spers(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_satyp(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_nodepid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); /**** DEPRECATED ****/ PMIX_EXPORT pmix_status_t pmix_bfrops_base_unpack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); /* * "Standard" copy functions */ PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy(pmix_pointer_array_t *regtypes, void **dest, void *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_payload(pmix_buffer_t *dest, pmix_buffer_t *src); PMIX_EXPORT pmix_status_t pmix_bfrops_base_std_copy(void **dest, void *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_string(char **dest, char *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_value(pmix_value_t **dest, pmix_value_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_proc(pmix_proc_t **dest, pmix_proc_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_app(pmix_app_t **dest, pmix_app_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_info(pmix_info_t **dest, pmix_info_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_buf(pmix_buffer_t **dest, pmix_buffer_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_kval(pmix_kval_t **dest, pmix_kval_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrop_base_copy_persist(pmix_persistence_t **dest, pmix_persistence_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_bo(pmix_byte_object_t **dest, pmix_byte_object_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_pdata(pmix_pdata_t **dest, pmix_pdata_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_pinfo(pmix_proc_info_t **dest, pmix_proc_info_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_darray(pmix_data_array_t **dest, pmix_data_array_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_query(pmix_query_t **dest, pmix_query_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_envar(pmix_envar_t **dest, pmix_envar_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_coord(pmix_coord_t **dest, pmix_coord_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_regattr(pmix_regattr_t **dest, pmix_regattr_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_regex(char **dest, char *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_cpuset(pmix_cpuset_t **dest, pmix_cpuset_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_geometry(pmix_geometry_t **dest, pmix_geometry_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_device(pmix_device_t **dest, pmix_device_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_resunit(pmix_resource_unit_t **dest, pmix_resource_unit_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_devdist(pmix_device_distance_t **dest, pmix_device_distance_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_endpoint(pmix_endpoint_t **dest, pmix_endpoint_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_topology(pmix_topology_t **dest, pmix_topology_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_nspace(pmix_nspace_t **dest, pmix_nspace_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_dbuf(pmix_data_buffer_t **dest, pmix_data_buffer_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_nodepid(pmix_node_pid_t **dest, pmix_node_pid_t *src, pmix_data_type_t type); /* * "Standard" print functions */ PMIX_EXPORT pmix_status_t pmix_bfrops_base_print(pmix_pointer_array_t *regtypes, char **output, char *prefix, void *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_bool(char **output, char *prefix, bool *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_byte(char **output, char *prefix, uint8_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_string(char **output, char *prefix, char *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_size(char **output, char *prefix, size_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_pid(char **output, char *prefix, pid_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_int(char **output, char *prefix, int *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_int8(char **output, char *prefix, int8_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_int16(char **output, char *prefix, int16_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_int32(char **output, char *prefix, int32_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_int64(char **output, char *prefix, int64_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_uint(char **output, char *prefix, uint *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_uint8(char **output, char *prefix, uint8_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_uint16(char **output, char *prefix, uint16_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_uint32(char **output, char *prefix, uint32_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_uint64(char **output, char *prefix, uint64_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_float(char **output, char *prefix, float *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_double(char **output, char *prefix, double *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_timeval(char **output, char *prefix, struct timeval *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_time(char **output, char *prefix, time_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_status(char **output, char *prefix, pmix_status_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_value(char **output, char *prefix, pmix_value_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_proc(char **output, char *prefix, pmix_proc_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_app(char **output, char *prefix, pmix_app_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_info(char **output, char *prefix, pmix_info_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_buf(char **output, char *prefix, pmix_buffer_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_kval(char **output, char *prefix, pmix_kval_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_persist(char **output, char *prefix, pmix_persistence_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_bo(char **output, char *prefix, pmix_byte_object_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_pdata(char **output, char *prefix, pmix_pdata_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_ptr(char **output, char *prefix, void *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_scope(char **output, char *prefix, pmix_scope_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_range(char **output, char *prefix, pmix_data_range_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_cmd(char **output, char *prefix, pmix_cmd_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_info_directives(char **output, char *prefix, pmix_info_directives_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_datatype(char **output, char *prefix, pmix_data_type_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_pstate(char **output, char *prefix, pmix_proc_state_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_pinfo(char **output, char *prefix, pmix_proc_info_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_darray(char **output, char *prefix, pmix_data_array_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_query(char **output, char *prefix, pmix_query_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_rank(char **output, char *prefix, pmix_rank_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_alloc_directive(char **output, char *prefix, pmix_alloc_directive_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_resblock_directive(char **output, char *prefix, pmix_resource_block_directive_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_iof_channel(char **output, char *prefix, pmix_iof_channel_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_envar(char **output, char *prefix, pmix_envar_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_coord(char **output, char *prefix, pmix_coord_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_regattr(char **output, char *prefix, pmix_regattr_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_regex(char **output, char *prefix, char *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_jobstate(char **output, char *prefix, pmix_job_state_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_linkstate(char **output, char *prefix, pmix_link_state_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_cpuset(char **output, char *prefix, pmix_cpuset_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_geometry(char **output, char *prefix, pmix_geometry_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_device(char **output, char *prefix, pmix_device_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_resunit(char **output, char *prefix, pmix_resource_unit_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_devdist(char **output, char *prefix, pmix_device_distance_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_endpoint(char **output, char *prefix, pmix_endpoint_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_topology(char **output, char *prefix, pmix_topology_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_devtype(char **output, char *prefix, pmix_device_type_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_locality(char **output, char *prefix, pmix_locality_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_nspace(char **output, char *prefix, pmix_nspace_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_dbuf(char **output, char *prefix, pmix_data_buffer_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_smed(char **output, char *prefix, pmix_storage_medium_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_sacc(char **output, char *prefix, pmix_storage_accessibility_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_spers(char **output, char *prefix, pmix_storage_persistence_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_satyp(char **output, char *prefix, pmix_storage_access_type_t *src, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_print_nodepid(char **output, char *prefix, pmix_node_pid_t *src, pmix_data_type_t type); /* * Common helper functions */ PMIX_EXPORT char *pmix_bfrop_buffer_extend(pmix_buffer_t *bptr, size_t bytes_to_add); PMIX_EXPORT bool pmix_bfrop_too_small(pmix_buffer_t *buffer, size_t bytes_reqd); PMIX_EXPORT pmix_status_t pmix_bfrop_store_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrop_get_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t *type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_copy_payload(pmix_buffer_t *dest, pmix_buffer_t *src); PMIX_EXPORT pmix_status_t pmix_bfrops_base_embed_payload(pmix_buffer_t *dest, pmix_byte_object_t *src); PMIX_EXPORT void pmix_bfrops_base_value_load(pmix_value_t *v, const void *data, pmix_data_type_t type); PMIX_EXPORT pmix_status_t pmix_bfrops_base_value_unload(pmix_value_t *kv, void **data, size_t *sz); PMIX_EXPORT pmix_status_t pmix_bfrops_base_value_xfer(pmix_value_t *p, const pmix_value_t *src); PMIX_EXPORT pmix_value_cmp_t pmix_bfrops_base_value_cmp(pmix_value_t *p, pmix_value_t *p1); PMIX_EXPORT void pmix_bfrops_base_value_destruct(pmix_value_t *v); PMIX_EXPORT void pmix_bfrops_base_darray_destruct(pmix_data_array_t *d); PMIX_EXPORT char* pmix_bfrops_base_get_components(void); /** * Maximum size of the type. * * type - Type (PMIX_SIZE, PMIX_INT to PMIX_UINT64) * size - size of the type */ PMIX_EXPORT pmix_status_t pmix_bfrops_base_get_max_size(pmix_data_type_t type, size_t *size); /** * Encode a basic integer type into a contiguous destination buffer. * * type - Type of the 'src' pointer (PMIX_SIZE, PMIX_INT to PMIX_UINT64) * src - pointer to a single basic integer type * dest - pointer to buffer to store data * dst_len - pointer to the packed size of dest, in bytes */ PMIX_EXPORT pmix_status_t pmix_bfrops_base_encode_int(pmix_data_type_t type, void *src, void *dest, size_t *dst_len); /** * Decode a basic a contiguous destination buffer into a basic integer type. * * type - Type of the 'dest' pointer (PMIX_SIZE, PMIX_INT to PMIX_UINT64) * src - pointer to buffer where data was stored * src_len - length, in bytes, of the src buffer * dest - pointer to a single basic integer type * dst_len - pointer to the unpacked size of dest, in bytes */ PMIX_EXPORT pmix_status_t pmix_bfrops_base_decode_int(pmix_data_type_t type, void *src, size_t src_len, void *dest, size_t *dst_len); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_unpack.c0000664000175000017500000020357315203536752023052 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/mca/preg/preg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/bfrops/bfrops_types.h" static pmix_status_t pmix_bfrops_base_unpack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dst, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t rc; pmix_data_type_t local_type; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_unpack_buffer( %p, %p, %lu, %d )\n", (void *) buffer, dst, (long unsigned int) *num_vals, (int) type); /** Unpack the declared data type */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix_bfrop_get_data_type(regtypes, buffer, &local_type))) { PMIX_ERROR_LOG(rc); return rc; } /* if the data types don't match, then return an error */ if (type != local_type) { pmix_output(0, "PMIx bfrop:unpack: got type %s when expecting type %s", PMIx_Data_type_string(local_type), PMIx_Data_type_string(type)); return PMIX_ERR_PACK_MISMATCH; } } PMIX_BFROPS_UNPACK_TYPE(rc, buffer, dst, num_vals, type, regtypes); return rc; } pmix_status_t pmix_bfrops_base_unpack(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dst, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t rc, ret; int32_t local_num, n = 1; pmix_data_type_t local_type; /* check for error */ if (NULL == buffer || NULL == dst || NULL == num_vals) { pmix_output(0, "SOMEONE IS NULL: buffer %s dst %s num_vals %s", (NULL == buffer) ? "NULL" : "GOOD", (NULL == dst) ? "NULL" : "GOOD", (NULL == num_vals) ? "NULL" : "GOOD"); return PMIX_ERR_BAD_PARAM; } /* if user provides a zero for num_vals, then there is no storage allocated * so return an appropriate error */ if (0 == *num_vals) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: inadequate space ( %p, %p, %lu, %d )\n", (void *) buffer, dst, (long unsigned int) *num_vals, (int) type); return PMIX_ERR_UNPACK_INADEQUATE_SPACE; } /** Unpack the declared number of values * REMINDER: it is possible that the buffer is corrupted and that * the BFROP will *think* there is a proper int32_t variable at the * beginning of the unpack region - but that the value is bogus (e.g., just * a byte field in a string array that so happens to have a value that * matches the int32_t data type flag). Therefore, this error check is * NOT completely safe. This is true for ALL unpack functions, not just * int32_t as used here. */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix_bfrop_get_data_type(regtypes, buffer, &local_type))) { *num_vals = 0; /* don't error log here as the user may be unpacking past * the end of the buffer, which isn't necessarily an error */ return rc; } if (PMIX_INT32 != local_type) { /* if the length wasn't first, then error */ *num_vals = 0; return PMIX_ERR_UNPACK_FAILURE; } } n = 1; PMIX_BFROPS_UNPACK_TYPE(rc, buffer, &local_num, &n, PMIX_INT32, regtypes); if (PMIX_SUCCESS != rc) { *num_vals = 0; /* don't error log here as the user may be unpacking past * the end of the buffer, which isn't necessarily an error */ return rc; } pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: found %d values for %d provided storage", local_num, *num_vals); /** if the storage provided is inadequate, set things up * to unpack as much as we can and to return an error code * indicating that everything was not unpacked - the buffer * is left in a state where it can not be further unpacked. */ if (local_num > *num_vals) { local_num = *num_vals; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: inadequate space ( %p, %p, %lu, %d )\n", (void *) buffer, dst, (long unsigned int) *num_vals, (int) type); ret = PMIX_ERR_UNPACK_INADEQUATE_SPACE; } else { /** enough or more than enough storage */ *num_vals = local_num; /** let the user know how many we actually unpacked */ ret = PMIX_SUCCESS; } /** Unpack the value(s) */ rc = pmix_bfrops_base_unpack_buffer(regtypes, buffer, dst, &local_num, type); if (PMIX_SUCCESS != rc) { *num_vals = 0; ret = rc; } return ret; } /* UNPACK GENERIC SYSTEM TYPES */ /* * BOOL */ pmix_status_t pmix_bfrops_base_unpack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint8_t *src; bool *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_bool * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, *num_vals)) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ src = (uint8_t *) buffer->unpack_ptr; dst = (bool *) dest; for (i = 0; i < *num_vals; i++) { if (src[i]) { dst[i] = true; } else { dst[i] = false; } } /* update buffer pointer */ buffer->unpack_ptr += *num_vals; return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_general_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t rc; size_t val_size, avail_size, unpack_size, max_size; int32_t i; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_unpack_integer * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (buffer->pack_ptr == buffer->unpack_ptr) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } PMIX_SQUASH_TYPE_SIZEOF(rc, type, val_size); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } rc = pmix_bfrops_base_get_max_size(type, &max_size); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { avail_size = buffer->pack_ptr - buffer->unpack_ptr; rc = pmix_bfrops_base_decode_int(type, buffer->unpack_ptr, avail_size, (uint8_t *) dest + i * val_size, &unpack_size); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* sanity checks */ if (unpack_size > max_size) { rc = PMIX_ERR_UNPACK_FAILURE; PMIX_ERROR_LOG(rc); return rc; } if (unpack_size > avail_size) { rc = PMIX_ERR_FATAL; PMIX_ERROR_LOG(rc); return rc; } buffer->unpack_ptr += unpack_size; } return PMIX_SUCCESS; } /* * INT */ pmix_status_t pmix_bfrops_base_unpack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, BFROP_TYPE_INT, regtypes); return ret; } /* * SIZE_T */ pmix_status_t pmix_bfrops_base_unpack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, BFROP_TYPE_SIZE_T, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); } return ret; } /* * PID_T */ pmix_status_t pmix_bfrops_base_unpack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix_bfrop_get_data_type(regtypes, buffer, &remote_type))) { return ret; } if (remote_type == BFROP_TYPE_PID_T) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, BFROP_TYPE_PID_T, regtypes); } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, pid_t, remote_type, ret); } return ret; } /* UNPACK FUNCTIONS FOR NON-GENERIC SYSTEM TYPES */ /* * BYTE, CHAR, INT8 */ pmix_status_t pmix_bfrops_base_unpack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_byte * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, *num_vals)) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ memcpy(dest, buffer->unpack_ptr, *num_vals); /* update buffer pointer */ buffer->unpack_ptr += *num_vals; return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_INT16, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; int32_t i, len, n = 1; char **sdest = (char **) dest; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < (*num_vals); ++i) { PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &len, &n, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 == len) { /* zero-length string - unpack the NULL */ sdest[i] = NULL; } else { sdest[i] = (char *) malloc(len); // NULL terminator is included if (NULL == sdest[i]) { return PMIX_ERR_OUT_OF_RESOURCE; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, sdest[i], &len, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; float *desttmp = (float *) dest, tmp; pmix_status_t ret; char *convert; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_float * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 1; convert = NULL; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &convert, &n, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (NULL != convert) { tmp = strtof(convert, NULL); memcpy(&desttmp[i], &tmp, sizeof(tmp)); free(convert); } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; double *desttmp = (double *) dest, tmp; pmix_status_t ret; char *convert; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_double * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 1; convert = NULL; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &convert, &n, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (NULL != convert) { tmp = strtod(convert, NULL); memcpy(&desttmp[i], &tmp, sizeof(tmp)); free(convert); } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; int64_t tmp[2]; struct timeval *desttmp = (struct timeval *) dest, tt; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_timeval * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 2; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, tmp, &n, PMIX_INT64, regtypes); if (PMIX_SUCCESS != ret) { return ret; } tt.tv_sec = tmp[0]; tt.tv_usec = tmp[1]; memcpy(&desttmp[i], &tt, sizeof(tt)); } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; time_t *desttmp = (time_t *) dest, tmp; pmix_status_t ret; uint64_t ui64; /* time_t is a system-dependent size, so cast it * to uint64_t as a generic safe size */ pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_time * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ui64, &n, PMIX_UINT64, regtypes); if (PMIX_SUCCESS != ret) { return ret; } tmp = (time_t) ui64; memcpy(&desttmp[i], &tmp, sizeof(tmp)); } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_status * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* unpack the data */ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_INT32, regtypes); return ret; } /* UNPACK FUNCTIONS FOR GENERIC PMIX TYPES */ /* * PMIX_VALUE */ pmix_status_t pmix_bfrops_base_unpack_val(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_value_t *val) { int m; pmix_status_t ret = PMIX_SUCCESS; m = 1; switch (val->type) { case PMIX_UNDEF: break; case PMIX_PROC: /* this field is now a pointer, so we must allocate storage for it */ PMIX_PROC_CREATE(val->data.proc, m); if (NULL == val->data.proc) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.proc, &m, PMIX_PROC, regtypes); break; case PMIX_PROC_INFO: /* this is now a pointer, so allocate storage for it */ PMIX_PROC_INFO_CREATE(val->data.pinfo, 1); if (NULL == val->data.pinfo) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.pinfo, &m, PMIX_PROC_INFO, regtypes); break; case PMIX_DATA_ARRAY: /* this is now a pointer, so allocate storage for it */ val->data.darray = (pmix_data_array_t *) malloc(sizeof(pmix_data_array_t)); if (NULL == val->data.darray) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.darray, &m, PMIX_DATA_ARRAY, regtypes); break; case PMIX_REGATTR: val->data.ptr = (pmix_regattr_t *) calloc(1, sizeof(pmix_regattr_t)); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.ptr, &m, PMIX_REGATTR, regtypes); return ret; case PMIX_COORD: val->data.coord = (pmix_coord_t *) calloc(1, sizeof(pmix_coord_t)); if (NULL == val->data.coord) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.coord, &m, PMIX_COORD, regtypes); return ret; case PMIX_TOPO: PMIX_TOPOLOGY_CREATE(val->data.topo, 1); if (NULL == val->data.topo) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.topo, &m, PMIX_TOPO, regtypes); return ret; case PMIX_PROC_CPUSET: PMIX_CPUSET_CREATE(val->data.cpuset, 1); if (NULL == val->data.cpuset) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.cpuset, &m, PMIX_PROC_CPUSET, regtypes); return ret; case PMIX_GEOMETRY: PMIX_GEOMETRY_CREATE(val->data.geometry, 1); if (NULL == val->data.geometry) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.geometry, &m, PMIX_GEOMETRY, regtypes); return ret; case PMIX_DEVICE: PMIX_DEVICE_CREATE(val->data.device, 1); if (NULL == val->data.device) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.device, &m, PMIX_DEVICE, regtypes); return ret; case PMIX_RESOURCE_UNIT: PMIX_RESOURCE_UNIT_CREATE(val->data.resunit, 1); if (NULL == val->data.resunit) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.resunit, &m, PMIX_RESOURCE_UNIT, regtypes); return ret; case PMIX_DEVICE_DIST: PMIX_DEVICE_DIST_CREATE(val->data.devdist, 1); if (NULL == val->data.devdist) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.devdist, &m, PMIX_DEVICE_DIST, regtypes); return ret; case PMIX_ENDPOINT: PMIX_ENDPOINT_CREATE(val->data.endpoint, 1); if (NULL == val->data.endpoint) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.endpoint, &m, PMIX_ENDPOINT, regtypes); return ret; case PMIX_PROC_NSPACE: PMIX_PROC_CREATE(val->data.proc, 1); if (NULL == val->data.proc) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &val->data.proc->nspace, &m, PMIX_PROC_NSPACE, regtypes); return ret; case PMIX_DATA_BUFFER: PMIX_DATA_BUFFER_CREATE(val->data.ptr); if (NULL == val->data.ptr) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.ptr, &m, PMIX_DATA_BUFFER, regtypes); return ret; case PMIX_NODE_PID: val->data.nodepid = PMIx_Node_pid_create(1); if (NULL == val->data.nodepid) { return PMIX_ERR_NOMEM; } PMIX_BFROPS_UNPACK_TYPE(ret, buffer, val->data.nodepid, &m, PMIX_NODE_PID, regtypes); return ret; default: PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &val->data, &m, val->type, regtypes); if (PMIX_ERR_UNKNOWN_DATA_TYPE == ret) { pmix_output(0, "UNPACK-PMIX-VALUE: UNSUPPORTED TYPE %d", (int) val->type); } } return ret; } pmix_status_t pmix_bfrops_base_unpack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_value_t *ptr; int32_t i, n; pmix_status_t ret; ptr = (pmix_value_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { /* unpack the type */ if (PMIX_SUCCESS != (ret = pmix_bfrop_get_data_type(regtypes, buffer, &ptr[i].type))) { PMIX_ERROR_LOG(ret); return ret; } /* unpack value */ if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_val(regtypes, buffer, &ptr[i]))) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_info_t *ptr; int32_t i, n, m; pmix_status_t ret; char *tmp; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d info", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_info_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { memset(ptr[i].key, 0, sizeof(ptr[i].key)); memset(&ptr[i].value, 0, sizeof(pmix_value_t)); /* unpack key */ m = 1; tmp = NULL; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &tmp, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } if (NULL == tmp) { return PMIX_ERROR; } pmix_strncpy(ptr[i].key, tmp, PMIX_MAX_KEYLEN); free(tmp); /* unpack the directives */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].flags, &m, PMIX_INFO_DIRECTIVES, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack value - since the value structure is statically-defined * instead of a pointer in this struct, we directly unpack it to * avoid the malloc */ if (PMIX_SUCCESS != (ret = pmix_bfrop_get_data_type(regtypes, buffer, &ptr[i].value.type))) { return ret; } pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: info type %d", ptr[i].value.type); m = 1; if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_val(regtypes, buffer, &ptr[i].value))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_pdata_t *ptr; int32_t i, n, m; pmix_status_t ret; char *tmp; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d pdata", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_pdata_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_PDATA_CONSTRUCT(&ptr[i]); /* unpack the proc */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].proc, &m, PMIX_PROC, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack key */ m = 1; tmp = NULL; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &tmp, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (NULL == tmp) { PMIX_ERROR_LOG(PMIX_ERROR); return PMIX_ERROR; } pmix_strncpy(ptr[i].key, tmp, PMIX_MAX_KEYLEN); free(tmp); /* unpack value - since the value structure is statically-defined * instead of a pointer in this struct, we directly unpack it to * avoid the malloc */ if (PMIX_SUCCESS != (ret = pmix_bfrop_get_data_type(regtypes, buffer, &ptr[i].value.type))) { PMIX_ERROR_LOG(ret); return ret; } pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: pdata type %d %s", ptr[i].value.type, ptr[i].value.data.string); m = 1; if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_val(regtypes, buffer, &ptr[i].value))) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_buffer_t *ptr; int32_t i, n, m; pmix_status_t ret; size_t nbytes; ptr = (pmix_buffer_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { PMIX_CONSTRUCT(&ptr[i], pmix_buffer_t); /* unpack the type of buffer */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].type, &m, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack the number of bytes */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &nbytes, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } m = nbytes; /* setup the buffer's data region */ if (0 < nbytes) { ptr[i].base_ptr = (char *) malloc(nbytes); if (NULL == ptr[i].base_ptr) { return PMIX_ERR_NOMEM; } /* unpack the bytes */ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].base_ptr, &m, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } ptr[i].pack_ptr = ptr[i].base_ptr + m; ptr[i].unpack_ptr = ptr[i].base_ptr; ptr[i].bytes_allocated = nbytes; ptr[i].bytes_used = m; } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_proc_t *ptr; int32_t i, n, m; pmix_status_t ret; char *tmp; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d procs", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_proc_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: init proc[%d]", i); memset(&ptr[i], 0, sizeof(pmix_proc_t)); /* unpack nspace */ m = 1; tmp = NULL; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &tmp, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (NULL == tmp) { PMIX_ERROR_LOG(PMIX_ERROR); return PMIX_ERROR; } pmix_strncpy(ptr[i].nspace, tmp, PMIX_MAX_NSLEN); free(tmp); /* unpack the rank */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].rank, &m, PMIX_PROC_RANK, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_app_t *ptr; int32_t i, k, n, m; pmix_status_t ret; int32_t nval; char *tmp; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d apps", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_app_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { /* initialize the fields */ PMIX_APP_CONSTRUCT(&ptr[i]); /* unpack cmd */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].cmd, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack argc */ m = 1; /* although nval is technically an int32, we have to unpack it * as a generic int due to a typo in earlier release series. This * preserves the ordering of bytes in the packed buffer as it * includes a tag indicating the actual size of the value. No * harm is done as generic int is equivalent to int32 on all * current systems - just something to watch out for in the * future should someone someday change the size of "int" */ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &nval, &m, PMIX_INT, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack argv */ for (k = 0; k < nval; k++) { m = 1; tmp = NULL; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &tmp, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (NULL == tmp) { return PMIX_ERROR; } PMIx_Argv_append_nosize(&ptr[i].argv, tmp); free(tmp); } /* unpack env */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &nval, &m, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } for (k = 0; k < nval; k++) { m = 1; tmp = NULL; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &tmp, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (NULL == tmp) { return PMIX_ERROR; } PMIx_Argv_append_nosize(&ptr[i].env, tmp); free(tmp); } /* unpack cwd */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].cwd, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack maxprocs */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].maxprocs, &m, PMIX_INT, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack info array */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].ninfo, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < ptr[i].ninfo) { PMIX_INFO_CREATE(ptr[i].info, ptr[i].ninfo); m = ptr[i].ninfo; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].info, &m, PMIX_INFO, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_kval_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d kvals", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_kval_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_CONSTRUCT(&ptr[i], pmix_kval_t); /* unpack the key */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].key, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* allocate the space */ ptr[i].value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); /* unpack the value */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].value, &m, PMIX_VALUE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_BYTE, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_byte_object_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d byte_object", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_byte_object_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { memset(&ptr[i], 0, sizeof(pmix_byte_object_t)); /* unpack the number of bytes */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].size, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < ptr[i].size) { ptr[i].bytes = (char *) malloc(ptr[i].size * sizeof(char)); if (NULL == ptr[i].bytes) { return PMIX_ERR_NOMEM; } m = ptr[i].size; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].bytes, &m, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { uint8_t foo = 1; int32_t cnt = 1; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(dest, num_vals, type); /* it obviously makes no sense to pack a pointer and * send it somewhere else, so we just unpack the sentinel */ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &foo, &cnt, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_info_directives(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT32, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_pstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_pinfo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_proc_info_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d pinfo", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_proc_info_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_PROC_INFO_CONSTRUCT(&ptr[i]); /* unpack the proc */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].proc, &m, PMIX_PROC, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack the hostname */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].hostname, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack the executable */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].executable_name, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack pid */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].pid, &m, PMIX_PID, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack state */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].state, &m, PMIX_PROC_STATE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_data_array_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_data_type_t t; size_t sm; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d data arrays", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_data_array_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { memset(&ptr[i], 0, sizeof(pmix_data_array_t)); /* unpack the type */ m = 1; if (PMIX_SUCCESS != (ret = pmix_bfrop_get_data_type(regtypes, buffer, &ptr[i].type))) { return ret; } if (PMIX_UNDEF == ptr[i].type) { // this was a NULL array pointer return PMIX_SUCCESS; } /* unpack the number of array elements */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].size, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 == ptr[i].size || PMIX_UNDEF == ptr[i].type) { /* nothing else to do */ continue; } /* allocate storage for the array and unpack the array elements */ sm = ptr[i].size; t = ptr[i].type; PMIX_DATA_ARRAY_CONSTRUCT(&ptr[i], sm, t); if (NULL == ptr[i].array) { return PMIX_ERR_NOMEM; } m = sm; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].array, &m, t, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT32, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_query_t *ptr; int32_t i, n, m; pmix_status_t ret; int32_t nkeys; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d queries", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_query_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_QUERY_CONSTRUCT(&ptr[i]); /* unpack the number of keys */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &nkeys, &m, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < nkeys) { /* unpack the keys */ if (NULL == (ptr[i].keys = (char **) calloc(nkeys + 1, sizeof(char *)))) { return PMIX_ERR_NOMEM; } /* unpack keys */ m = nkeys; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].keys, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } /* unpack the number of qualifiers */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].nqual, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < ptr[i].nqual) { /* unpack the qualifiers */ PMIX_INFO_CREATE(ptr[i].qualifiers, ptr[i].nqual); m = ptr[i].nqual; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].qualifiers, &m, PMIX_INFO, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_alloc_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_resblock_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_iof_channel(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT16, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_envar(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_envar_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d envars", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_envar_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_ENVAR_CONSTRUCT(&ptr[i]); /* unpack the name */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].envar, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack the value */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].value, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack the separator */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].separator, &m, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_coord(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_coord_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d coordinates", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_coord_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_COORD_CONSTRUCT(&ptr[i]); /* unpack the view */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].view, &m, PMIX_UINT8, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack the dims */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].dims, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < ptr[i].dims) { ptr[i].coord = (uint32_t *) malloc(ptr[i].dims * sizeof(uint32_t)); /* unpack the coords */ m = ptr[i].dims; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].coord, &m, PMIX_UINT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_regattr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_regattr_t *ptr; int32_t i, n, m, nd; pmix_status_t ret; char *tmp; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d regattrs", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_regattr_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_REGATTR_CONSTRUCT(&ptr[i]); /* unpack the name */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].name, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack the string */ m = 1; tmp = NULL; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &tmp, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } if (NULL == tmp) { return PMIX_ERROR; } pmix_strncpy(ptr[i].string, tmp, PMIX_MAX_KEYLEN); free(tmp); /* unpack the type */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].type, &m, PMIX_DATA_TYPE, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } /* unpack the description */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &nd, &m, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } if (0 < nd) { /* unpack the description */ if (NULL == (ptr[i].description = (char **) calloc(nd + 1, sizeof(char *)))) { return PMIX_ERR_NOMEM; } m = nd; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].description, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_regex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { char **ptr; int32_t i, n; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d regex", *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); ptr = (char **) dest; n = *num_vals; for (i = 0; i < n; ++i) { ret = pmix_preg.unpack(buffer, &ptr[i]); if (PMIX_SUCCESS != ret) { *num_vals = 0; return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_jobstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_linkstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_cpuset(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_cpuset_t *ptr; int32_t i, n; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d cpuset", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_cpuset_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { ret = pmix_hwloc_unpack_cpuset(buffer, &ptr[i], regtypes); if (PMIX_SUCCESS != ret) { *num_vals = 0; return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_geometry(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_geometry_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d geometry", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_geometry_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_GEOMETRY_CONSTRUCT(&ptr[i]); /* unpack the fabric id */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].fabric, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack the uuid */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].uuid, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } /* unpack the osname */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].osname, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } /* get the number of coords */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].ncoords, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } if (0 < ptr[i].ncoords) { /* allocate the coords */ ptr[i].coordinates = (pmix_coord_t *) calloc(ptr[i].ncoords, sizeof(pmix_coord_t)); /* unpack them */ m = ptr[i].ncoords; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].coordinates, &m, PMIX_COORD, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_device(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_device_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d devices", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_device_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_DEVICE_CONSTRUCT(&ptr[i]); /* unpack the uuid */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].uuid, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].osname, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].type, &m, PMIX_DEVTYPE, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_resunit(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_resource_unit_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d resource units", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_resource_unit_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_RESOURCE_UNIT_CONSTRUCT(&ptr[i]); /* unpack the type */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].type, &m, PMIX_DEVTYPE, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } /* get the number of them */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].count, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_devdist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_device_distance_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d device distances", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_device_distance_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_DEVICE_DIST_CONSTRUCT(&ptr[i]); /* unpack the uuid */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].uuid, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].osname, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].type, &m, PMIX_DEVTYPE, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].mindist, &m, PMIX_UINT16, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].maxdist, &m, PMIX_UINT16, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_endpoint(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_endpoint_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d endpts", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_endpoint_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_ENDPOINT_CONSTRUCT(&ptr[i]); /* unpack the uuid */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].uuid, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].osname, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].endpt.size, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } if (0 < ptr[i].endpt.size) { ptr[i].endpt.bytes = (char *) malloc(ptr[i].endpt.size); m = ptr[i].endpt.size; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].endpt.bytes, &m, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_topology(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_topology_t *ptr; int32_t i, n; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d topology", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_topology_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { ret = pmix_hwloc_unpack_topology(buffer, &ptr[i], regtypes); if (PMIX_SUCCESS != ret) { *num_vals = 0; return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_devtype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d device types", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT64, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_locality(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d locality", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT16, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_nspace(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_nspace_t *ptr; int32_t i, n, m; pmix_status_t ret; char *p; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d nspace", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_nspace_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &p, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } PMIX_LOAD_NSPACE(ptr[i], p); free(p); } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_dbuf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_data_buffer_t *ptr = (pmix_data_buffer_t *) dest; int32_t i, m, n; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); n = *num_vals; for (i = 0; i < n; ++i) { m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].bytes_used, &m, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } if (0 < ptr[i].bytes_used) { ptr[i].base_ptr = malloc(ptr[i].bytes_used); m = ptr[i].bytes_used; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, ptr[i].base_ptr, &m, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_unpack_smed(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d storage medium", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT64, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_sacc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d storage access", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT64, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_spers(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d storage persistence", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT64, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_satyp(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d storage access type", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, PMIX_UINT16, regtypes); return ret; } pmix_status_t pmix_bfrops_base_unpack_nodepid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_node_pid_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack: %d node_pid", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_node_pid_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIx_Node_pid_construct(&ptr[i]); /* unpack the hostname */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].hostname, &m, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack the nodeid */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].nodeid, &m, PMIX_UINT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* unpack pid */ m = 1; PMIX_BFROPS_UNPACK_TYPE(ret, buffer, &ptr[i].pid, &m, PMIX_PID, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/bfrops/base/Makefile.include0000664000175000017500000000317615203536752022322 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2017 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022-2025 Nanook Consulting All rights reserved. # Copyright (c) 2022 Triad National Security, LLC. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from # src/Makefile.am headers += \ base/base.h \ base/bfrop_base_tma.h sources += \ base/bfrop_base_frame.c \ base/bfrop_base_fns.c \ base/bfrop_base_select.c \ base/bfrop_base_cmp.c \ base/bfrop_base_copy.c \ base/bfrop_base_pack.c \ base/bfrop_base_print.c \ base/bfrop_base_unpack.c \ base/bfrop_base_stubs.c \ base/bfrop_base_macro_backers.c \ base/bfrop_base_squash.c \ base/bfrop_base_get_number.c pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_select.c0000664000175000017500000001244315203536752023042 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/util/pmix_error.h" #include "src/util/pmix_show_help.h" #include "src/mca/bfrops/base/base.h" /* Function for selecting a prioritized list of components * from all those that are available. */ int pmix_bfrop_base_select(void) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_mca_base_component_t *component = NULL; pmix_mca_base_module_t *module = NULL; pmix_bfrops_module_t *nmodule; pmix_bfrops_base_active_module_t *newmodule, *mod; int rc, priority; bool inserted; if (pmix_bfrops_globals.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_bfrops_globals.selected = true; /* Query all available components and ask if they have a module */ PMIX_LIST_FOREACH (cli, &pmix_bfrops_base_framework.framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_mca_base_component_t *) cli->cli_component; pmix_output_verbose(5, pmix_bfrops_base_framework.framework_output, "mca:bfrops:select: checking available component %s", component->pmix_mca_component_name); /* If there's no query function, skip it */ if (NULL == component->pmix_mca_query_component) { pmix_output_verbose(5, pmix_bfrops_base_framework.framework_output, "mca:bfrops:select: Skipping component [%s]. It does not implement " "a query function", component->pmix_mca_component_name); continue; } /* Query the component */ pmix_output_verbose(5, pmix_bfrops_base_framework.framework_output, "mca:bfrops:select: Querying component [%s]", component->pmix_mca_component_name); rc = component->pmix_mca_query_component(&module, &priority); /* If no module was returned, then skip component */ if (PMIX_SUCCESS != rc || NULL == module) { pmix_output_verbose( 5, pmix_bfrops_base_framework.framework_output, "mca:bfrops:select: Skipping component [%s]. Query failed to return a module", component->pmix_mca_component_name); continue; } nmodule = (pmix_bfrops_module_t *) module; /* give it a chance to initialize */ if (NULL != nmodule->init) { if (PMIX_SUCCESS != nmodule->init()) { /* reject the module */ continue; } } /* If we got a module, keep it */ /* add to the list of selected modules */ newmodule = PMIX_NEW(pmix_bfrops_base_active_module_t); newmodule->pri = priority; newmodule->module = nmodule; newmodule->component = (pmix_bfrops_base_component_t *) cli->cli_component; /* maintain priority order */ inserted = false; PMIX_LIST_FOREACH (mod, &pmix_bfrops_globals.actives, pmix_bfrops_base_active_module_t) { if (priority > mod->pri) { pmix_list_insert_pos(&pmix_bfrops_globals.actives, (pmix_list_item_t *) mod, &newmodule->super); inserted = true; break; } } if (!inserted) { /* must be lowest priority - add to end */ pmix_list_append(&pmix_bfrops_globals.actives, &newmodule->super); } } /* if no modules were found, then that's an error as we require at least one */ if (0 == pmix_list_get_size(&pmix_bfrops_globals.actives)) { pmix_show_help("help-pmix-runtime.txt", "no-plugins", true, "BFROPS"); return PMIX_ERR_SILENT; } if (4 < pmix_output_get_verbosity(pmix_bfrops_base_framework.framework_output)) { pmix_output(0, "Final Bfrop priorities"); /* show the prioritized list */ PMIX_LIST_FOREACH (mod, &pmix_bfrops_globals.actives, pmix_bfrops_base_active_module_t) { pmix_output(0, "\tBfrop: %s Priority: %d", mod->component->base.pmix_mca_component_name, mod->pri); } } return PMIX_SUCCESS; ; } pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_copy.c0000664000175000017500000003516215203536752022540 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/mca/preg/preg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/bfrops/base/bfrop_base_tma.h" pmix_status_t pmix_bfrops_base_copy(pmix_pointer_array_t *regtypes, void **dest, void *src, pmix_data_type_t type) { pmix_bfrop_type_info_t *info; /* check for error */ if (NULL == dest || NULL == src) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* Lookup the copy function for this type and call it */ if (NULL == (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(regtypes, type))) { PMIX_ERROR_LOG(PMIX_ERR_UNKNOWN_DATA_TYPE); return PMIX_ERR_UNKNOWN_DATA_TYPE; } return info->odti_copy_fn(dest, src, type); } pmix_status_t pmix_bfrops_base_copy_payload(pmix_buffer_t *dest, pmix_buffer_t *src) { return pmix_bfrops_base_tma_copy_payload(dest, src, NULL); } pmix_status_t pmix_bfrops_base_embed_payload(pmix_buffer_t *dest, pmix_byte_object_t *src) { return pmix_bfrops_base_tma_embed_payload(dest, src, NULL); } /* * STANDARD COPY FUNCTION - WORKS FOR EVERYTHING NON-STRUCTURED */ pmix_status_t pmix_bfrops_base_std_copy(void **dest, void *src, pmix_data_type_t type) { size_t datasize; uint8_t *val = NULL; switch (type) { case PMIX_BOOL: datasize = sizeof(bool); break; case PMIX_INT: case PMIX_UINT: datasize = sizeof(int); break; case PMIX_SIZE: datasize = sizeof(size_t); break; case PMIX_PID: datasize = sizeof(pid_t); break; case PMIX_BYTE: case PMIX_INT8: case PMIX_UINT8: case PMIX_LINK_STATE: datasize = 1; break; case PMIX_INT16: case PMIX_UINT16: case PMIX_IOF_CHANNEL: case PMIX_LOCTYPE: case PMIX_STOR_ACCESS_TYPE: datasize = 2; break; case PMIX_INT32: case PMIX_UINT32: datasize = 4; break; case PMIX_INT64: case PMIX_UINT64: case PMIX_DEVTYPE: case PMIX_STOR_MEDIUM: case PMIX_STOR_ACCESS: case PMIX_STOR_PERSIST: datasize = 8; break; case PMIX_FLOAT: datasize = sizeof(float); break; case PMIX_TIMEVAL: datasize = sizeof(struct timeval); break; case PMIX_TIME: datasize = sizeof(time_t); break; case PMIX_STATUS: datasize = sizeof(pmix_status_t); break; case PMIX_PROC_RANK: datasize = sizeof(pmix_rank_t); break; case PMIX_PERSIST: datasize = sizeof(pmix_persistence_t); break; case PMIX_POINTER: datasize = sizeof(char *); break; case PMIX_SCOPE: datasize = sizeof(pmix_scope_t); break; case PMIX_DATA_RANGE: datasize = sizeof(pmix_data_range_t); break; case PMIX_COMMAND: datasize = sizeof(pmix_cmd_t); break; case PMIX_INFO_DIRECTIVES: datasize = sizeof(pmix_info_directives_t); break; case PMIX_PROC_STATE: datasize = sizeof(pmix_proc_state_t); break; case PMIX_ALLOC_DIRECTIVE: datasize = sizeof(pmix_alloc_directive_t); break; case PMIX_RESBLOCK_DIRECTIVE: datasize = sizeof(pmix_resource_block_directive_t); break; case PMIX_JOB_STATE: datasize = sizeof(pmix_job_state_t); break; default: return PMIX_ERR_UNKNOWN_DATA_TYPE; } val = (uint8_t *) malloc(datasize); if (NULL == val) { return PMIX_ERR_OUT_OF_RESOURCE; } memcpy(val, src, datasize); *dest = val; return PMIX_SUCCESS; } /* COPY FUNCTIONS FOR NON-STANDARD SYSTEM TYPES */ /* * STRING */ pmix_status_t pmix_bfrops_base_copy_string(char **dest, char *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); if (NULL == src) { /* got zero-length string/NULL pointer - store NULL */ *dest = NULL; } else { *dest = strdup(src); } return PMIX_SUCCESS; } /* PMIX_VALUE */ pmix_status_t pmix_bfrops_base_copy_value(pmix_value_t **dest, pmix_value_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_value(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_info(pmix_info_t **dest, pmix_info_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_info_t *) malloc(sizeof(pmix_info_t)); pmix_strncpy((*dest)->key, src->key, PMIX_MAX_KEYLEN); (*dest)->flags = src->flags; return pmix_bfrops_base_value_xfer(&(*dest)->value, &src->value); } pmix_status_t pmix_bfrops_base_copy_buf(pmix_buffer_t **dest, pmix_buffer_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = PMIX_NEW(pmix_buffer_t); pmix_bfrops_base_copy_payload(*dest, src); return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_copy_app(pmix_app_t **dest, pmix_app_t *src, pmix_data_type_t type) { size_t j; PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_app_t *) malloc(sizeof(pmix_app_t)); (*dest)->cmd = strdup(src->cmd); (*dest)->argv = PMIx_Argv_copy(src->argv); (*dest)->env = PMIx_Argv_copy(src->env); if (NULL != src->cwd) { (*dest)->cwd = strdup(src->cwd); } (*dest)->maxprocs = src->maxprocs; (*dest)->ninfo = src->ninfo; (*dest)->info = (pmix_info_t *) malloc(src->ninfo * sizeof(pmix_info_t)); for (j = 0; j < src->ninfo; j++) { pmix_strncpy((*dest)->info[j].key, src->info[j].key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&(*dest)->info[j].value, &src->info[j].value); } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_copy_kval(pmix_kval_t **dest, pmix_kval_t *src, pmix_data_type_t type) { pmix_kval_t *p; PMIX_HIDE_UNUSED_PARAMS(type); /* create the new object */ *dest = PMIX_NEW(pmix_kval_t); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } p = *dest; /* copy the type */ p->value->type = src->value->type; /* copy the data */ return pmix_bfrops_base_value_xfer(p->value, src->value); } pmix_status_t pmix_bfrops_base_copy_proc(pmix_proc_t **dest, pmix_proc_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_proc_t *) malloc(sizeof(pmix_proc_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } pmix_strncpy((*dest)->nspace, src->nspace, PMIX_MAX_NSLEN); (*dest)->rank = src->rank; return PMIX_SUCCESS; } pmix_status_t pmix_bfrop_base_copy_persist(pmix_persistence_t **dest, pmix_persistence_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_persistence_t *) malloc(sizeof(pmix_persistence_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } memcpy(*dest, src, sizeof(pmix_persistence_t)); return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_copy_bo(pmix_byte_object_t **dest, pmix_byte_object_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_byte_object_t *) malloc(sizeof(pmix_byte_object_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } (*dest)->bytes = (char *) malloc(src->size); memcpy((*dest)->bytes, src->bytes, src->size); (*dest)->size = src->size; return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_copy_pdata(pmix_pdata_t **dest, pmix_pdata_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_pdata_t *) malloc(sizeof(pmix_pdata_t)); pmix_strncpy((*dest)->proc.nspace, src->proc.nspace, PMIX_MAX_NSLEN); (*dest)->proc.rank = src->proc.rank; pmix_strncpy((*dest)->key, src->key, PMIX_MAX_KEYLEN); return pmix_bfrops_base_value_xfer(&(*dest)->value, &src->value); } pmix_status_t pmix_bfrops_base_copy_pinfo(pmix_proc_info_t **dest, pmix_proc_info_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_pinfo(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_darray(pmix_data_array_t **dest, pmix_data_array_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_darray(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_query(pmix_query_t **dest, pmix_query_t *src, pmix_data_type_t type) { pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_query_t *) malloc(sizeof(pmix_query_t)); if (NULL != src->keys) { (*dest)->keys = PMIx_Argv_copy(src->keys); } (*dest)->nqual = src->nqual; if (NULL != src->qualifiers) { if (PMIX_SUCCESS != (rc = pmix_bfrops_base_copy_info(&((*dest)->qualifiers), src->qualifiers, PMIX_INFO))) { free(*dest); return rc; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_copy_envar(pmix_envar_t **dest, pmix_envar_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); PMIX_ENVAR_CREATE(*dest, 1); if (NULL == (*dest)) { return PMIX_ERR_NOMEM; } if (NULL != src->envar) { (*dest)->envar = strdup(src->envar); } if (NULL != src->value) { (*dest)->value = strdup(src->value); } (*dest)->separator = src->separator; return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_copy_coord(pmix_coord_t **dest, pmix_coord_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_coord(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_regattr(pmix_regattr_t **dest, pmix_regattr_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_regattr(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_regex(char **dest, char *src, pmix_data_type_t type) { size_t len; PMIX_HIDE_UNUSED_PARAMS(type); return pmix_preg.copy(dest, &len, src); } pmix_status_t pmix_bfrops_base_copy_cpuset(pmix_cpuset_t **dest, pmix_cpuset_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_cpuset(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_geometry(pmix_geometry_t **dest, pmix_geometry_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_geometry(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_device(pmix_device_t **dest, pmix_device_t *src, pmix_data_type_t type) { pmix_device_t *dst; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_DEVICE_CREATE(dst, 1); if (NULL == dst) { return PMIX_ERR_NOMEM; } if (NULL != src->uuid) { dst->uuid = strdup(src->uuid); } if (NULL != src->osname) { dst->osname = strdup(src->osname); } dst->type = src->type; *dest = dst; return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_copy_resunit(pmix_resource_unit_t **dest, pmix_resource_unit_t *src, pmix_data_type_t type) { pmix_resource_unit_t *dst; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_RESOURCE_UNIT_CREATE(dst, 1); if (NULL == dst) { return PMIX_ERR_NOMEM; } memcpy(dst, src, sizeof(pmix_resource_unit_t)); *dest = dst; return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_copy_devdist(pmix_device_distance_t **dest, pmix_device_distance_t *src, pmix_data_type_t type) { pmix_device_distance_t *dst; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_DEVICE_DIST_CREATE(dst, 1); if (NULL == dst) { return PMIX_ERR_NOMEM; } if (NULL != src->uuid) { dst->uuid = strdup(src->uuid); } if (NULL != src->osname) { dst->osname = strdup(src->osname); } dst->type = src->type; dst->mindist = src->mindist; dst->maxdist = src->maxdist; *dest = dst; return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_copy_endpoint(pmix_endpoint_t **dest, pmix_endpoint_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_endpoint(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_topology(pmix_topology_t **dest, pmix_topology_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_topology(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_nspace(pmix_nspace_t **dest, pmix_nspace_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_nspace(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_dbuf(pmix_data_buffer_t **dest, pmix_data_buffer_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_dbuf(dest, src, type, NULL); } pmix_status_t pmix_bfrops_base_copy_nodepid(pmix_node_pid_t **dest, pmix_node_pid_t *src, pmix_data_type_t type) { return pmix_bfrops_base_tma_copy_nodepid(dest, src, type, NULL); } pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_pack.c0000664000175000017500000013432715203536752022507 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include "src/class/pmix_pointer_array.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/mca/preg/preg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/mca/bfrops/base/base.h" pmix_status_t pmix_bfrops_base_pack(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type) { pmix_status_t rc; /* check for error */ if (NULL == buffer || (NULL == src && 0 < num_vals)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* Pack the number of values */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix_bfrop_store_data_type(regtypes, buffer, PMIX_INT32))) { return rc; } } PMIX_BFROPS_PACK_TYPE(rc, buffer, &num_vals, 1, PMIX_INT32, regtypes); if (PMIX_SUCCESS != rc) { return rc; } /* Pack the value(s) */ return pmix_bfrops_base_pack_buffer(regtypes, buffer, src, num_vals, type); } pmix_status_t pmix_bfrops_base_pack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t rc; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_pack_buffer( %p, %p, %lu, %d )\n", (void *) buffer, src, (long unsigned int) num_vals, (int) type); /* Pack the declared data type */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix_bfrop_store_data_type(regtypes, buffer, type))) { return rc; } } PMIX_BFROPS_PACK_TYPE(rc, buffer, src, num_vals, type, regtypes); return rc; } /* PACK FUNCTIONS FOR GENERIC SYSTEM TYPES */ /* * BOOL */ pmix_status_t pmix_bfrops_base_pack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { uint8_t *dst; int32_t i; bool *s = (bool *) src; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_pack_bool * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = (uint8_t *) pmix_bfrop_buffer_extend(buffer, num_vals))) { return PMIX_ERR_OUT_OF_RESOURCE; } /* store the data */ for (i = 0; i < num_vals; i++) { if (s[i]) { dst[i] = 1; } else { dst[i] = 0; } } /* update buffer pointers */ buffer->pack_ptr += num_vals; buffer->bytes_used += num_vals; return PMIX_SUCCESS; } /* * INT16, INT32, INT64, UIN16, UINT32, UINT64 */ pmix_status_t pmix_bfrops_base_pack_general_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t rc; int32_t i; char *dst; size_t val_size, max_size, pkg_size; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_pack_integer * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes); PMIX_SQUASH_TYPE_SIZEOF(rc, type, val_size); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } rc = pmix_bfrops_base_get_max_size(type, &max_size); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals * max_size))) { rc = PMIX_ERR_OUT_OF_RESOURCE; PMIX_ERROR_LOG(rc); return rc; } for (i = 0; i < num_vals; ++i) { rc = pmix_bfrops_base_encode_int(type, (uint8_t *) src + i * val_size, dst, &pkg_size); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } dst += pkg_size; buffer->pack_ptr += pkg_size; buffer->bytes_used += pkg_size; } return PMIX_SUCCESS; } /* * INT */ pmix_status_t pmix_bfrops_base_pack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); /* Turn around and pack the real type */ PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, BFROP_TYPE_INT, regtypes); return ret; } /* * SIZE_T */ pmix_status_t pmix_bfrops_base_pack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, BFROP_TYPE_SIZE_T, regtypes); return ret; } /* * PID_T */ pmix_status_t pmix_bfrops_base_pack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them. */ if (PMIX_SUCCESS != (ret = pmix_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_PID_T))) { return ret; } /* Turn around and pack the real type */ PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, BFROP_TYPE_PID_T, regtypes); return ret; } /* * BYTE, CHAR, INT8 */ pmix_status_t pmix_bfrops_base_pack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { char *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_pack_byte * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals))) { return PMIX_ERR_OUT_OF_RESOURCE; } /* store the data */ memcpy(dst, src, num_vals); /* update buffer pointers */ buffer->pack_ptr += num_vals; buffer->bytes_used += num_vals; return PMIX_SUCCESS; } /* * STRING */ pmix_status_t pmix_bfrops_base_pack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret = PMIX_SUCCESS; int32_t i, len; char **ssrc = (char **) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { if (NULL == ssrc[i]) { /* got zero-length string/NULL pointer - store NULL */ len = 0; PMIX_BFROPS_PACK_TYPE(ret, buffer, &len, 1, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } else { len = (int32_t) strlen(ssrc[i]) + 1; // retain the NULL terminator PMIX_BFROPS_PACK_TYPE(ret, buffer, &len, 1, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, ssrc[i], len, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return ret; } /* FLOAT */ pmix_status_t pmix_bfrops_base_pack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret = PMIX_SUCCESS; int32_t i; float *ssrc = (float *) src; char *convert; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { ret = asprintf(&convert, "%f", ssrc[i]); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &convert, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { free(convert); return ret; } free(convert); } return PMIX_SUCCESS; } /* DOUBLE */ pmix_status_t pmix_bfrops_base_pack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret = PMIX_SUCCESS; int32_t i; double *ssrc = (double *) src; char *convert; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { ret = asprintf(&convert, "%f", ssrc[i]); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &convert, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { free(convert); return ret; } free(convert); } return PMIX_SUCCESS; } /* TIMEVAL */ pmix_status_t pmix_bfrops_base_pack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int64_t tmp[2]; int ret = PMIX_SUCCESS; int32_t i; struct timeval *ssrc = (struct timeval *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { tmp[0] = (int64_t) ssrc[i].tv_sec; tmp[1] = (int64_t) ssrc[i].tv_usec; PMIX_BFROPS_PACK_TYPE(ret, buffer, tmp, 2, PMIX_INT64, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } /* TIME */ pmix_status_t pmix_bfrops_base_pack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret = PMIX_SUCCESS; int32_t i; time_t *ssrc = (time_t *) src; uint64_t ui64; PMIX_HIDE_UNUSED_PARAMS(type); /* time_t is a system-dependent size, so cast it * to uint64_t as a generic safe size */ for (i = 0; i < num_vals; ++i) { ui64 = (uint64_t) ssrc[i]; PMIX_BFROPS_PACK_TYPE(ret, buffer, &ui64, 1, PMIX_UINT64, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } /* STATUS */ pmix_status_t pmix_bfrops_base_pack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret = PMIX_SUCCESS; int32_t i; pmix_status_t *ssrc = (pmix_status_t *) src; int32_t status; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { status = (int32_t) ssrc[i]; PMIX_BFROPS_PACK_TYPE(ret, buffer, &status, 1, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_buffer_t *ptr; int32_t i; int ret; PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_buffer_t *) src; for (i = 0; i < num_vals; ++i) { /* pack the type of buffer */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].type, 1, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the number of bytes */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].bytes_used, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the bytes */ if (0 < ptr[i].bytes_used) { PMIX_BFROPS_PACK_TYPE(ret, buffer, ptr[i].base_ptr, ptr[i].bytes_used, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret; int i; pmix_byte_object_t *bo; PMIX_HIDE_UNUSED_PARAMS(type); bo = (pmix_byte_object_t *) src; for (i = 0; i < num_vals; i++) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &bo[i].size, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < bo[i].size) { PMIX_BFROPS_PACK_TYPE(ret, buffer, bo[i].bytes, bo[i].size, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_proc_t *proc; int32_t i; int ret; PMIX_HIDE_UNUSED_PARAMS(type); proc = (pmix_proc_t *) src; for (i = 0; i < num_vals; ++i) { char *ptr = proc[i].nspace; PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &proc[i].rank, 1, PMIX_PROC_RANK, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } /* PMIX_VALUE */ pmix_status_t pmix_bfrops_base_pack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_value_t *ptr; int32_t i; int ret; PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_value_t *) src; for (i = 0; i < num_vals; ++i) { /* pack the type */ if (PMIX_SUCCESS != (ret = pmix_bfrop_store_data_type(regtypes, buffer, ptr[i].type))) { return ret; } /* now pack the right field */ if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_val(regtypes, buffer, &ptr[i]))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_info_t *info; int32_t i; int ret; char *foo; PMIX_HIDE_UNUSED_PARAMS(type); info = (pmix_info_t *) src; for (i = 0; i < num_vals; ++i) { /* pack key */ foo = info[i].key; PMIX_BFROPS_PACK_TYPE(ret, buffer, &foo, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack info directives */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &info[i].flags, 1, PMIX_INFO_DIRECTIVES, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the type */ if (PMIX_SUCCESS != (ret = pmix_bfrop_store_data_type(regtypes, buffer, info[i].value.type))) { return ret; } /* pack value */ if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_val(regtypes, buffer, &info[i].value))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_pdata_t *pdata; int32_t i; int ret; char *foo; PMIX_HIDE_UNUSED_PARAMS(type); pdata = (pmix_pdata_t *) src; for (i = 0; i < num_vals; ++i) { /* pack the proc */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &pdata[i].proc, 1, PMIX_PROC, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack key */ foo = pdata[i].key; PMIX_BFROPS_PACK_TYPE(ret, buffer, &foo, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } /* pack the type */ if (PMIX_SUCCESS != (ret = pmix_bfrop_store_data_type(regtypes, buffer, pdata[i].value.type))) { PMIX_ERROR_LOG(ret); return ret; } /* pack value */ if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_val(regtypes, buffer, &pdata[i].value))) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_app_t *app; int32_t i, j, nvals; int ret; PMIX_HIDE_UNUSED_PARAMS(type); app = (pmix_app_t *) src; for (i = 0; i < num_vals; ++i) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &app[i].cmd, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* argv */ nvals = PMIx_Argv_count(app[i].argv); /* although nvals is technically an int32, we have to pack it * as a generic int due to a typo in earlier release series. This * preserves the ordering of bytes in the packed buffer as it * includes a tag indicating the actual size of the value. No * harm is done as generic int is equivalent to int32 on all * current systems - just something to watch out for in the * future should someone someday change the size of "int" */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &nvals, 1, PMIX_INT, regtypes); if (PMIX_SUCCESS != ret) { return ret; } for (j = 0; j < nvals; j++) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &app[i].argv[j], 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } /* env */ nvals = PMIx_Argv_count(app[i].env); PMIX_BFROPS_PACK_TYPE(ret, buffer, &nvals, 1, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } for (j = 0; j < nvals; j++) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &app[i].env[j], 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } /* cwd */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &app[i].cwd, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* maxprocs */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &app[i].maxprocs, 1, PMIX_INT, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* info array */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &app[i].ninfo, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < app[i].ninfo) { PMIX_BFROPS_PACK_TYPE(ret, buffer, app[i].info, app[i].ninfo, PMIX_INFO, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_kval_t *ptr; int32_t i; int ret; PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_kval_t *) src; for (i = 0; i < num_vals; ++i) { /* pack the key */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].key, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the value */ PMIX_BFROPS_PACK_TYPE(ret, buffer, ptr[i].value, 1, PMIX_VALUE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_BYTE, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT16, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; uint8_t foo = 1; PMIX_HIDE_UNUSED_PARAMS(src, num_vals, type); /* it obviously makes no sense to pack a pointer and * send it somewhere else, so we just pack a sentinel */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &foo, 1, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_info_directives(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT32, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_pstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_pinfo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_proc_info_t *pinfo = (pmix_proc_info_t *) src; pmix_status_t ret; int32_t i; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; i++) { /* pack the proc identifier */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &pinfo[i].proc, 1, PMIX_PROC, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the hostname and exec */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &pinfo[i].hostname, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &pinfo[i].executable_name, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the pid and state */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &pinfo[i].pid, 1, PMIX_PID, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &pinfo[i].state, 1, PMIX_PROC_STATE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_data_array_t *p = (pmix_data_array_t *) src; pmix_status_t ret; int32_t i; PMIX_HIDE_UNUSED_PARAMS(type); // handle the case of a NULL data array pointer if (NULL == src) { ret = pmix_bfrop_store_data_type(regtypes, buffer, PMIX_UNDEF); return ret; } for (i = 0; i < num_vals; i++) { /* pack the actual type in the array */ if (PMIX_SUCCESS != (ret = pmix_bfrop_store_data_type(regtypes, buffer, p[i].type))) { return ret; } /* pack the number of array elements */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &p[i].size, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 == p[i].size || PMIX_UNDEF == p[i].type) { /* nothing left to do */ continue; } /* pack the actual elements */ PMIX_BFROPS_PACK_TYPE(ret, buffer, p[i].array, p[i].size, p[i].type, regtypes); if (PMIX_ERR_UNKNOWN_DATA_TYPE == ret) { pmix_output(0, "PACK-PMIX-VALUE[%s:%d]: UNSUPPORTED TYPE %d", __FILE__, __LINE__, (int) p[i].type); } if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT32, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_query_t *pq = (pmix_query_t *) src; pmix_status_t ret; int32_t i; int32_t nkeys; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; i++) { /* pack the number of keys */ nkeys = PMIx_Argv_count(pq[i].keys); PMIX_BFROPS_PACK_TYPE(ret, buffer, &nkeys, 1, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < nkeys) { /* pack the keys */ PMIX_BFROPS_PACK_TYPE(ret, buffer, pq[i].keys, nkeys, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } /* pack the number of qualifiers */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &pq[i].nqual, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < pq[i].nqual) { /* pack any provided qualifiers */ PMIX_BFROPS_PACK_TYPE(ret, buffer, pq[i].qualifiers, pq[i].nqual, PMIX_INFO, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } /********************/ /* PACK FUNCTIONS FOR VALUE TYPES */ pmix_status_t pmix_bfrops_base_pack_val(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_value_t *p) { pmix_status_t ret; switch (p->type) { case PMIX_UNDEF: break; /* need to callout all the fields that are pointers to * a data object as opposed to a simple value */ case PMIX_PROC: case PMIX_PROC_NSPACE: case PMIX_PROC_INFO: case PMIX_DATA_ARRAY: case PMIX_COORD: case PMIX_TOPO: case PMIX_PROC_CPUSET: case PMIX_GEOMETRY: case PMIX_DEVICE: case PMIX_DEVICE_DIST: case PMIX_ENDPOINT: case PMIX_REGATTR: case PMIX_RESOURCE_UNIT: case PMIX_NODE_PID: PMIX_BFROPS_PACK_TYPE(ret, buffer, p->data.ptr, 1, p->type, regtypes); if (PMIX_SUCCESS != ret) { return ret; } break; default: /* pass the address of the value instead of the value itself */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &p->data, 1, p->type, regtypes); if (PMIX_ERR_UNKNOWN_DATA_TYPE == ret) { pmix_output(0, "PACK-PMIX-VALUE[%s:%d]: UNSUPPORTED TYPE %d", __FILE__, __LINE__, (int) p->type); return PMIX_ERROR; } else if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_alloc_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_resblock_directive(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_iof_channel(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT16, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_envar(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_envar_t *ptr = (pmix_envar_t *) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack the name */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].envar, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the value */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].value, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the separator */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].separator, 1, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_coord(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_coord_t *ptr = (pmix_coord_t *) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack the view */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].view, 1, PMIX_UINT8, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the number of dimensions */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].dims, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the array of coordinates */ PMIX_BFROPS_PACK_TYPE(ret, buffer, ptr[i].coord, ptr[i].dims, PMIX_UINT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_regattr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_regattr_t *ptr = (pmix_regattr_t *) src; int32_t i, nd; pmix_status_t ret; char *foo; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack the name */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].name, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the string */ foo = ptr[i].string; PMIX_BFROPS_PACK_TYPE(ret, buffer, &foo, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } /* pack the type */ PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].type, 1, PMIX_DATA_TYPE, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } /* pack the description */ nd = PMIx_Argv_count(ptr[i].description); PMIX_BFROPS_PACK_TYPE(ret, buffer, &nd, 1, PMIX_INT32, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, ptr[i].description, nd, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_regex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { char **ptr = (char **) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); for (i = 0; i < num_vals; ++i) { ret = pmix_preg.pack(buffer, ptr[i]); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_jobstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_linkstate(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT8, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_cpuset(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_cpuset_t *ptr = (pmix_cpuset_t *) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { ret = pmix_hwloc_pack_cpuset(buffer, &ptr[i], regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_geometry(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_geometry_t *ptr = (pmix_geometry_t *) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].fabric, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].uuid, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].osname, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].ncoords, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, ptr[i].coordinates, ptr[i].ncoords, PMIX_COORD, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_device(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_device_t *ptr = (pmix_device_t *) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].uuid, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].osname, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].type, 1, PMIX_DEVTYPE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_resunit(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_resource_unit_t *ptr = (pmix_resource_unit_t *) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].type, 1, PMIX_DEVTYPE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].count, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_devdist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_device_distance_t *ptr = (pmix_device_distance_t *) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].uuid, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].osname, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].type, 1, PMIX_DEVTYPE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].mindist, 1, PMIX_UINT16, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].maxdist, 1, PMIX_UINT16, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_endpoint(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_endpoint_t *ptr = (pmix_endpoint_t *) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].uuid, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].osname, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].endpt.size, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < ptr[i].endpt.size) { PMIX_BFROPS_PACK_TYPE(ret, buffer, ptr[i].endpt.bytes, ptr[i].endpt.size, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_topology(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_topology_t *ptr = (pmix_topology_t *) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* call the framework to pack it */ ret = pmix_hwloc_pack_topology(buffer, &ptr[i], regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_devtype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT64, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_locality(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT16, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_nspace(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_nspace_t *ptr = (pmix_nspace_t *) src; char *p; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { p = (char *) ptr[i]; PMIX_BFROPS_PACK_TYPE(ret, buffer, &p, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_dbuf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_data_buffer_t *ptr = (pmix_data_buffer_t *) src; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].bytes_used, 1, PMIX_SIZE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } if (0 < ptr[i].bytes_used) { PMIX_BFROPS_PACK_TYPE(ret, buffer, ptr[i].base_ptr, ptr[i].bytes_used, PMIX_BYTE, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix_bfrops_base_pack_smed(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT64, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_sacc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT64, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_spers(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT64, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_satyp(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, PMIX_UINT16, regtypes); return ret; } pmix_status_t pmix_bfrops_base_pack_nodepid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_node_pid_t *ptr = (pmix_node_pid_t *) src; pmix_status_t ret; int32_t i; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].hostname, 1, PMIX_STRING, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].nodeid, 1, PMIX_UINT32, regtypes); if (PMIX_SUCCESS != ret) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, &ptr[i].pid, 1, PMIX_PID, regtypes); if (PMIX_SUCCESS != ret) { return ret; } } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_macro_backers.c0000664000175000017500000004371615203536752024365 0ustar alastairalastair/* * Copyright (c) 2022-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/bfrops/base/bfrop_base_tma.h" void PMIx_Load_key(pmix_key_t key, const char *src) { pmix_bfrops_base_tma_load_key(key, src, NULL); } bool PMIx_Check_key(const char *key, const char *str) { return pmix_bfrops_base_tma_check_key(key, str, NULL); } void PMIx_Load_nspace(pmix_nspace_t nspace, const char *str) { pmix_bfrops_base_tma_load_nspace(nspace, str, NULL); } bool PMIx_Check_nspace(const char *nspace1, const char *nspace2) { return pmix_bfrops_base_tma_check_nspace(nspace1, nspace2, NULL); } bool PMIx_Nspace_invalid(const char *nspace) { return pmix_bfrops_base_tma_nspace_invalid(nspace, NULL); } bool PMIx_Check_reserved_key(const char *key) { return pmix_bfrops_base_tma_check_reserved_key(key, NULL); } void PMIx_Load_procid(pmix_proc_t *p, const char *ns, pmix_rank_t rk) { pmix_bfrops_base_tma_load_procid(p, ns, rk, NULL); } void PMIx_Xfer_procid(pmix_proc_t *dst, const pmix_proc_t *src) { pmix_bfrops_base_tma_xfer_procid(dst, src, NULL); } bool PMIx_Check_procid(const pmix_proc_t *a, const pmix_proc_t *b) { return pmix_bfrops_base_tma_check_procid(a, b, NULL); } bool PMIx_Check_rank(pmix_rank_t a, pmix_rank_t b) { return pmix_bfrops_base_tma_check_rank(a, b, NULL); } bool PMIx_Rank_valid(pmix_rank_t a) { return pmix_bfrops_base_tma_rank_valid(a, NULL); } bool PMIx_Procid_invalid(const pmix_proc_t *p) { return pmix_bfrops_base_tma_procid_invalid(p, NULL); } int PMIx_Argv_count(char **argv) { return pmix_bfrops_base_tma_argv_count(argv, NULL); } pmix_status_t PMIx_Argv_append_nosize(char ***argv, const char *arg) { return pmix_bfrops_base_tma_argv_append_nosize(argv, arg, NULL); } pmix_status_t PMIx_Argv_prepend_nosize(char ***argv, const char *arg) { return pmix_bfrops_base_tma_argv_prepend_nosize(argv, arg, NULL); } pmix_status_t PMIx_Argv_append_unique_nosize(char ***argv, const char *arg) { return pmix_bfrops_base_tma_argv_append_unique_nosize(argv, arg, NULL); } void PMIx_Argv_free(char **argv) { pmix_bfrops_base_tma_argv_free(argv, NULL); } char **PMIx_Argv_split_inter(const char *src_string, int delimiter, bool include_empty) { return pmix_bfrops_base_tma_argv_split_inter(src_string, delimiter, include_empty, NULL); } char **PMIx_Argv_split_with_empty(const char *src_string, int delimiter) { return pmix_bfrops_base_tma_argv_split_with_empty(src_string, delimiter, NULL); } char **PMIx_Argv_split(const char *src_string, int delimiter) { return pmix_bfrops_base_tma_argv_split(src_string, delimiter, NULL); } char *PMIx_Argv_join(char **argv, int delimiter) { return pmix_bfrops_base_tma_argv_join(argv, delimiter, NULL); } char **PMIx_Argv_copy(char **argv) { return pmix_bfrops_base_tma_argv_copy(argv, NULL); } pmix_status_t PMIx_Setenv(const char *name, const char *value, bool overwrite, char ***env) { return pmix_bfrops_base_tma_setenv(name, value, overwrite, env, NULL); } void PMIx_Value_construct(pmix_value_t *val) { pmix_bfrops_base_tma_value_construct(val, NULL); } void PMIx_Value_destruct(pmix_value_t *val) { pmix_bfrops_base_tma_value_destruct(val, NULL); } pmix_value_t* PMIx_Value_create(size_t n) { return pmix_bfrops_base_tma_value_create(n, NULL); } void PMIx_Value_free(pmix_value_t *v, size_t n) { pmix_bfrops_base_tma_value_free(v, n, NULL); } pmix_boolean_t PMIx_Value_true(const pmix_value_t *value) { return pmix_bfrops_base_tma_value_true(value, NULL); } pmix_status_t PMIx_Value_load(pmix_value_t *v, const void *data, pmix_data_type_t type) { return pmix_bfrops_base_tma_value_load(v, data, type, NULL); } pmix_status_t PMIx_Value_unload(pmix_value_t *kv, void **data, size_t *sz) { return pmix_bfrops_base_tma_value_unload(kv, data, sz, NULL); } pmix_status_t PMIx_Value_xfer(pmix_value_t *dest, const pmix_value_t *src) { return pmix_bfrops_base_tma_value_xfer(dest, src, NULL); } pmix_value_cmp_t PMIx_Value_compare(pmix_value_t *v1, pmix_value_t *v2) { return pmix_bfrops_base_tma_value_compare(v1, v2, NULL); } PMIX_EXPORT void PMIx_Info_construct(pmix_info_t *p) { pmix_bfrops_base_tma_info_construct(p, NULL); } PMIX_EXPORT void PMIx_Info_destruct(pmix_info_t *p) { pmix_bfrops_base_tma_info_destruct(p, NULL); } PMIX_EXPORT pmix_info_t* PMIx_Info_create(size_t n) { return pmix_bfrops_base_tma_info_create(n, NULL); } PMIX_EXPORT void PMIx_Info_free(pmix_info_t *p, size_t n) { pmix_bfrops_base_tma_info_free(p, n, NULL); } pmix_boolean_t PMIx_Info_true(const pmix_info_t *p) { return pmix_bfrops_base_tma_info_true(p, NULL); } pmix_status_t PMIx_Info_load(pmix_info_t *info, const char *key, const void *data, pmix_data_type_t type) { return pmix_bfrops_base_tma_info_load(info, key, data, type, NULL); } void PMIx_Info_required(pmix_info_t *p) { pmix_bfrops_base_tma_info_required(p, NULL); } bool PMIx_Info_is_required(const pmix_info_t *p) { return pmix_bfrops_base_tma_info_is_required(p, NULL); } void PMIx_Info_optional(pmix_info_t *p) { pmix_bfrops_base_tma_info_optional(p, NULL); } bool PMIx_Info_is_optional(const pmix_info_t *p) { return pmix_bfrops_base_tma_info_is_optional(p, NULL); } void PMIx_Info_processed(pmix_info_t *p) { pmix_bfrops_base_tma_info_processed(p, NULL); } bool PMIx_Info_was_processed(const pmix_info_t *p) { return pmix_bfrops_base_tma_info_was_processed(p, NULL); } void PMIx_Info_set_end(pmix_info_t *p) { pmix_bfrops_base_tma_info_set_end(p, NULL); } bool PMIx_Info_is_end(const pmix_info_t *p) { return pmix_bfrops_base_tma_info_is_end(p, NULL); } void PMIx_Info_qualifier(pmix_info_t *p) { pmix_bfrops_base_tma_info_qualifier(p, NULL); } bool PMIx_Info_is_qualifier(const pmix_info_t *p) { return pmix_bfrops_base_tma_info_is_qualifier(p, NULL); } void PMIx_Info_persistent(pmix_info_t *p) { pmix_bfrops_base_tma_info_persistent(p, NULL); } bool PMIx_Info_is_persistent(const pmix_info_t *p) { return pmix_bfrops_base_tma_info_is_persistent(p, NULL); } pmix_status_t PMIx_Info_xfer(pmix_info_t *dest, const pmix_info_t *src) { return pmix_bfrops_base_tma_info_xfer(dest, src, NULL); } void PMIx_Coord_construct(pmix_coord_t *m) { pmix_bfrops_base_tma_coord_construct(m, NULL); } void PMIx_Coord_destruct(pmix_coord_t *m) { pmix_bfrops_base_tma_coord_destruct(m, NULL); } pmix_coord_t* PMIx_Coord_create(size_t dims, size_t number) { return pmix_bfrops_base_tma_coord_create(dims, number, NULL); } void PMIx_Coord_free(pmix_coord_t *m, size_t number) { pmix_bfrops_base_tma_coord_free(m, number, NULL); } void PMIx_Topology_construct(pmix_topology_t *t) { pmix_bfrops_base_tma_topology_construct(t, NULL); } void PMIx_Topology_destruct(pmix_topology_t *t) { pmix_bfrops_base_tma_topology_destruct(t, NULL); } pmix_topology_t* PMIx_Topology_create(size_t n) { return pmix_bfrops_base_tma_topology_create(n, NULL); } void PMIx_Topology_free(pmix_topology_t *t, size_t n) { pmix_bfrops_base_tma_topology_free(t, n, NULL); } void PMIx_Cpuset_construct(pmix_cpuset_t *c) { pmix_bfrops_base_tma_cpuset_construct(c, NULL); } void PMIx_Cpuset_destruct(pmix_cpuset_t *c) { pmix_bfrops_base_tma_cpuset_destruct(c, NULL); } pmix_cpuset_t* PMIx_Cpuset_create(size_t n) { return pmix_bfrops_base_tma_cpuset_create(n, NULL); } void PMIx_Cpuset_free(pmix_cpuset_t *c, size_t n) { pmix_bfrops_base_tma_cpuset_free(c, n, NULL); } void PMIx_Geometry_construct(pmix_geometry_t *g) { pmix_bfrops_base_tma_geometry_construct(g, NULL); } void PMIx_Geometry_destruct(pmix_geometry_t *g) { pmix_bfrops_base_tma_geometry_destruct(g, NULL); } pmix_geometry_t* PMIx_Geometry_create(size_t n) { return pmix_bfrops_base_tma_geometry_create(n, NULL); } void PMIx_Geometry_free(pmix_geometry_t *g, size_t n) { pmix_bfrops_base_tma_geometry_free(g, n, NULL); } void PMIx_Device_construct(pmix_device_t *d) { pmix_bfrops_base_tma_device_construct(d, NULL); } void PMIx_Device_destruct(pmix_device_t *d) { pmix_bfrops_base_tma_device_destruct(d, NULL); } pmix_device_t* PMIx_Device_create(size_t n) { return pmix_bfrops_base_tma_device_create(n, NULL); } void PMIx_Device_free(pmix_device_t *d, size_t n) { pmix_bfrops_base_tma_device_free(d, n, NULL); } void PMIx_Node_pid_construct(pmix_node_pid_t *d) { pmix_bfrops_base_tma_node_pid_construct(d, NULL); } void PMIx_Node_pid_destruct(pmix_node_pid_t *d) { pmix_bfrops_base_tma_node_pid_destruct(d, NULL); } pmix_node_pid_t* PMIx_Node_pid_create(size_t n) { return pmix_bfrops_base_tma_node_pid_create(n, NULL); } void PMIx_Node_pid_free(pmix_node_pid_t *d, size_t n) { pmix_bfrops_base_tma_node_pid_free(d, n, NULL); } void PMIx_Resource_unit_construct(pmix_resource_unit_t *d) { pmix_bfrops_base_tma_resource_unit_construct(d, NULL); } void PMIx_Resource_unit_destruct(pmix_resource_unit_t *d) { pmix_bfrops_base_tma_resource_unit_destruct(d, NULL); } pmix_resource_unit_t* PMIx_Resource_unit_create(size_t n) { return pmix_bfrops_base_tma_resource_unit_create(n, NULL); } void PMIx_Resource_unit_free(pmix_resource_unit_t *d, size_t n) { pmix_bfrops_base_tma_resource_unit_free(d, n, NULL); } void PMIx_Device_distance_construct(pmix_device_distance_t *d) { pmix_bfrops_base_tma_device_distance_construct(d, NULL); } void PMIx_Device_distance_destruct(pmix_device_distance_t *d) { pmix_bfrops_base_tma_device_distance_destruct(d, NULL); } pmix_device_distance_t* PMIx_Device_distance_create(size_t n) { return pmix_bfrops_base_tma_device_distance_create(n, NULL); } void PMIx_Device_distance_free(pmix_device_distance_t *d, size_t n) { pmix_bfrops_base_tma_device_distance_free(d, n, NULL); } void PMIx_Byte_object_construct(pmix_byte_object_t *b) { pmix_bfrops_base_tma_byte_object_construct(b, NULL); } void PMIx_Byte_object_destruct(pmix_byte_object_t *b) { pmix_bfrops_base_tma_byte_object_destruct(b, NULL); } pmix_byte_object_t* PMIx_Byte_object_create(size_t n) { return pmix_bfrops_base_tma_byte_object_create(n, NULL); } void PMIx_Byte_object_load(pmix_byte_object_t *b, char *d, size_t sz) { b->bytes = d; b->size = sz; } void PMIx_Byte_object_free(pmix_byte_object_t *b, size_t n) { pmix_bfrops_base_tma_byte_object_free(b, n, NULL); } void PMIx_Endpoint_construct(pmix_endpoint_t *e) { pmix_bfrops_base_tma_endpoint_construct(e, NULL); } void PMIx_Endpoint_destruct(pmix_endpoint_t *e) { pmix_bfrops_base_tma_endpoint_destruct(e, NULL); } pmix_endpoint_t* PMIx_Endpoint_create(size_t n) { return pmix_bfrops_base_tma_endpoint_create(n, NULL); } void PMIx_Endpoint_free(pmix_endpoint_t *e, size_t n) { pmix_bfrops_base_tma_endpoint_free(e, n, NULL); } PMIX_EXPORT void PMIx_Envar_construct(pmix_envar_t *e) { pmix_bfrops_base_tma_envar_construct(e, NULL); } PMIX_EXPORT void PMIx_Envar_destruct(pmix_envar_t *e) { pmix_bfrops_base_tma_envar_destruct(e, NULL); } PMIX_EXPORT pmix_envar_t* PMIx_Envar_create(size_t n) { return pmix_bfrops_base_tma_envar_create(n, NULL); } void PMIx_Envar_free(pmix_envar_t *e, size_t n) { pmix_bfrops_base_tma_envar_free(e, n, NULL); } void PMIx_Envar_load(pmix_envar_t *e, char *var, char *value, char separator) { pmix_bfrops_base_tma_envar_load(e, var, value, separator, NULL); } void PMIx_Data_buffer_construct(pmix_data_buffer_t *b) { pmix_bfrops_base_tma_data_buffer_construct(b, NULL); } void PMIx_Data_buffer_destruct(pmix_data_buffer_t *b) { pmix_bfrops_base_tma_data_buffer_destruct(b, NULL); } pmix_data_buffer_t* PMIx_Data_buffer_create(void) { return pmix_bfrops_base_tma_data_buffer_create(NULL); } void PMIx_Data_buffer_release(pmix_data_buffer_t *b) { pmix_bfrops_base_tma_data_buffer_release(b, NULL); } void PMIx_Data_buffer_load(pmix_data_buffer_t *b, char *bytes, size_t sz) { pmix_bfrops_base_tma_data_buffer_load(b, bytes, sz, NULL); } void PMIx_Data_buffer_unload(pmix_data_buffer_t *b, char **bytes, size_t *sz) { pmix_bfrops_base_tma_data_buffer_unload(b, bytes, sz, NULL); } void PMIx_Proc_construct(pmix_proc_t *p) { pmix_bfrops_base_tma_proc_construct(p, NULL); } void PMIx_Proc_destruct(pmix_proc_t *p) { pmix_bfrops_base_tma_proc_destruct(p, NULL); } pmix_proc_t* PMIx_Proc_create(size_t n) { return pmix_bfrops_base_tma_proc_create(n, NULL); } void PMIx_Proc_free(pmix_proc_t *p, size_t n) { pmix_bfrops_base_tma_proc_free(p, n, NULL); } void PMIx_Proc_load(pmix_proc_t *p, const char *nspace, pmix_rank_t rank) { pmix_bfrops_base_tma_proc_load(p, nspace, rank, NULL); } void PMIx_Multicluster_nspace_construct(pmix_nspace_t target, pmix_nspace_t cluster, pmix_nspace_t nspace) { pmix_bfrops_base_tma_multicluster_nspace_construct(target, cluster, nspace, NULL); } void PMIx_Multicluster_nspace_parse(pmix_nspace_t target, pmix_nspace_t cluster, pmix_nspace_t nspace) { pmix_bfrops_base_tma_multicluster_nspace_parse(target, cluster, nspace, NULL); } void PMIx_Proc_info_construct(pmix_proc_info_t *p) { pmix_bfrops_base_tma_proc_info_construct(p, NULL); } void PMIx_Proc_info_destruct(pmix_proc_info_t *p) { pmix_bfrops_base_tma_proc_info_destruct(p, NULL); } pmix_proc_info_t* PMIx_Proc_info_create(size_t n) { return pmix_bfrops_base_tma_proc_info_create(n, NULL); } void PMIx_Proc_info_free(pmix_proc_info_t *p, size_t n) { pmix_bfrops_base_tma_proc_info_free(p, n, NULL); } void PMIx_Pdata_construct(pmix_pdata_t *p) { pmix_bfrops_base_tma_pdata_construct(p, NULL); } void PMIx_Pdata_destruct(pmix_pdata_t *p) { pmix_bfrops_base_tma_pdata_destruct(p, NULL); } pmix_pdata_t* PMIx_Pdata_create(size_t n) { return pmix_bfrops_base_tma_pdata_create(n, NULL); } void PMIx_Pdata_free(pmix_pdata_t *p, size_t n) { pmix_bfrops_base_tma_pdata_free(p, n, NULL); } void PMIx_Pdata_load(pmix_pdata_t *dest, const pmix_proc_t *p, const char *key, const void *data, pmix_data_type_t type) { pmix_bfrops_base_tma_pdata_load(dest, p, key, data, type, NULL); } void PMIx_Pdata_xfer(pmix_pdata_t *dest, pmix_pdata_t *src) { pmix_bfrops_base_tma_pdata_xfer(dest, src, NULL); } void PMIx_App_construct(pmix_app_t *p) { pmix_bfrops_base_tma_app_construct(p, NULL); } void PMIx_App_destruct(pmix_app_t *p) { pmix_bfrops_base_tma_app_destruct(p, NULL); } pmix_app_t* PMIx_App_create(size_t n) { return pmix_bfrops_base_tma_app_create(n, NULL); } void PMIx_App_info_create(pmix_app_t *p, size_t n) { pmix_bfrops_base_tma_app_info_create(p, n, NULL); } void PMIx_App_free(pmix_app_t *p, size_t n) { pmix_bfrops_base_tma_app_free(p, n, NULL); } void PMIx_App_release(pmix_app_t *p) { pmix_bfrops_base_tma_app_release(p, NULL); } void PMIx_Query_construct(pmix_query_t *p) { pmix_bfrops_base_tma_query_construct(p, NULL); } void PMIx_Query_destruct(pmix_query_t *p) { pmix_bfrops_base_tma_query_destruct(p, NULL); } pmix_query_t* PMIx_Query_create(size_t n) { return pmix_bfrops_base_tma_query_create(n, NULL); } void PMIx_Query_qualifiers_create(pmix_query_t *p, size_t n) { pmix_bfrops_base_tma_query_qualifiers_create(p, n, NULL); } void PMIx_Query_free(pmix_query_t *p, size_t n) { pmix_bfrops_base_tma_query_free(p, n, NULL); } void PMIx_Query_release(pmix_query_t *p) { pmix_bfrops_base_tma_query_release(p, NULL); } void PMIx_Regattr_construct(pmix_regattr_t *p) { pmix_bfrops_base_tma_regattr_construct(p, NULL); } void PMIx_Regattr_destruct(pmix_regattr_t *p) { pmix_bfrops_base_tma_regattr_destruct(p, NULL); } pmix_regattr_t* PMIx_Regattr_create(size_t n) { return pmix_bfrops_base_tma_regattr_create(n, NULL); } void PMIx_Regattr_free(pmix_regattr_t *p, size_t n) { pmix_bfrops_base_tma_regattr_free(p, n, NULL); } void PMIx_Regattr_load(pmix_regattr_t *p, const char *name, const char *key, pmix_data_type_t type, const char *description) { pmix_bfrops_base_tma_regattr_load(p, name, key, type, description, NULL); } void PMIx_Regattr_xfer(pmix_regattr_t *dest, const pmix_regattr_t *src) { pmix_bfrops_base_tma_regattr_xfer(dest, src, NULL); } void PMIx_Data_array_init(pmix_data_array_t *p, pmix_data_type_t type) { pmix_bfrops_base_tma_data_array_init(p, type, NULL); } void PMIx_Data_array_construct(pmix_data_array_t *p, size_t num, pmix_data_type_t type) { pmix_bfrops_base_tma_data_array_construct(p, num, type, NULL); } void PMIx_Data_array_destruct(pmix_data_array_t *d) { pmix_bfrops_base_tma_data_array_destruct(d, NULL); } PMIX_EXPORT pmix_data_array_t* PMIx_Data_array_create(size_t n, pmix_data_type_t type) { return pmix_bfrops_base_tma_data_array_create(n, type, NULL); } PMIX_EXPORT void PMIx_Data_array_free(pmix_data_array_t *p) { pmix_bfrops_base_tma_data_array_free(p, NULL); } pmix-6.1.1~rc2/src/mca/bfrops/base/bfrop_base_squash.c0000664000175000017500000003222115203536752023063 0ustar alastairalastair/* * Copyright (c) 2019 IBM Corporation. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * * Copyright (c) 2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include #ifdef HAVE_SYS_TYPES_H # include #endif #include "src/mca/bfrops/base/base.h" /* Flexible packing constants */ #define FLEX_BASE7_MAX_BUF_SIZE (SIZEOF_SIZE_T + 1) #define FLEX_BASE7_MASK ((1 << 7) - 1) #define FLEX_BASE7_SHIFT 7 #define FLEX_BASE7_CONT_FLAG (1 << 7) /** * Packing conversion of a signed integer value to a flexible representation. * The main idea is to split a signed negative value onto an absolute value * and a sign bit stored in the special location. * This allows efficient representetion of negative values in the * flexible form. * * type - type (pmix_data_type_t) of integer value * ptr - pointer to the signed integer value * with the type defined as (type) * out - flexible representation of *ptr, * extended to uint64_t if needed * (see a comment to `pmix_bfrops_pack_flex` for additional details) */ #define FLEX128_PACK_CONVERT_SIGNED(type, ptr, out) \ do { \ type __tbuf = 0; \ size_t __tmp; \ int __sign = 0; \ memcpy(&__tbuf, (ptr), sizeof(type)); \ __tmp = __tbuf; \ (out) = (size_t) __tmp; \ if (__tmp & (1UL << (sizeof(__tmp) * CHAR_BIT - 1))) { \ __sign = 1; \ out = ~(out); \ } \ (out) = ((out) << 1) + __sign; \ } while (0) /** * Packing conversion of a signed integer value to a flexible representation. * For unsigned types it is reduced to a memcopy. * * type - usual integer C-type of integer value * ptr - pointer to the signed integer value * with the type defined as (type) * out - flexible representation of *ptr, * extended to uint64_t if needed * (see a comment to `pmix_bfrops_pack_flex` for additional details) */ #define FLEX128_PACK_CONVERT_UNSIGNED(type, ptr, out) \ do { \ type __tbuf = 0; \ memcpy(&__tbuf, (ptr), sizeof(type)); \ out = __tbuf; \ } while (0) /** * Packing conversion from integer value to a flexible representation. * * r - return status code * t - type (pmix_data_type_t) of integer value, it is determines * which type of integer is converted * s - pointer to the integer value with the type defined as (t) * d - flexible representation output value (uin64_t) * (see a comment to `pmix_bfrops_pack_flex` for additional details) */ #define FLEX128_PACK_CONVERT(r, t, s, d) \ do { \ (r) = PMIX_SUCCESS; \ switch (t) { \ case PMIX_INT16: \ FLEX128_PACK_CONVERT_SIGNED(int16_t, s, d); \ break; \ case PMIX_UINT16: \ FLEX128_PACK_CONVERT_UNSIGNED(uint16_t, s, d); \ break; \ case PMIX_INT: \ case PMIX_INT32: \ FLEX128_PACK_CONVERT_SIGNED(int32_t, s, d); \ break; \ case PMIX_UINT: \ case PMIX_UINT32: \ FLEX128_PACK_CONVERT_UNSIGNED(uint32_t, s, d); \ break; \ case PMIX_INT64: \ FLEX128_PACK_CONVERT_SIGNED(int64_t, s, d); \ break; \ case PMIX_SIZE: \ FLEX128_PACK_CONVERT_UNSIGNED(size_t, s, d); \ break; \ case PMIX_UINT64: \ FLEX128_PACK_CONVERT_UNSIGNED(uint64_t, s, d); \ break; \ default: \ (r) = PMIX_ERR_BAD_PARAM; \ } \ } while (0) /** * Unpacking conversion from a flexible representation to a * signed integer value. * * type - C-type of a signed integer value * val - flexible representation (uint64_t) * ptr - pointer to a 64-bit output buffer for the upacked value * (see a comment to `pmix_bfrops_pack_flex` for additional details) */ #define FLEX128_UNPACK_CONVERT_SIGNED(type, val, ptr) \ do { \ type __tbuf = 0; \ size_t __tmp = val; \ int sign = (__tmp) &1; \ __tmp >>= 1; \ if (sign) { \ __tmp = ~__tmp; \ } \ __tbuf = (type) __tmp; \ memcpy(ptr, &__tbuf, sizeof(type)); \ } while (0) /** * Unpacking conversion of a flexible representation value * to an unsigned integer. * * type - C-type of unsigned integer value * val - flexible representation value (uint64_t) * ptr - pointer to a 64-bit output buffer for the upacked value * (see a comment to `pmix_bfrops_pack_flex` for additional details) */ #define FLEX128_UNPACK_CONVERT_UNSIGNED(type, val, ptr) \ do { \ type __tbuf = 0; \ __tbuf = (type) val; \ memcpy(ptr, &__tbuf, sizeof(type)); \ } while (0) /** * Unpacking conversion of a flexible representation value * to an integer. * * r - return status code * t - type (pmix_data_type_t) of integer value, it is determines * which type of integer is converted * s - flex-representation value (uin64_t) * d - pointer to a 64-bit output buffer for the upacked value * (see a comment to `pmix_bfrops_pack_flex` for additional details) */ #define FLEX128_UNPACK_CONVERT(r, t, s, d) \ do { \ (r) = PMIX_SUCCESS; \ switch (t) { \ case PMIX_INT16: \ FLEX128_UNPACK_CONVERT_SIGNED(int16_t, s, d); \ break; \ case PMIX_UINT16: \ FLEX128_UNPACK_CONVERT_UNSIGNED(uint16_t, s, d); \ break; \ case PMIX_INT: \ case PMIX_INT32: \ FLEX128_UNPACK_CONVERT_SIGNED(int32_t, s, d); \ break; \ case PMIX_UINT: \ case PMIX_UINT32: \ FLEX128_UNPACK_CONVERT_UNSIGNED(uint32_t, s, d); \ break; \ case PMIX_INT64: \ FLEX128_UNPACK_CONVERT_SIGNED(int64_t, s, d); \ break; \ case PMIX_SIZE: \ FLEX128_UNPACK_CONVERT_UNSIGNED(size_t, s, d); \ break; \ case PMIX_UINT64: \ FLEX128_UNPACK_CONVERT_UNSIGNED(uint64_t, s, d); \ break; \ default: \ (r) = PMIX_ERR_BAD_PARAM; \ } \ } while (0) static size_t flex_pack_integer(size_t val, uint8_t out_buf[FLEX_BASE7_MAX_BUF_SIZE]); static size_t flex_unpack_integer(const uint8_t in_buf[], size_t buf_size, size_t *out_val, size_t *out_val_size); pmix_status_t pmix_bfrops_base_get_max_size(pmix_data_type_t type, size_t *size) { pmix_status_t rc; PMIX_SQUASH_TYPE_SIZEOF(rc, type, *size); /* the size of the packed value can be 1B larger * because of continuation flags */ *size += 1; return rc; } pmix_status_t pmix_bfrops_base_encode_int(pmix_data_type_t type, void *src, void *dst, size_t *size) { pmix_status_t rc = PMIX_SUCCESS; uint8_t tmp_buf[FLEX_BASE7_MAX_BUF_SIZE]; uint64_t tmp; FLEX128_PACK_CONVERT(rc, type, (uint8_t *) src, tmp); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } *size = flex_pack_integer(tmp, tmp_buf); memcpy(dst, tmp_buf, *size); return rc; } pmix_status_t pmix_bfrops_base_decode_int(pmix_data_type_t type, void *src, size_t src_len, void *dest, size_t *dst_size) { pmix_status_t rc = PMIX_SUCCESS; size_t tmp; size_t val_size, unpack_val_size; PMIX_SQUASH_TYPE_SIZEOF(rc, type, val_size); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } *dst_size = flex_unpack_integer(src, src_len, &tmp, &unpack_val_size); if (val_size < unpack_val_size) { // sanity check rc = PMIX_ERR_UNPACK_FAILURE; PMIX_ERROR_LOG(rc); return rc; } FLEX128_UNPACK_CONVERT(rc, type, tmp, (uint8_t *) dest); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } return rc; } /* * Typical representation of a number in computer systems is: * A[0]*B^0 + A[1]*B^1 + A[2]*B^2 + ... + A[n]*B^n * where B called a base and B == 256 (one byte) * * This encoding changes the default representation by introducing an additional * bit per each byte to store a "continuation flag". So integers are now encoded * with the same representation, but the base B = 128 and the remaining bit is * used to indicate whether or not the next byte contains more bits of this value. */ static size_t flex_pack_integer(size_t val, uint8_t out_buf[FLEX_BASE7_MAX_BUF_SIZE]) { size_t tmp = val; size_t idx = 0; do { uint8_t encoding = tmp & FLEX_BASE7_MASK; tmp >>= FLEX_BASE7_SHIFT; if (PMIX_UNLIKELY(tmp)) { encoding |= FLEX_BASE7_CONT_FLAG; } out_buf[idx++] = encoding; } while (tmp && idx < SIZEOF_SIZE_T); /* If we have leftover (VERY unlikely) */ if (PMIX_UNLIKELY(SIZEOF_SIZE_T == idx && tmp)) { out_buf[idx++] = tmp; } return idx; } /* * See a comment to `pmix_bfrops_pack_flex` for additional details. */ static size_t flex_unpack_integer(const uint8_t in_buf[], size_t buf_size, size_t *out_val, size_t *out_val_size) { size_t value = 0, shift = 0, shift_last = 0; size_t idx = 0; uint8_t val = 0, val_last = 0; uint8_t hi_bit = 0; size_t flex_size = buf_size; /* restrict the buf size to max flex size */ if (buf_size > FLEX_BASE7_MAX_BUF_SIZE) { flex_size = FLEX_BASE7_MAX_BUF_SIZE; } do { val = in_buf[idx++]; val_last = val; shift_last = shift; value = value + (((uint64_t) val & FLEX_BASE7_MASK) << shift); shift += FLEX_BASE7_SHIFT; } while (PMIX_UNLIKELY((val & FLEX_BASE7_CONT_FLAG) && (idx < (flex_size - 1)))); /* If we have leftover (VERY unlikely) */ if (PMIX_UNLIKELY((flex_size - 1) == idx && (val & FLEX_BASE7_CONT_FLAG))) { val = in_buf[idx++]; val_last = val; value = value + ((uint64_t) val << shift); shift_last = shift; } /* compute the most significant bit of val */ while (val_last != 0) { val_last >>= 1; hi_bit++; } /* compute the real val size */ *out_val_size = (hi_bit + shift_last) / CHAR_BIT + !!((hi_bit + shift_last) & (CHAR_BIT - 1)); *out_val = value; return idx; } pmix-6.1.1~rc2/src/mca/bfrops/v21/0000775000175000017500000000000015203536752016727 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/bfrops/v21/bfrop_pmix21_component.c0000664000175000017500000000674315203536752023477 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennbfropsee and The University * of Tennbfropsee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include "bfrop_pmix21.h" #include "src/mca/bfrops/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_error.h" extern pmix_bfrops_module_t pmix_bfrops_pmix21_module; static pmix_status_t component_open(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_close(void); static pmix_bfrops_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_bfrops_base_component_t pmix_mca_bfrops_v21_component = { .base = { PMIX_BFROPS_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "v21", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .priority = 30, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, bfrops, v21) pmix_status_t component_open(void) { /* setup the types array */ PMIX_CONSTRUCT(&pmix_mca_bfrops_v21_component.types, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_mca_bfrops_v21_component.types, 32, INT_MAX, 16); return PMIX_SUCCESS; } pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = pmix_mca_bfrops_v21_component.priority; *module = (pmix_mca_base_module_t *) &pmix_bfrops_pmix21_module; return PMIX_SUCCESS; } pmix_status_t component_close(void) { PMIX_DESTRUCT(&pmix_mca_bfrops_v21_component.types); return PMIX_SUCCESS; } static pmix_bfrops_module_t *assign_module(void) { pmix_output_verbose(10, pmix_bfrops_base_framework.framework_output, "bfrops:pmix21x assigning module"); return &pmix_bfrops_pmix21_module; } pmix-6.1.1~rc2/src/mca/bfrops/v21/bfrop_pmix21.c0000664000175000017500000010452015203536752021405 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "bfrop_pmix21.h" #include "src/mca/bfrops/base/base.h" static pmix_status_t init(void); static void finalize(void); static pmix_status_t pmix21_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type); static pmix_status_t pmix21_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix21_copy(void **dest, void *src, pmix_data_type_t type); static pmix_status_t pmix21_print(char **output, char *prefix, void *src, pmix_data_type_t type); static const char *data_type_string(pmix_data_type_t type); pmix_bfrops_module_t pmix_bfrops_pmix21_module = { .version = "v21", .init = init, .finalize = finalize, .pack = pmix21_pack, .unpack = pmix21_unpack, .copy = pmix21_copy, .print = pmix21_print, .copy_payload = pmix_bfrops_base_copy_payload, .value_xfer = pmix_bfrops_base_value_xfer, .value_load = pmix_bfrops_base_value_load, .value_unload = pmix_bfrops_base_value_unload, .value_cmp = pmix_bfrops_base_value_cmp, .data_type_string = data_type_string }; /* DEPRECATED data type values */ #define PMIX_MODEX 29 #define PMIX_INFO_ARRAY 44 /**** PMIX MODEX STRUCT - DEPRECATED ****/ typedef struct pmix_modex_data { char nspace[PMIX_MAX_NSLEN + 1]; int rank; uint8_t *blob; size_t size; } pmix_modex_data_t; static pmix_status_t pack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t unpack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t unpack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t unpack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t unpack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t unpack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix21_bfrop_pack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pmix21_bfrop_pack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pmix21_bfrop_unpack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix21_bfrop_unpack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix21_bfrop_copy_array(pmix_info_array_t **dest, pmix_info_array_t *src, pmix_data_type_t type); static pmix_status_t pmix21_bfrop_copy_modex(pmix_modex_data_t **dest, pmix_modex_data_t *src, pmix_data_type_t type); static pmix_status_t pmix21_bfrop_print_array(char **output, char *prefix, pmix_info_array_t *src, pmix_data_type_t type); static pmix_status_t pmix21_bfrop_print_modex(char **output, char *prefix, pmix_modex_data_t *src, pmix_data_type_t type); static pmix_status_t init(void) { /* some standard types don't require anything special */ PMIX_REGISTER_TYPE("PMIX_BOOL", PMIX_BOOL, pmix_bfrops_base_pack_bool, pmix_bfrops_base_unpack_bool, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_bool, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE", PMIX_BYTE, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_byte, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_STRING", PMIX_STRING, pmix_bfrops_base_pack_string, pmix_bfrops_base_unpack_string, pmix_bfrops_base_copy_string, pmix_bfrops_base_print_string, &pmix_mca_bfrops_v21_component.types); /* Register the rest of the standard generic types to point to internal functions */ PMIX_REGISTER_TYPE("PMIX_SIZE", PMIX_SIZE, pack_sizet, unpack_sizet, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_size, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_PID", PMIX_PID, pmix_bfrops_base_pack_pid, pmix_bfrops_base_unpack_pid, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pid, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_INT", PMIX_INT, pack_int, unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int, &pmix_mca_bfrops_v21_component.types); /* Register all the standard fixed types to point to base functions */ PMIX_REGISTER_TYPE("PMIX_INT8", PMIX_INT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int8, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_INT16", PMIX_INT16, pack_int16, unpack_int16, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int16, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_INT32", PMIX_INT32, pack_int32, unpack_int32, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int32, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_INT64", PMIX_INT64, pack_int64, unpack_int64, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int64, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_UINT", PMIX_UINT, pack_int, unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_UINT8", PMIX_UINT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint8, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_UINT16", PMIX_UINT16, pack_int16, unpack_int16, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint16, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_UINT32", PMIX_UINT32, pack_int32, unpack_int32, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint32, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_UINT64", PMIX_UINT64, pack_int64, unpack_int64, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint64, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_FLOAT", PMIX_FLOAT, pmix_bfrops_base_pack_float, pmix_bfrops_base_unpack_float, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_float, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_DOUBLE", PMIX_DOUBLE, pmix_bfrops_base_pack_double, pmix_bfrops_base_unpack_double, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_double, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_TIMEVAL", PMIX_TIMEVAL, pmix_bfrops_base_pack_timeval, pmix_bfrops_base_unpack_timeval, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_timeval, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_TIME", PMIX_TIME, pmix_bfrops_base_pack_time, pmix_bfrops_base_unpack_time, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_time, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_STATUS", PMIX_STATUS, pmix_bfrops_base_pack_status, pmix_bfrops_base_unpack_status, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_status, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_VALUE", PMIX_VALUE, pmix_bfrops_base_pack_value, pmix_bfrops_base_unpack_value, pmix_bfrops_base_copy_value, pmix_bfrops_base_print_value, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_PROC", PMIX_PROC, pmix_bfrops_base_pack_proc, pmix_bfrops_base_unpack_proc, pmix_bfrops_base_copy_proc, pmix_bfrops_base_print_proc, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_APP", PMIX_APP, pmix_bfrops_base_pack_app, pmix_bfrops_base_unpack_app, pmix_bfrops_base_copy_app, pmix_bfrops_base_print_app, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_INFO", PMIX_INFO, pmix_bfrops_base_pack_info, pmix_bfrops_base_unpack_info, pmix_bfrops_base_copy_info, pmix_bfrops_base_print_info, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_PDATA", PMIX_PDATA, pmix_bfrops_base_pack_pdata, pmix_bfrops_base_unpack_pdata, pmix_bfrops_base_copy_pdata, pmix_bfrops_base_print_pdata, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_BUFFER", PMIX_BUFFER, pmix_bfrops_base_pack_buf, pmix_bfrops_base_unpack_buf, pmix_bfrops_base_copy_buf, pmix_bfrops_base_print_buf, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE_OBJECT", PMIX_BYTE_OBJECT, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_KVAL", PMIX_KVAL, pmix_bfrops_base_pack_kval, pmix_bfrops_base_unpack_kval, pmix_bfrops_base_copy_kval, pmix_bfrops_base_print_kval, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_MODEX", PMIX_MODEX, pmix21_bfrop_pack_modex, pmix21_bfrop_unpack_modex, pmix21_bfrop_copy_modex, pmix21_bfrop_print_modex, &pmix_mca_bfrops_v21_component.types); /* these are fixed-sized values and can be done by base */ PMIX_REGISTER_TYPE("PMIX_PERSIST", PMIX_PERSIST, pmix_bfrops_base_pack_persist, pmix_bfrops_base_unpack_persist, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_persist, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_POINTER", PMIX_POINTER, pmix_bfrops_base_pack_ptr, pmix_bfrops_base_unpack_ptr, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_SCOPE", PMIX_SCOPE, pmix_bfrops_base_pack_scope, pmix_bfrops_base_unpack_scope, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_scope, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_RANGE", PMIX_DATA_RANGE, pmix_bfrops_base_pack_range, pmix_bfrops_base_unpack_range, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_COMMAND", PMIX_COMMAND, pmix_bfrops_base_pack_cmd, pmix_bfrops_base_unpack_cmd, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_cmd, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_INFO_DIRECTIVES", PMIX_INFO_DIRECTIVES, pmix_bfrops_base_pack_info_directives, pmix_bfrops_base_unpack_info_directives, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_info_directives, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_TYPE", PMIX_DATA_TYPE, pmix_bfrops_base_pack_datatype, pmix_bfrops_base_unpack_datatype, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_datatype, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_STATE", PMIX_PROC_STATE, pmix_bfrops_base_pack_pstate, pmix_bfrops_base_unpack_pstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pstate, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_INFO", PMIX_PROC_INFO, pmix_bfrops_base_pack_pinfo, pmix_bfrops_base_unpack_pinfo, pmix_bfrops_base_copy_pinfo, pmix_bfrops_base_print_pinfo, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_ARRAY", PMIX_DATA_ARRAY, pmix_bfrops_base_pack_darray, pmix_bfrops_base_unpack_darray, pmix_bfrops_base_copy_darray, pmix_bfrops_base_print_darray, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_RANK", PMIX_PROC_RANK, pmix_bfrops_base_pack_rank, pmix_bfrops_base_unpack_rank, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_rank, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_QUERY", PMIX_QUERY, pmix_bfrops_base_pack_query, pmix_bfrops_base_unpack_query, pmix_bfrops_base_copy_query, pmix_bfrops_base_print_query, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_STRING", PMIX_COMPRESSED_STRING, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v21_component.types); PMIX_REGISTER_TYPE("PMIX_ALLOC_DIRECTIVE", PMIX_ALLOC_DIRECTIVE, pmix_bfrops_base_pack_alloc_directive, pmix_bfrops_base_unpack_alloc_directive, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_alloc_directive, &pmix_mca_bfrops_v21_component.types); /**** DEPRECATED ****/ PMIX_REGISTER_TYPE("PMIX_INFO_ARRAY", PMIX_INFO_ARRAY, pmix21_bfrop_pack_array, pmix21_bfrop_unpack_array, pmix21_bfrop_copy_array, pmix21_bfrop_print_array, &pmix_mca_bfrops_v21_component.types); /********************/ return PMIX_SUCCESS; } static void finalize(void) { int n; pmix_bfrop_type_info_t *info; for (n = 0; n < pmix_mca_bfrops_v21_component.types.size; n++) { if (NULL != (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v21_component.types, n))) { PMIX_RELEASE(info); pmix_pointer_array_set_item(&pmix_mca_bfrops_v21_component.types, n, NULL); } } } static pmix_status_t pmix21_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_pack(&pmix_mca_bfrops_v21_component.types, buffer, src, num_vals, type); } static pmix_status_t pmix21_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_unpack(&pmix_mca_bfrops_v21_component.types, buffer, dest, num_vals, type); } static pmix_status_t pmix21_copy(void **dest, void *src, pmix_data_type_t type) { return pmix_bfrops_base_copy(&pmix_mca_bfrops_v21_component.types, dest, src, type); } static pmix_status_t pmix21_print(char **output, char *prefix, void *src, pmix_data_type_t type) { return pmix_bfrops_base_print(&pmix_mca_bfrops_v21_component.types, output, prefix, src, type); } static const char *data_type_string(pmix_data_type_t type) { return pmix_bfrops_base_data_type_string(&pmix_mca_bfrops_v21_component.types, type); } static pmix_status_t pack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them */ if (PMIX_SUCCESS != (ret = pmix_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_INT))) { return ret; } /* Turn around and pack the real type */ PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, BFROP_TYPE_INT, regtypes); return ret; } static pmix_status_t pack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them. */ if (PMIX_SUCCESS != (ret = pmix_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_SIZE_T))) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, BFROP_TYPE_SIZE_T, regtypes); return ret; } static pmix_status_t pack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint16_t tmp, *srctmp = (uint16_t *) src; char *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_pack_int16 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals * sizeof(tmp)))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { tmp = pmix_htons(srctmp[i]); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += num_vals * sizeof(tmp); buffer->bytes_used += num_vals * sizeof(tmp); return PMIX_SUCCESS; } static pmix_status_t pack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint32_t tmp, *srctmp = (uint32_t *) src; char *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_pack_int32 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals * sizeof(tmp)))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { tmp = htonl(srctmp[i]); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += num_vals * sizeof(tmp); buffer->bytes_used += num_vals * sizeof(tmp); return PMIX_SUCCESS; } static pmix_status_t pack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint64_t tmp, tmp2; char *dst; size_t bytes_packed = num_vals * sizeof(tmp); pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_pack_int64 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, bytes_packed))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { memcpy(&tmp2, (char *) src + i * sizeof(uint64_t), sizeof(uint64_t)); tmp = pmix_hton64(tmp2); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += bytes_packed; buffer->bytes_used += bytes_packed; return PMIX_SUCCESS; } static pmix_status_t unpack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix_bfrop_get_data_type(regtypes, buffer, &remote_type))) { return ret; } if (remote_type == BFROP_TYPE_INT) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, BFROP_TYPE_INT, regtypes); } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, int, remote_type, ret); } return ret; } static pmix_status_t unpack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix_bfrop_get_data_type(regtypes, buffer, &remote_type))) { PMIX_ERROR_LOG(ret); return ret; } if (remote_type == BFROP_TYPE_SIZE_T) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, BFROP_TYPE_SIZE_T, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); } } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, size_t, remote_type, ret); } return ret; } static pmix_status_t unpack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint16_t tmp, *desttmp = (uint16_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_int16 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = pmix_ntohs(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } static pmix_status_t unpack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint32_t tmp, *desttmp = (uint32_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_int32 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = ntohl(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } static pmix_status_t unpack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint64_t tmp, *desttmp = (uint64_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_int64 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = pmix_ntoh64(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } /**** DEPRECATED ****/ static pmix_status_t pmix21_bfrop_pack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_info_array_t *ptr; int32_t i; pmix_status_t ret; ptr = (pmix_info_array_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack the size */ if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_sizet(regtypes, buffer, &ptr[i].size, 1, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { /* pack the values */ if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_info(regtypes, buffer, ptr[i].array, ptr[i].size, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } static pmix_status_t pmix21_bfrop_pack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_modex_data_t *ptr; int32_t i; pmix_status_t ret; ptr = (pmix_modex_data_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_sizet(regtypes, buffer, &ptr[i].size, 1, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_byte(regtypes, buffer, ptr[i].blob, ptr[i].size, PMIX_UINT8))) { return ret; } } } return PMIX_SUCCESS; } /********************/ /**** DEPRECATED ****/ static pmix_status_t pmix21_bfrop_unpack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_info_array_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix21_bfrop_unpack: %d info arrays", *num_vals); ptr = (pmix_info_array_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix21_bfrop_unpack: init array[%d]", i); memset(&ptr[i], 0, sizeof(pmix_info_array_t)); /* unpack the size of this array */ m = 1; if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { ptr[i].array = (pmix_info_t *) malloc(ptr[i].size * sizeof(pmix_info_t)); m = ptr[i].size; if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_value(regtypes, buffer, ptr[i].array, &m, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } static pmix_status_t pmix21_bfrop_unpack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_modex_data_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d modex", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_modex_data_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { memset(&ptr[i], 0, sizeof(pmix_modex_data_t)); /* unpack the number of bytes */ m = 1; if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { ptr[i].blob = (uint8_t *) malloc(ptr[i].size * sizeof(uint8_t)); m = ptr[i].size; if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_byte(regtypes, buffer, ptr[i].blob, &m, PMIX_UINT8))) { return ret; } } } return PMIX_SUCCESS; } /********************/ /**** DEPRECATED ****/ static pmix_status_t pmix21_bfrop_copy_array(pmix_info_array_t **dest, pmix_info_array_t *src, pmix_data_type_t type) { pmix_info_t *d1, *s1; PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_info_array_t *) malloc(sizeof(pmix_info_array_t)); (*dest)->size = src->size; (*dest)->array = (pmix_info_t *) malloc(src->size * sizeof(pmix_info_t)); d1 = (pmix_info_t *) (*dest)->array; s1 = (pmix_info_t *) src->array; memcpy(d1, s1, src->size * sizeof(pmix_info_t)); return PMIX_SUCCESS; } static pmix_status_t pmix21_bfrop_copy_modex(pmix_modex_data_t **dest, pmix_modex_data_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_modex_data_t *) malloc(sizeof(pmix_modex_data_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } (*dest)->blob = NULL; (*dest)->size = 0; if (NULL != src->blob) { (*dest)->blob = (uint8_t *) malloc(src->size * sizeof(uint8_t)); if (NULL == (*dest)->blob) { return PMIX_ERR_OUT_OF_RESOURCE; } memcpy((*dest)->blob, src->blob, src->size * sizeof(uint8_t)); (*dest)->size = src->size; } return PMIX_SUCCESS; } /*******************/ /**** DEPRECATED ****/ static pmix_status_t pmix21_bfrop_print_array(char **output, char *prefix, pmix_info_array_t *src, pmix_data_type_t type) { size_t j; char *tmp, *tmp2, *tmp3, *pfx; pmix_info_t *s1; PMIX_HIDE_UNUSED_PARAMS(type); if (0 > asprintf(&tmp, "%sARRAY SIZE: %ld", prefix, (long) src->size)) { return PMIX_ERR_NOMEM; } if (0 > asprintf(&pfx, "\n%s\t", (NULL == prefix) ? "" : prefix)) { free(tmp); return PMIX_ERR_NOMEM; } s1 = (pmix_info_t *) src->array; for (j = 0; j < src->size; j++) { pmix_bfrops_base_print_info(&tmp2, pfx, &s1[j], PMIX_INFO); if (0 > asprintf(&tmp3, "%s%s", tmp, tmp2)) { free(tmp); free(tmp2); free(pfx); return PMIX_ERR_NOMEM; } free(tmp); free(tmp2); tmp = tmp3; } *output = tmp; free(pfx); return PMIX_SUCCESS; } static pmix_status_t pmix21_bfrop_print_modex(char **output, char *prefix, pmix_modex_data_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } /********************/ pmix-6.1.1~rc2/src/mca/bfrops/v21/Makefile.am0000664000175000017500000000345315203536752020770 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = bfrop_pmix21.h sources = \ bfrop_pmix21_component.c \ bfrop_pmix21.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_bfrops_v21_DSO lib = lib_sources = component = pmix_mca_bfrops_v21.la component_sources = $(headers) $(sources) else lib = libpmix_mca_bfrops_v21.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_bfrops_v21_la_SOURCES = $(component_sources) pmix_mca_bfrops_v21_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_bfrops_v21_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_bfrops_v21_la_SOURCES = $(lib_sources) libpmix_mca_bfrops_v21_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/bfrops/v21/bfrop_pmix21.h0000664000175000017500000000227215203536752021413 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2017 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_BFROPS_PMIX2_H #define PMIX_BFROPS_PMIX2_H #include "src/mca/bfrops/bfrops.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_bfrops_base_component_t pmix_mca_bfrops_v21_component; extern pmix_bfrops_module_t pmix_bfrops_pmix21_module; END_C_DECLS #endif /* PMIX_BFROPS_PMIX2_H */ pmix-6.1.1~rc2/src/mca/bfrops/v3/0000775000175000017500000000000015203536752016647 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/bfrops/v3/bfrop_pmix3_component.c0000664000175000017500000000672715203536752023341 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennbfropsee and The University * of Tennbfropsee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include "bfrop_pmix3.h" #include "src/mca/bfrops/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_error.h" extern pmix_bfrops_module_t pmix_bfrops_pmix3_module; static pmix_status_t component_open(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_close(void); static pmix_bfrops_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_bfrops_base_component_t pmix_mca_bfrops_v3_component = { .base = { PMIX_BFROPS_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "v3", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .priority = 40, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, bfrops, v3) pmix_status_t component_open(void) { /* setup the types array */ PMIX_CONSTRUCT(&pmix_mca_bfrops_v3_component.types, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_mca_bfrops_v3_component.types, 32, INT_MAX, 16); return PMIX_SUCCESS; } pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = pmix_mca_bfrops_v3_component.priority; *module = (pmix_mca_base_module_t *) &pmix_bfrops_pmix3_module; return PMIX_SUCCESS; } pmix_status_t component_close(void) { PMIX_DESTRUCT(&pmix_mca_bfrops_v3_component.types); return PMIX_SUCCESS; } static pmix_bfrops_module_t *assign_module(void) { pmix_output_verbose(10, pmix_bfrops_base_framework.framework_output, "bfrops:pmix3x assigning module"); return &pmix_bfrops_pmix3_module; } pmix-6.1.1~rc2/src/mca/bfrops/v3/bfrop_pmix3.h0000664000175000017500000000227015203536752021251 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2017 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_BFROPS_PMIX3_H #define PMIX_BFROPS_PMIX3_H #include "src/mca/bfrops/bfrops.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_bfrops_base_component_t pmix_mca_bfrops_v3_component; extern pmix_bfrops_module_t pmix_bfrops_pmix3_module; END_C_DECLS #endif /* PMIX_BFROPS_PMIX3_H */ pmix-6.1.1~rc2/src/mca/bfrops/v3/bfrop_pmix3.c0000664000175000017500000010506515203536752021252 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "bfrop_pmix3.h" #include "src/mca/bfrops/base/base.h" static pmix_status_t init(void); static void finalize(void); static pmix_status_t pmix3_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type); static pmix_status_t pmix3_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix3_copy(void **dest, void *src, pmix_data_type_t type); static pmix_status_t pmix3_print(char **output, char *prefix, void *src, pmix_data_type_t type); static const char *data_type_string(pmix_data_type_t type); pmix_bfrops_module_t pmix_bfrops_pmix3_module = { .version = "v3", .init = init, .finalize = finalize, .pack = pmix3_pack, .unpack = pmix3_unpack, .copy = pmix3_copy, .print = pmix3_print, .copy_payload = pmix_bfrops_base_copy_payload, .value_xfer = pmix_bfrops_base_value_xfer, .value_load = pmix_bfrops_base_value_load, .value_unload = pmix_bfrops_base_value_unload, .value_cmp = pmix_bfrops_base_value_cmp, .data_type_string = data_type_string }; /* DEPRECATED data type values */ #define PMIX_MODEX 29 #define PMIX_INFO_ARRAY 44 /**** PMIX MODEX STRUCT - DEPRECATED ****/ typedef struct pmix_modex_data { char nspace[PMIX_MAX_NSLEN + 1]; int rank; uint8_t *blob; size_t size; } pmix_modex_data_t; static pmix_status_t pack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t unpack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t unpack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t unpack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t unpack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t unpack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix3_bfrop_pack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pmix3_bfrop_pack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); static pmix_status_t pmix3_bfrop_unpack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix3_bfrop_unpack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); static pmix_status_t pmix3_bfrop_copy_array(pmix_info_array_t **dest, pmix_info_array_t *src, pmix_data_type_t type); static pmix_status_t pmix3_bfrop_copy_modex(pmix_modex_data_t **dest, pmix_modex_data_t *src, pmix_data_type_t type); static pmix_status_t pmix3_bfrop_print_array(char **output, char *prefix, pmix_info_array_t *src, pmix_data_type_t type); static pmix_status_t pmix3_bfrop_print_modex(char **output, char *prefix, pmix_modex_data_t *src, pmix_data_type_t type); static pmix_status_t init(void) { /* some standard types don't require anything special */ PMIX_REGISTER_TYPE("PMIX_BOOL", PMIX_BOOL, pmix_bfrops_base_pack_bool, pmix_bfrops_base_unpack_bool, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_bool, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE", PMIX_BYTE, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_byte, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_STRING", PMIX_STRING, pmix_bfrops_base_pack_string, pmix_bfrops_base_unpack_string, pmix_bfrops_base_copy_string, pmix_bfrops_base_print_string, &pmix_mca_bfrops_v3_component.types); /* Register the rest of the standard generic types to point to internal functions */ PMIX_REGISTER_TYPE("PMIX_SIZE", PMIX_SIZE, pack_sizet, unpack_sizet, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_size, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_PID", PMIX_PID, pmix_bfrops_base_pack_pid, pmix_bfrops_base_unpack_pid, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pid, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_INT", PMIX_INT, pack_int, unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int, &pmix_mca_bfrops_v3_component.types); /* Register all the standard fixed types to point to base functions */ PMIX_REGISTER_TYPE("PMIX_INT8", PMIX_INT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int8, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_INT16", PMIX_INT16, pack_int16, unpack_int16, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int16, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_INT32", PMIX_INT32, pack_int32, unpack_int32, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int32, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_INT64", PMIX_INT64, pack_int64, unpack_int64, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_int64, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_UINT", PMIX_UINT, pack_int, unpack_int, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_UINT8", PMIX_UINT8, pmix_bfrops_base_pack_byte, pmix_bfrops_base_unpack_byte, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint8, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_UINT16", PMIX_UINT16, pack_int16, unpack_int16, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint16, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_UINT32", PMIX_UINT32, pack_int32, unpack_int32, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint32, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_UINT64", PMIX_UINT64, pack_int64, unpack_int64, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_uint64, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_FLOAT", PMIX_FLOAT, pmix_bfrops_base_pack_float, pmix_bfrops_base_unpack_float, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_float, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_DOUBLE", PMIX_DOUBLE, pmix_bfrops_base_pack_double, pmix_bfrops_base_unpack_double, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_double, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_TIMEVAL", PMIX_TIMEVAL, pmix_bfrops_base_pack_timeval, pmix_bfrops_base_unpack_timeval, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_timeval, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_TIME", PMIX_TIME, pmix_bfrops_base_pack_time, pmix_bfrops_base_unpack_time, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_time, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_STATUS", PMIX_STATUS, pmix_bfrops_base_pack_status, pmix_bfrops_base_unpack_status, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_status, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_VALUE", PMIX_VALUE, pmix_bfrops_base_pack_value, pmix_bfrops_base_unpack_value, pmix_bfrops_base_copy_value, pmix_bfrops_base_print_value, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_PROC", PMIX_PROC, pmix_bfrops_base_pack_proc, pmix_bfrops_base_unpack_proc, pmix_bfrops_base_copy_proc, pmix_bfrops_base_print_proc, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_APP", PMIX_APP, pmix_bfrops_base_pack_app, pmix_bfrops_base_unpack_app, pmix_bfrops_base_copy_app, pmix_bfrops_base_print_app, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_INFO", PMIX_INFO, pmix_bfrops_base_pack_info, pmix_bfrops_base_unpack_info, pmix_bfrops_base_copy_info, pmix_bfrops_base_print_info, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_PDATA", PMIX_PDATA, pmix_bfrops_base_pack_pdata, pmix_bfrops_base_unpack_pdata, pmix_bfrops_base_copy_pdata, pmix_bfrops_base_print_pdata, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_BUFFER", PMIX_BUFFER, pmix_bfrops_base_pack_buf, pmix_bfrops_base_unpack_buf, pmix_bfrops_base_copy_buf, pmix_bfrops_base_print_buf, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE_OBJECT", PMIX_BYTE_OBJECT, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_KVAL", PMIX_KVAL, pmix_bfrops_base_pack_kval, pmix_bfrops_base_unpack_kval, pmix_bfrops_base_copy_kval, pmix_bfrops_base_print_kval, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_MODEX", PMIX_MODEX, pmix3_bfrop_pack_modex, pmix3_bfrop_unpack_modex, pmix3_bfrop_copy_modex, pmix3_bfrop_print_modex, &pmix_mca_bfrops_v3_component.types); /* these are fixed-sized values and can be done by base */ PMIX_REGISTER_TYPE("PMIX_PERSIST", PMIX_PERSIST, pmix_bfrops_base_pack_persist, pmix_bfrops_base_unpack_persist, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_persist, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_POINTER", PMIX_POINTER, pmix_bfrops_base_pack_ptr, pmix_bfrops_base_unpack_ptr, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_SCOPE", PMIX_SCOPE, pmix_bfrops_base_pack_scope, pmix_bfrops_base_unpack_scope, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_scope, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_RANGE", PMIX_DATA_RANGE, pmix_bfrops_base_pack_range, pmix_bfrops_base_unpack_range, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_ptr, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_COMMAND", PMIX_COMMAND, pmix_bfrops_base_pack_cmd, pmix_bfrops_base_unpack_cmd, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_cmd, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_INFO_DIRECTIVES", PMIX_INFO_DIRECTIVES, pmix_bfrops_base_pack_info_directives, pmix_bfrops_base_unpack_info_directives, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_info_directives, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_TYPE", PMIX_DATA_TYPE, pmix_bfrops_base_pack_datatype, pmix_bfrops_base_unpack_datatype, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_datatype, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_STATE", PMIX_PROC_STATE, pmix_bfrops_base_pack_pstate, pmix_bfrops_base_unpack_pstate, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_pstate, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_INFO", PMIX_PROC_INFO, pmix_bfrops_base_pack_pinfo, pmix_bfrops_base_unpack_pinfo, pmix_bfrops_base_copy_pinfo, pmix_bfrops_base_print_pinfo, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_ARRAY", PMIX_DATA_ARRAY, pmix_bfrops_base_pack_darray, pmix_bfrops_base_unpack_darray, pmix_bfrops_base_copy_darray, pmix_bfrops_base_print_darray, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_RANK", PMIX_PROC_RANK, pmix_bfrops_base_pack_rank, pmix_bfrops_base_unpack_rank, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_rank, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_QUERY", PMIX_QUERY, pmix_bfrops_base_pack_query, pmix_bfrops_base_unpack_query, pmix_bfrops_base_copy_query, pmix_bfrops_base_print_query, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_COMPRESSED_STRING", PMIX_COMPRESSED_STRING, pmix_bfrops_base_pack_bo, pmix_bfrops_base_unpack_bo, pmix_bfrops_base_copy_bo, pmix_bfrops_base_print_bo, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_ALLOC_DIRECTIVE", PMIX_ALLOC_DIRECTIVE, pmix_bfrops_base_pack_alloc_directive, pmix_bfrops_base_unpack_alloc_directive, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_alloc_directive, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_IOF_CHANNEL", PMIX_IOF_CHANNEL, pmix_bfrops_base_pack_iof_channel, pmix_bfrops_base_unpack_iof_channel, pmix_bfrops_base_std_copy, pmix_bfrops_base_print_iof_channel, &pmix_mca_bfrops_v3_component.types); PMIX_REGISTER_TYPE("PMIX_ENVAR", PMIX_ENVAR, pmix_bfrops_base_pack_envar, pmix_bfrops_base_unpack_envar, pmix_bfrops_base_copy_envar, pmix_bfrops_base_print_envar, &pmix_mca_bfrops_v3_component.types); /**** DEPRECATED ****/ PMIX_REGISTER_TYPE("PMIX_INFO_ARRAY", PMIX_INFO_ARRAY, pmix3_bfrop_pack_array, pmix3_bfrop_unpack_array, pmix3_bfrop_copy_array, pmix3_bfrop_print_array, &pmix_mca_bfrops_v3_component.types); /********************/ return PMIX_SUCCESS; } static void finalize(void) { int n; pmix_bfrop_type_info_t *info; for (n = 0; n < pmix_mca_bfrops_v3_component.types.size; n++) { if (NULL != (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v3_component.types, n))) { PMIX_RELEASE(info); pmix_pointer_array_set_item(&pmix_mca_bfrops_v3_component.types, n, NULL); } } } static pmix_status_t pmix3_pack(pmix_buffer_t *buffer, const void *src, int num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_pack(&pmix_mca_bfrops_v3_component.types, buffer, src, num_vals, type); } static pmix_status_t pmix3_unpack(pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { /* kick the process off by passing this in to the base */ return pmix_bfrops_base_unpack(&pmix_mca_bfrops_v3_component.types, buffer, dest, num_vals, type); } static pmix_status_t pmix3_copy(void **dest, void *src, pmix_data_type_t type) { return pmix_bfrops_base_copy(&pmix_mca_bfrops_v3_component.types, dest, src, type); } static pmix_status_t pmix3_print(char **output, char *prefix, void *src, pmix_data_type_t type) { return pmix_bfrops_base_print(&pmix_mca_bfrops_v3_component.types, output, prefix, src, type); } static const char *data_type_string(pmix_data_type_t type) { return pmix_bfrops_base_data_type_string(&pmix_mca_bfrops_v3_component.types, type); } static pmix_status_t pack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them */ if (PMIX_SUCCESS != (ret = pmix_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_INT))) { return ret; } /* Turn around and pack the real type */ PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, BFROP_TYPE_INT, regtypes); return ret; } static pmix_status_t pack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them. */ if (PMIX_SUCCESS != (ret = pmix_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_SIZE_T))) { return ret; } PMIX_BFROPS_PACK_TYPE(ret, buffer, src, num_vals, BFROP_TYPE_SIZE_T, regtypes); return ret; } static pmix_status_t pack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint16_t tmp, *srctmp = (uint16_t *) src; char *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_pack_int16 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals * sizeof(tmp)))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { tmp = pmix_htons(srctmp[i]); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += num_vals * sizeof(tmp); buffer->bytes_used += num_vals * sizeof(tmp); return PMIX_SUCCESS; } static pmix_status_t pack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint32_t tmp, *srctmp = (uint32_t *) src; char *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_pack_int32 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals * sizeof(tmp)))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { tmp = htonl(srctmp[i]); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += num_vals * sizeof(tmp); buffer->bytes_used += num_vals * sizeof(tmp); return PMIX_SUCCESS; } static pmix_status_t pack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint64_t tmp, tmp2; char *dst; size_t bytes_packed = num_vals * sizeof(tmp); pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrops_base_pack_int64 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, bytes_packed))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { memcpy(&tmp2, (char *) src + i * sizeof(uint64_t), sizeof(uint64_t)); tmp = pmix_hton64(tmp2); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += bytes_packed; buffer->bytes_used += bytes_packed; return PMIX_SUCCESS; } static pmix_status_t unpack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix_bfrop_get_data_type(regtypes, buffer, &remote_type))) { return ret; } if (remote_type == BFROP_TYPE_INT) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, BFROP_TYPE_INT, regtypes); } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, int, remote_type, ret); } return ret; } static pmix_status_t unpack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix_bfrop_get_data_type(regtypes, buffer, &remote_type))) { PMIX_ERROR_LOG(ret); return ret; } if (remote_type == BFROP_TYPE_SIZE_T) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ PMIX_BFROPS_UNPACK_TYPE(ret, buffer, dest, num_vals, BFROP_TYPE_SIZE_T, regtypes); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); } } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, size_t, remote_type, ret); } return ret; } static pmix_status_t unpack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint16_t tmp, *desttmp = (uint16_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_int16 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = pmix_ntohs(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } static pmix_status_t unpack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint32_t tmp, *desttmp = (uint32_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_int32 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = ntohl(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } static pmix_status_t unpack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint64_t tmp, *desttmp = (uint64_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix_bfrop_unpack_int64 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = pmix_ntoh64(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } /**** DEPRECATED ****/ static pmix_status_t pmix3_bfrop_pack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_info_array_t *ptr; int32_t i; pmix_status_t ret; ptr = (pmix_info_array_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { /* pack the size */ if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_sizet(regtypes, buffer, &ptr[i].size, 1, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { /* pack the values */ if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_info(regtypes, buffer, ptr[i].array, ptr[i].size, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } static pmix_status_t pmix3_bfrop_pack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_modex_data_t *ptr; int32_t i; pmix_status_t ret; ptr = (pmix_modex_data_t *) src; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < num_vals; ++i) { if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_sizet(regtypes, buffer, &ptr[i].size, 1, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { if (PMIX_SUCCESS != (ret = pmix_bfrops_base_pack_byte(regtypes, buffer, ptr[i].blob, ptr[i].size, PMIX_UINT8))) { return ret; } } } return PMIX_SUCCESS; } /********************/ /**** DEPRECATED ****/ static pmix_status_t pmix3_bfrop_unpack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_info_array_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix3_bfrop_unpack: %d info arrays", *num_vals); ptr = (pmix_info_array_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix3_bfrop_unpack: init array[%d]", i); memset(&ptr[i], 0, sizeof(pmix_info_array_t)); /* unpack the size of this array */ m = 1; if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { ptr[i].array = (pmix_info_t *) malloc(ptr[i].size * sizeof(pmix_info_t)); m = ptr[i].size; if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_value(regtypes, buffer, ptr[i].array, &m, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } static pmix_status_t pmix3_bfrop_unpack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_modex_data_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix20_bfrop_unpack: %d modex", *num_vals); ptr = (pmix_modex_data_t *) dest; n = *num_vals; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < n; ++i) { memset(&ptr[i], 0, sizeof(pmix_modex_data_t)); /* unpack the number of bytes */ m = 1; if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { ptr[i].blob = (uint8_t *) malloc(ptr[i].size * sizeof(uint8_t)); m = ptr[i].size; if (PMIX_SUCCESS != (ret = pmix_bfrops_base_unpack_byte(regtypes, buffer, ptr[i].blob, &m, PMIX_UINT8))) { return ret; } } } return PMIX_SUCCESS; } /********************/ /**** DEPRECATED ****/ static pmix_status_t pmix3_bfrop_copy_array(pmix_info_array_t **dest, pmix_info_array_t *src, pmix_data_type_t type) { pmix_info_t *d1, *s1; PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_info_array_t *) malloc(sizeof(pmix_info_array_t)); (*dest)->size = src->size; (*dest)->array = (pmix_info_t *) malloc(src->size * sizeof(pmix_info_t)); d1 = (pmix_info_t *) (*dest)->array; s1 = (pmix_info_t *) src->array; memcpy(d1, s1, src->size * sizeof(pmix_info_t)); return PMIX_SUCCESS; } static pmix_status_t pmix3_bfrop_copy_modex(pmix_modex_data_t **dest, pmix_modex_data_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_modex_data_t *) malloc(sizeof(pmix_modex_data_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } (*dest)->blob = NULL; (*dest)->size = 0; if (NULL != src->blob) { (*dest)->blob = (uint8_t *) malloc(src->size * sizeof(uint8_t)); if (NULL == (*dest)->blob) { return PMIX_ERR_OUT_OF_RESOURCE; } memcpy((*dest)->blob, src->blob, src->size * sizeof(uint8_t)); (*dest)->size = src->size; } return PMIX_SUCCESS; } /*******************/ /**** DEPRECATED ****/ static pmix_status_t pmix3_bfrop_print_array(char **output, char *prefix, pmix_info_array_t *src, pmix_data_type_t type) { size_t j; char *tmp, *tmp2, *tmp3, *pfx; pmix_info_t *s1; PMIX_HIDE_UNUSED_PARAMS(type); if (0 > asprintf(&tmp, "%sARRAY SIZE: %ld", prefix, (long) src->size)) { return PMIX_ERR_NOMEM; } if (0 > asprintf(&pfx, "\n%s\t", (NULL == prefix) ? "" : prefix)) { free(tmp); return PMIX_ERR_NOMEM; } s1 = (pmix_info_t *) src->array; for (j = 0; j < src->size; j++) { pmix_bfrops_base_print_info(&tmp2, pfx, &s1[j], PMIX_INFO); if (0 > asprintf(&tmp3, "%s%s", tmp, tmp2)) { free(tmp); free(tmp2); free(pfx); return PMIX_ERR_NOMEM; } free(tmp); free(tmp2); tmp = tmp3; } *output = tmp; free(pfx); return PMIX_SUCCESS; } static pmix_status_t pmix3_bfrop_print_modex(char **output, char *prefix, pmix_modex_data_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } /********************/ pmix-6.1.1~rc2/src/mca/bfrops/v3/Makefile.am0000664000175000017500000000344015203536752020704 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = bfrop_pmix3.h sources = \ bfrop_pmix3_component.c \ bfrop_pmix3.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_bfrops_v3_DSO lib = lib_sources = component = pmix_mca_bfrops_v3.la component_sources = $(headers) $(sources) else lib = libpmix_mca_bfrops_v3.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_bfrops_v3_la_SOURCES = $(component_sources) pmix_mca_bfrops_v3_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_bfrops_v3_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_bfrops_v3_la_SOURCES = $(lib_sources) libpmix_mca_bfrops_v3_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/bfrops/Makefile.am0000664000175000017500000000257115203536752020360 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2017 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(LTDLINCL) # main library setup noinst_LTLIBRARIES = libmca_bfrops.la libmca_bfrops_la_SOURCES = # local files headers = bfrops.h bfrops_types.h sources = # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.include libmca_bfrops_la_SOURCES += $(headers) $(sources) distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/bfrops/v12/0000775000175000017500000000000015203536752016727 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/bfrops/v12/unpack.c0000664000175000017500000013146115203536752020362 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "bfrop_v12.h" #include "internal.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" pmix_status_t pmix12_bfrop_unpack(pmix_buffer_t *buffer, void *dst, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t rc, ret; int32_t local_num, n = 1; pmix_data_type_t local_type; pmix_pointer_array_t *regtypes = &pmix_mca_bfrops_v12_component.types; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: for type %d", (int) type); /* check for error */ if (NULL == buffer || NULL == dst || NULL == num_vals) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* if user provides a zero for num_vals, then there is no storage allocated * so return an appropriate error */ if (0 == *num_vals) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: inadequate space ( %p, %p, %lu, %d )\n", (void *) buffer, dst, (long unsigned int) *num_vals, (int) type); PMIX_ERROR_LOG(PMIX_ERR_UNPACK_INADEQUATE_SPACE); return PMIX_ERR_UNPACK_INADEQUATE_SPACE; } /** Unpack the declared number of values * REMINDER: it is possible that the buffer is corrupted and that * the BFROP will *think* there is a proper int32_t variable at the * beginning of the unpack region - but that the value is bogus (e.g., just * a byte field in a string array that so happens to have a value that * matches the int32_t data type flag). Therefore, this error check is * NOT completely safe. This is true for ALL unpack functions, not just * int32_t as used here. */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix12_bfrop_get_data_type(regtypes, buffer, &local_type))) { *num_vals = 0; /* don't error log here as the user may be unpacking past * the end of the buffer, which isn't necessarily an error */ return rc; } if (PMIX_INT32 != local_type) { /* if the length wasn't first, then error */ *num_vals = 0; PMIX_ERROR_LOG(PMIX_ERR_UNPACK_FAILURE); return PMIX_ERR_UNPACK_FAILURE; } } n = 1; if (PMIX_SUCCESS != (rc = pmix12_bfrop_unpack_int32(regtypes, buffer, &local_num, &n, PMIX_INT32))) { *num_vals = 0; /* don't error log here as the user may be unpacking past * the end of the buffer, which isn't necessarily an error */ return rc; } pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: found %d values for %d provided storage", local_num, *num_vals); /** if the storage provided is inadequate, set things up * to unpack as much as we can and to return an error code * indicating that everything was not unpacked - the buffer * is left in a state where it can not be further unpacked. */ if (local_num > *num_vals) { local_num = *num_vals; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: inadequate space ( %p, %p, %lu, %d )\n", (void *) buffer, dst, (long unsigned int) *num_vals, (int) type); ret = PMIX_ERR_UNPACK_INADEQUATE_SPACE; } else { /** enough or more than enough storage */ *num_vals = local_num; /** let the user know how many we actually unpacked */ ret = PMIX_SUCCESS; } /** Unpack the value(s) */ if (PMIX_SUCCESS != (rc = pmix12_bfrop_unpack_buffer(regtypes, buffer, dst, &local_num, type))) { PMIX_ERROR_LOG(rc); *num_vals = 0; ret = rc; } return ret; } pmix_status_t pmix12_bfrop_unpack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dst, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t rc; pmix_data_type_t local_type, v1type; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack_buffer( %p, %p, %lu, %d )\n", (void *) buffer, dst, (long unsigned int) *num_vals, (int) type); /* some v1 types are simply declared differently */ switch (type) { case PMIX_COMMAND: v1type = PMIX_UINT32; break; case PMIX_SCOPE: case PMIX_DATA_RANGE: v1type = PMIX_UINT; break; case PMIX_PROC_RANK: case PMIX_PERSIST: case PMIX_STATUS: v1type = PMIX_INT; break; default: v1type = type; } /** Unpack the declared data type */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix12_bfrop_get_data_type(regtypes, buffer, &local_type))) { PMIX_ERROR_LOG(rc); return rc; } /* if the data types don't match, then return an error */ if (v1type != local_type) { pmix_output_verbose(1, pmix_bfrops_base_framework.framework_output, "PMIX bfrop:unpack: got type %d when expecting type %d", local_type, v1type); return PMIX_ERR_PACK_MISMATCH; } } PMIX_BFROPS_UNPACK_TYPE(rc, buffer, dst, num_vals, v1type, regtypes); return rc; } /* UNPACK GENERIC SYSTEM TYPES */ /* * BOOL */ pmix_status_t pmix12_bfrop_unpack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint8_t *src; bool *dst; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack_bool * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, *num_vals)) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ src = (uint8_t *) buffer->unpack_ptr; dst = (bool *) dest; for (i = 0; i < *num_vals; i++) { if (src[i]) { dst[i] = true; } else { dst[i] = false; } } /* update buffer pointer */ buffer->unpack_ptr += *num_vals; return PMIX_SUCCESS; } /* * INT */ pmix_status_t pmix12_bfrop_unpack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix12_bfrop_get_data_type(regtypes, buffer, &remote_type))) { return ret; } if (remote_type == BFROP_TYPE_INT) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, dest, num_vals, BFROP_TYPE_INT))) { } } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, int, remote_type, ret); } return ret; } /* * SIZE_T */ pmix_status_t pmix12_bfrop_unpack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix12_bfrop_get_data_type(regtypes, buffer, &remote_type))) { return ret; } if (remote_type == BFROP_TYPE_SIZE_T) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, dest, num_vals, BFROP_TYPE_SIZE_T))) { } } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, size_t, remote_type, ret); } return ret; } /* * PID_T */ pmix_status_t pmix12_bfrop_unpack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; pmix_data_type_t remote_type; PMIX_HIDE_UNUSED_PARAMS(type); if (PMIX_SUCCESS != (ret = pmix12_bfrop_get_data_type(regtypes, buffer, &remote_type))) { return ret; } if (remote_type == BFROP_TYPE_PID_T) { /* fast path it if the sizes are the same */ /* Turn around and unpack the real type */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, dest, num_vals, BFROP_TYPE_PID_T))) { } } else { /* slow path - types are different sizes */ PMIX_BFROP_UNPACK_SIZE_MISMATCH(regtypes, pid_t, remote_type, ret); } return ret; } /* UNPACK FUNCTIONS FOR NON-GENERIC SYSTEM TYPES */ /* * BYTE, CHAR, INT8 */ pmix_status_t pmix12_bfrop_unpack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack_byte * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, *num_vals)) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ memcpy(dest, buffer->unpack_ptr, *num_vals); /* update buffer pointer */ buffer->unpack_ptr += *num_vals; return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint16_t tmp, *desttmp = (uint16_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack_int16 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = pmix_ntohs(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint32_t tmp, *desttmp = (uint32_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack_int32 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = ntohl(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { return pmix12_bfrop_unpack_int32(regtypes, buffer, dest, num_vals, type); } pmix_status_t pmix12_bfrop_unpack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i; uint64_t tmp, *desttmp = (uint64_t *) dest; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack_int64 * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(tmp))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { memcpy(&(tmp), buffer->unpack_ptr, sizeof(tmp)); tmp = pmix_ntoh64(tmp); memcpy(&desttmp[i], &tmp, sizeof(tmp)); buffer->unpack_ptr += sizeof(tmp); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_status_t ret; int32_t i, len, n = 1; char **sdest = (char **) dest; PMIX_HIDE_UNUSED_PARAMS(type); for (i = 0; i < (*num_vals); ++i) { if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_int32(regtypes, buffer, &len, &n, PMIX_INT32))) { return ret; } if (0 == len) { /* zero-length string - unpack the NULL */ sdest[i] = NULL; } else if (PMIX_TAINT_INT_LIMIT < len) { // arbitrary value to guard against tainted input return PMIX_ERR_BAD_PARAM; } else { sdest[i] = (char *) malloc(len); if (NULL == sdest[i]) { return PMIX_ERR_OUT_OF_RESOURCE; } if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_byte(regtypes, buffer, sdest[i], &len, PMIX_BYTE))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; float *desttmp = (float *) dest, tmp; pmix_status_t ret; char *convert; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack_float * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(float))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 1; convert = NULL; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_string(regtypes, buffer, &convert, &n, PMIX_STRING))) { if (NULL != convert) { free(convert); } return ret; } if (NULL != convert) { tmp = strtof(convert, NULL); memcpy(&desttmp[i], &tmp, sizeof(tmp)); free(convert); } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; double *desttmp = (double *) dest, tmp; pmix_status_t ret; char *convert; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack_double * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(double))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 1; convert = NULL; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_string(regtypes, buffer, &convert, &n, PMIX_STRING))) { if (NULL != convert) { free(convert); } return ret; } if (NULL != convert) { tmp = strtod(convert, NULL); memcpy(&desttmp[i], &tmp, sizeof(tmp)); free(convert); } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; int64_t tmp[2]; struct timeval *desttmp = (struct timeval *) dest, tt; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack_timeval * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * sizeof(struct timeval))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 2; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_int64(regtypes, buffer, tmp, &n, PMIX_INT64))) { return ret; } tt.tv_sec = tmp[0]; tt.tv_usec = tmp[1]; memcpy(&desttmp[i], &tt, sizeof(tt)); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { int32_t i, n; time_t *desttmp = (time_t *) dest, tmp; pmix_status_t ret; uint64_t ui64; /* time_t is a system-dependent size, so cast it * to uint64_t as a generic safe size */ pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack_time * %d\n", (int) *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); /* check to see if there's enough data in buffer */ if (pmix_bfrop_too_small(buffer, (*num_vals) * (sizeof(uint64_t)))) { return PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER; } /* unpack the data */ for (i = 0; i < (*num_vals); ++i) { n = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_int64(regtypes, buffer, &ui64, &n, PMIX_UINT64))) { return ret; } tmp = (time_t) ui64; memcpy(&desttmp[i], &tmp, sizeof(tmp)); } return PMIX_SUCCESS; } /* UNPACK FUNCTIONS FOR GENERIC PMIX TYPES */ /* * PMIX_VALUE */ static pmix_status_t unpack_val(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_value_t *val) { int32_t m; pmix_status_t ret; m = 1; switch (val->type) { case PMIX_BOOL: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.flag, &m, PMIX_BOOL))) { return ret; } break; case PMIX_BYTE: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.byte, &m, PMIX_BYTE))) { return ret; } break; case PMIX_STRING: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.string, &m, PMIX_STRING))) { return ret; } break; case PMIX_SIZE: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.size, &m, PMIX_SIZE))) { return ret; } break; case PMIX_PID: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.pid, &m, PMIX_PID))) { return ret; } break; case PMIX_INT: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.integer, &m, PMIX_INT))) { return ret; } break; case PMIX_INT8: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.int8, &m, PMIX_INT8))) { return ret; } break; case PMIX_INT16: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.int16, &m, PMIX_INT16))) { return ret; } break; case PMIX_INT32: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.int32, &m, PMIX_INT32))) { return ret; } break; case PMIX_INT64: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.int64, &m, PMIX_INT64))) { return ret; } break; case PMIX_UINT: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.uint, &m, PMIX_UINT))) { return ret; } break; case PMIX_UINT8: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.uint8, &m, PMIX_UINT8))) { return ret; } break; case PMIX_UINT16: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.uint16, &m, PMIX_UINT16))) { return ret; } break; case PMIX_UINT32: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.uint32, &m, PMIX_UINT32))) { return ret; } break; case PMIX_UINT64: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.uint64, &m, PMIX_UINT64))) { return ret; } break; case PMIX_FLOAT: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.fval, &m, PMIX_FLOAT))) { return ret; } break; case PMIX_DOUBLE: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.dval, &m, PMIX_DOUBLE))) { return ret; } break; case PMIX_TIMEVAL: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.tv, &m, PMIX_TIMEVAL))) { return ret; } break; case PMIX_INFO_ARRAY: /* we don't know anything about info array's so we * have to convert this to a data array */ val->data.darray = (pmix_data_array_t *) calloc(1, sizeof(pmix_data_array_t)); val->data.darray->type = PMIX_INFO_ARRAY; val->data.darray->size = m; /* unpack into it */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.darray->array, &m, PMIX_INFO_ARRAY))) { return ret; } break; case PMIX_BYTE_OBJECT: if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_buffer(regtypes, buffer, &val->data.bo, &m, PMIX_BYTE_OBJECT))) { return ret; } break; default: pmix_output(0, "UNPACK-PMIX-VALUE: UNSUPPORTED TYPE"); return PMIX_ERROR; } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_value_t *ptr; int32_t i, m, n; pmix_status_t ret; int v1type; PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_value_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { /* unpack the type */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_int(regtypes, buffer, &v1type, &m, PMIX_INT))) { return ret; } /* convert the type - unfortunately, v1.2 directly packed the int instead of * using the store_data_type function. This means we lose the translation! * So get it here */ ptr[i].type = pmix12_v1_to_v2_datatype(v1type); /* unpack value */ if (PMIX_SUCCESS != (ret = unpack_val(regtypes, buffer, &ptr[i]))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_info_t *ptr; int32_t i, n, m; pmix_status_t ret; char *tmp; int v1type; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: %d info", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_info_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { memset(ptr[i].key, 0, sizeof(ptr[i].key)); memset(&ptr[i].value, 0, sizeof(pmix_value_t)); /* unpack key */ m = 1; tmp = NULL; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_string(regtypes, buffer, &tmp, &m, PMIX_STRING))) { if (NULL != tmp) { free(tmp); } return ret; } if (NULL == tmp) { return PMIX_ERROR; } pmix_strncpy(ptr[i].key, tmp, PMIX_MAX_KEYLEN); free(tmp); /* unpack value - since the value structure is statically-defined * instead of a pointer in this struct, we directly unpack it to * avoid the malloc */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_int(regtypes, buffer, &v1type, &m, PMIX_INT))) { return ret; } /* convert the type - unfortunately, v1.2 directly packed the int instead of * using the store_data_type function. This means we lose the translation! * So get it here */ ptr[i].value.type = pmix12_v1_to_v2_datatype(v1type); pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: info type %d", ptr[i].value.type); m = 1; if (PMIX_SUCCESS != (ret = unpack_val(regtypes, buffer, &ptr[i].value))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_pdata_t *ptr; int32_t i, n, m; pmix_status_t ret; char *tmp; int v1type; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: %d pdata", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_pdata_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_PDATA_CONSTRUCT(&ptr[i]); /* unpack the proc */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_proc(regtypes, buffer, &ptr[i].proc, &m, PMIX_PROC))) { return ret; } /* unpack key */ m = 1; tmp = NULL; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_string(regtypes, buffer, &tmp, &m, PMIX_STRING))) { if (NULL != tmp) { free(tmp); } return ret; } if (NULL == tmp) { return PMIX_ERROR; } pmix_strncpy(ptr[i].key, tmp, PMIX_MAX_KEYLEN); free(tmp); /* unpack value - since the value structure is statically-defined * instead of a pointer in this struct, we directly unpack it to * avoid the malloc */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_int(regtypes, buffer, &v1type, &m, PMIX_INT))) { return ret; } /* convert the type - unfortunately, v1.2 directly packed the int instead of * using the store_data_type function. This means we lose the translation! * So get it here */ ptr[i].value.type = pmix12_v1_to_v2_datatype(v1type); pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: pdata type %d", ptr[i].value.type); m = 1; if (PMIX_SUCCESS != (ret = unpack_val(regtypes, buffer, &ptr[i].value))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_buffer_t *ptr; int32_t i, n, m; pmix_status_t ret; size_t nbytes; PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_buffer_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { /* unpack the number of bytes */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_sizet(regtypes, buffer, &nbytes, &m, PMIX_SIZE))) { return ret; } m = nbytes; /* setup the buffer's data region */ if (0 < nbytes) { ptr[i].base_ptr = (char *) malloc(nbytes); /* unpack the bytes */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_byte(regtypes, buffer, ptr[i].base_ptr, &m, PMIX_BYTE))) { return ret; } } ptr[i].pack_ptr = ptr[i].base_ptr + m; ptr[i].unpack_ptr = ptr[i].base_ptr; ptr[i].bytes_allocated = nbytes; ptr[i].bytes_used = m; } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_proc_t *ptr; int32_t i, n, m; pmix_status_t ret; char *tmp; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: %d procs", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_proc_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: init proc[%d]", i); memset(&ptr[i], 0, sizeof(pmix_proc_t)); /* unpack nspace */ m = 1; tmp = NULL; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_string(regtypes, buffer, &tmp, &m, PMIX_STRING))) { if (NULL != tmp) { free(tmp); } return ret; } if (NULL == tmp) { return PMIX_ERROR; } pmix_strncpy(ptr[i].nspace, tmp, PMIX_MAX_NSLEN); free(tmp); /* unpack the rank */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_int(regtypes, buffer, &ptr[i].rank, &m, PMIX_INT))) { return ret; } /* we have to do some conversion here as the definition of rank * changed from INT32 to UINT32 */ if (INT32_MAX == ptr[i].rank) { ptr[i].rank = PMIX_RANK_UNDEF; } else if (INT32_MAX - 1 == ptr[i].rank) { ptr[i].rank = PMIX_RANK_WILDCARD; } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_app_t *ptr; int32_t i, k, n, m; pmix_status_t ret; int32_t nval; char *tmp; int argc; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: %d apps", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_app_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { /* initialize the fields */ PMIX_APP_CONSTRUCT(&ptr[i]); /* unpack cmd */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_string(regtypes, buffer, &ptr[i].cmd, &m, PMIX_STRING))) { return ret; } /* unpack argc */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_int(regtypes, buffer, &argc, &m, PMIX_INT))) { return ret; } /* unpack argv */ for (k = 0; k < argc; k++) { m = 1; tmp = NULL; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_string(regtypes, buffer, &tmp, &m, PMIX_STRING))) { if (NULL != tmp) { free(tmp); } return ret; } if (NULL == tmp) { return PMIX_ERROR; } PMIx_Argv_append_nosize(&ptr[i].argv, tmp); free(tmp); } /* unpack env */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_int32(regtypes, buffer, &nval, &m, PMIX_INT32))) { return ret; } if (PMIX_TAINT_INT_LIMIT < nval) { // arbitrary value to guard against tainted input return PMIX_ERR_BAD_PARAM; } for (k = 0; k < nval; k++) { m = 1; tmp = NULL; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_string(regtypes, buffer, &tmp, &m, PMIX_STRING))) { if (NULL != tmp) { free(tmp); } return ret; } if (NULL == tmp) { return PMIX_ERROR; } PMIx_Argv_append_nosize(&ptr[i].env, tmp); free(tmp); } /* unpack maxprocs */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_int(regtypes, buffer, &ptr[i].maxprocs, &m, PMIX_INT))) { return ret; } /* unpack info array */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_sizet(regtypes, buffer, &ptr[i].ninfo, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].ninfo) { PMIX_INFO_CREATE(ptr[i].info, ptr[i].ninfo); m = ptr[i].ninfo; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_info(regtypes, buffer, ptr[i].info, &m, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_kval_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: %d kvals", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_kval_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { PMIX_CONSTRUCT(&ptr[i], pmix_kval_t); /* unpack the key */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_string(regtypes, buffer, &ptr[i].key, &m, PMIX_STRING))) { PMIX_ERROR_LOG(ret); return ret; } /* allocate the space */ ptr[i].value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); /* unpack the value */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_value(regtypes, buffer, ptr[i].value, &m, PMIX_VALUE))) { PMIX_ERROR_LOG(ret); return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_info_array_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: %d info arrays", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_info_array_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: init array[%d]", i); memset(&ptr[i], 0, sizeof(pmix_info_array_t)); /* unpack the size of this array */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { ptr[i].array = (pmix_info_t *) malloc(ptr[i].size * sizeof(pmix_info_t)); m = ptr[i].size; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_value(regtypes, buffer, ptr[i].array, &m, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_modex_data_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: %d modex", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_modex_data_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { memset(&ptr[i], 0, sizeof(pmix_modex_data_t)); /* unpack the number of bytes */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { ptr[i].blob = (uint8_t *) malloc(ptr[i].size * sizeof(uint8_t)); m = ptr[i].size; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_byte(regtypes, buffer, ptr[i].blob, &m, PMIX_UINT8))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); return pmix12_bfrop_unpack_int(regtypes, buffer, dest, num_vals, PMIX_INT); } pmix_status_t pmix12_bfrop_unpack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { pmix_byte_object_t *ptr; int32_t i, n, m; pmix_status_t ret; pmix_output_verbose(20, pmix_bfrops_base_framework.framework_output, "pmix12_bfrop_unpack: %d byte_object", *num_vals); PMIX_HIDE_UNUSED_PARAMS(type); ptr = (pmix_byte_object_t *) dest; n = *num_vals; for (i = 0; i < n; ++i) { memset(&ptr[i], 0, sizeof(pmix_byte_object_t)); /* unpack the number of bytes */ m = 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_sizet(regtypes, buffer, &ptr[i].size, &m, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { ptr[i].bytes = (char *) malloc(ptr[i].size * sizeof(char)); m = ptr[i].size; if (PMIX_SUCCESS != (ret = pmix12_bfrop_unpack_byte(regtypes, buffer, ptr[i].bytes, &m, PMIX_BYTE))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_unpack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_unpack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_unpack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_unpack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_unpack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_unpack_info_directives(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_unpack_proc_state(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_unpack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_unpack_proc_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_unpack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_unpack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, dest, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix-6.1.1~rc2/src/mca/bfrops/v12/copy.c0000664000175000017500000003477215203536752020062 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "bfrop_v12.h" #include "internal.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" pmix_status_t pmix12_bfrop_copy(void **dest, void *src, pmix_data_type_t type) { pmix_bfrop_type_info_t *info; /* check for error */ if (NULL == dest) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } if (NULL == src) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* Lookup the copy function for this type and call it */ if (NULL == (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v12_component.types, type))) { PMIX_ERROR_LOG(PMIX_ERR_UNKNOWN_DATA_TYPE); return PMIX_ERR_UNKNOWN_DATA_TYPE; } return info->odti_copy_fn(dest, src, type); } pmix_status_t pmix12_bfrop_copy_payload(pmix_buffer_t *dest, pmix_buffer_t *src) { size_t to_copy = 0; char *ptr; /* deal with buffer type */ if (NULL == dest->base_ptr) { /* destination buffer is empty - derive src buffer type */ dest->type = src->type; } else if (dest->type != src->type) { /* buffer types mismatch */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } to_copy = src->pack_ptr - src->unpack_ptr; if (NULL == (ptr = pmix_bfrop_buffer_extend(dest, to_copy))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return PMIX_ERR_OUT_OF_RESOURCE; } memcpy(ptr, src->unpack_ptr, to_copy); dest->bytes_used += to_copy; dest->pack_ptr += to_copy; return PMIX_SUCCESS; } /* * STANDARD COPY FUNCTION - WORKS FOR EVERYTHING NON-STRUCTURED */ pmix_status_t pmix12_bfrop_std_copy(void **dest, void *src, pmix_data_type_t type) { size_t datasize; uint8_t *val = NULL; switch (type) { case PMIX_BOOL: datasize = sizeof(bool); break; case PMIX_INT: case PMIX_UINT: datasize = sizeof(int); break; case PMIX_SIZE: datasize = sizeof(size_t); break; case PMIX_PID: datasize = sizeof(pid_t); break; case PMIX_BYTE: case PMIX_INT8: case PMIX_UINT8: datasize = 1; break; case PMIX_INT16: case PMIX_UINT16: datasize = 2; break; case PMIX_INT32: case PMIX_UINT32: datasize = 4; break; case PMIX_INT64: case PMIX_UINT64: datasize = 8; break; case PMIX_FLOAT: datasize = sizeof(float); break; case PMIX_TIMEVAL: datasize = sizeof(struct timeval); break; case PMIX_TIME: datasize = sizeof(time_t); break; default: return PMIX_ERR_UNKNOWN_DATA_TYPE; } val = (uint8_t *) malloc(datasize); if (NULL == val) { return PMIX_ERR_OUT_OF_RESOURCE; } memcpy(val, src, datasize); *dest = val; return PMIX_SUCCESS; } /* COPY FUNCTIONS FOR NON-STANDARD SYSTEM TYPES */ /* * STRING */ pmix_status_t pmix12_bfrop_copy_string(char **dest, char *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); if (NULL == src) { /* got zero-length string/NULL pointer - store NULL */ *dest = NULL; } else { *dest = strdup(src); } return PMIX_SUCCESS; } /* compare function for pmix_value_t*/ pmix_value_cmp_t pmix12_bfrop_value_cmp(pmix_value_t *p, pmix_value_t *p1) { bool rc = false; switch (p->type) { case PMIX_BOOL: rc = (p->data.flag == p1->data.flag); break; case PMIX_BYTE: rc = (p->data.byte == p1->data.byte); break; case PMIX_SIZE: rc = (p->data.size == p1->data.size); break; case PMIX_INT: rc = (p->data.integer == p1->data.integer); break; case PMIX_INT8: rc = (p->data.int8 == p1->data.int8); break; case PMIX_INT16: rc = (p->data.int16 == p1->data.int16); break; case PMIX_INT32: rc = (p->data.int32 == p1->data.int32); break; case PMIX_INT64: rc = (p->data.int64 == p1->data.int64); break; case PMIX_UINT: rc = (p->data.uint == p1->data.uint); break; case PMIX_UINT8: rc = (p->data.uint8 == p1->data.int8); break; case PMIX_UINT16: rc = (p->data.uint16 == p1->data.uint16); break; case PMIX_UINT32: rc = (p->data.uint32 == p1->data.uint32); break; case PMIX_UINT64: rc = (p->data.uint64 == p1->data.uint64); break; case PMIX_STRING: rc = strcmp(p->data.string, p1->data.string); break; default: pmix_output(0, "COMPARE-PMIX-VALUE: UNSUPPORTED TYPE %d", (int) p->type); } if (rc) { return PMIX_EQUAL; } return PMIX_VALUE1_GREATER; } /* COPY FUNCTIONS FOR GENERIC PMIX TYPES */ pmix_status_t pmix12_bfrop_value_xfer(pmix_value_t *p, const pmix_value_t *src) { /* copy the right field */ p->type = src->type; switch (src->type) { case PMIX_BOOL: p->data.flag = src->data.flag; break; case PMIX_BYTE: p->data.byte = src->data.byte; break; case PMIX_STRING: if (NULL != src->data.string) { p->data.string = strdup(src->data.string); } else { p->data.string = NULL; } break; case PMIX_SIZE: p->data.size = src->data.size; break; case PMIX_PID: p->data.pid = src->data.pid; break; case PMIX_INT: /* to avoid alignment issues */ memcpy(&p->data.integer, &src->data.integer, sizeof(int)); break; case PMIX_INT8: p->data.int8 = src->data.int8; break; case PMIX_INT16: /* to avoid alignment issues */ memcpy(&p->data.int16, &src->data.int16, 2); break; case PMIX_INT32: /* to avoid alignment issues */ memcpy(&p->data.int32, &src->data.int32, 4); break; case PMIX_INT64: /* to avoid alignment issues */ memcpy(&p->data.int64, &src->data.int64, 8); break; case PMIX_UINT: /* to avoid alignment issues */ memcpy(&p->data.uint, &src->data.uint, sizeof(unsigned int)); break; case PMIX_UINT8: p->data.uint8 = src->data.uint8; break; case PMIX_UINT16: /* to avoid alignment issues */ memcpy(&p->data.uint16, &src->data.uint16, 2); break; case PMIX_UINT32: /* to avoid alignment issues */ memcpy(&p->data.uint32, &src->data.uint32, 4); break; case PMIX_UINT64: /* to avoid alignment issues */ memcpy(&p->data.uint64, &src->data.uint64, 8); break; case PMIX_FLOAT: p->data.fval = src->data.fval; break; case PMIX_DOUBLE: p->data.dval = src->data.dval; break; case PMIX_TIMEVAL: p->data.tv.tv_sec = src->data.tv.tv_sec; p->data.tv.tv_usec = src->data.tv.tv_usec; break; case PMIX_INFO_ARRAY: return PMIX_ERR_NOT_SUPPORTED; case PMIX_BYTE_OBJECT: if (NULL != src->data.bo.bytes && 0 < src->data.bo.size) { p->data.bo.bytes = malloc(src->data.bo.size); memcpy(p->data.bo.bytes, src->data.bo.bytes, src->data.bo.size); p->data.bo.size = src->data.bo.size; } else { p->data.bo.bytes = NULL; p->data.bo.size = 0; } break; default: pmix_output(0, "COPY-PMIX-VALUE: UNSUPPORTED TYPE %d", (int) src->type); return PMIX_ERROR; } return PMIX_SUCCESS; } /* PMIX_VALUE */ pmix_status_t pmix12_bfrop_copy_value(pmix_value_t **dest, pmix_value_t *src, pmix_data_type_t type) { pmix_value_t *p; PMIX_HIDE_UNUSED_PARAMS(type); /* create the new object */ *dest = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } p = *dest; /* copy the type */ p->type = src->type; /* copy the data */ return PMIx_Value_xfer(p, src); } pmix_status_t pmix12_bfrop_copy_info(pmix_info_t **dest, pmix_info_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_info_t *) malloc(sizeof(pmix_info_t)); pmix_strncpy((*dest)->key, src->key, PMIX_MAX_KEYLEN); return PMIx_Value_xfer(&(*dest)->value, &src->value); } pmix_status_t pmix12_bfrop_copy_buf(pmix_buffer_t **dest, pmix_buffer_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = PMIX_NEW(pmix_buffer_t); pmix_bfrops_base_copy_payload(*dest, src); return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_copy_app(pmix_app_t **dest, pmix_app_t *src, pmix_data_type_t type) { size_t j; PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_app_t *) malloc(sizeof(pmix_app_t)); (*dest)->cmd = strdup(src->cmd); (*dest)->argv = PMIx_Argv_copy(src->argv); (*dest)->env = PMIx_Argv_copy(src->env); (*dest)->maxprocs = src->maxprocs; (*dest)->ninfo = src->ninfo; (*dest)->info = (pmix_info_t *) malloc(src->ninfo * sizeof(pmix_info_t)); for (j = 0; j < src->ninfo; j++) { pmix_strncpy((*dest)->info[j].key, src->info[j].key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&(*dest)->info[j].value, &src->info[j].value); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_copy_kval(pmix_kval_t **dest, pmix_kval_t *src, pmix_data_type_t type) { pmix_kval_t *p; PMIX_HIDE_UNUSED_PARAMS(type); /* create the new object */ *dest = PMIX_NEW(pmix_kval_t); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } p = *dest; /* copy the type */ p->value->type = src->value->type; /* copy the data */ return PMIx_Value_xfer(p->value, src->value); } pmix_status_t pmix12_bfrop_copy_array(pmix_info_array_t **dest, pmix_info_array_t *src, pmix_data_type_t type) { pmix_info_t *d1, *s1; PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_info_array_t *) malloc(sizeof(pmix_info_array_t)); (*dest)->size = src->size; (*dest)->array = (pmix_info_t *) malloc(src->size * sizeof(pmix_info_t)); d1 = (pmix_info_t *) (*dest)->array; s1 = (pmix_info_t *) src->array; memcpy(d1, s1, src->size * sizeof(pmix_info_t)); return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_copy_proc(pmix_proc_t **dest, pmix_proc_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_proc_t *) malloc(sizeof(pmix_proc_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } pmix_strncpy((*dest)->nspace, src->nspace, PMIX_MAX_NSLEN); (*dest)->rank = src->rank; return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_copy_modex(pmix_modex_data_t **dest, pmix_modex_data_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_modex_data_t *) malloc(sizeof(pmix_modex_data_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } (*dest)->blob = NULL; (*dest)->size = 0; if (NULL != src->blob) { (*dest)->blob = (uint8_t *) malloc(src->size * sizeof(uint8_t)); if (NULL == (*dest)->blob) { return PMIX_ERR_OUT_OF_RESOURCE; } memcpy((*dest)->blob, src->blob, src->size * sizeof(uint8_t)); (*dest)->size = src->size; } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_copy_persist(pmix_persistence_t **dest, pmix_persistence_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_persistence_t *) malloc(sizeof(pmix_persistence_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } memcpy(*dest, src, sizeof(pmix_persistence_t)); return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_copy_bo(pmix_byte_object_t **dest, pmix_byte_object_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_byte_object_t *) malloc(sizeof(pmix_byte_object_t)); if (NULL == *dest) { return PMIX_ERR_OUT_OF_RESOURCE; } (*dest)->bytes = (char *) malloc(src->size); memcpy((*dest)->bytes, src->bytes, src->size); (*dest)->size = src->size; return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_copy_pdata(pmix_pdata_t **dest, pmix_pdata_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(type); *dest = (pmix_pdata_t *) malloc(sizeof(pmix_pdata_t)); pmix_strncpy((*dest)->proc.nspace, src->proc.nspace, PMIX_MAX_NSLEN); (*dest)->proc.rank = src->proc.rank; pmix_strncpy((*dest)->key, src->key, PMIX_MAX_KEYLEN); return PMIx_Value_xfer(&(*dest)->value, &src->value); } pmix_status_t pmix12_bfrop_copy_darray(pmix_pdata_t **dest, pmix_data_array_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(dest, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_copy_proc_info(pmix_pdata_t **dest, pmix_proc_info_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(dest, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_copy_query(pmix_pdata_t **dest, pmix_query_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(dest, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix-6.1.1~rc2/src/mca/bfrops/v12/internal.h0000664000175000017500000006547015203536752020730 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX1_BFROP_INTERNAL_H_ #define PMIX1_BFROP_INTERNAL_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_pointer_array.h" #include "src/mca/bfrops/base/base.h" BEGIN_C_DECLS /* DEPRECATED data type values */ #define PMIX_MODEX 29 #define PMIX_INFO_ARRAY 44 /**** PMIX MODEX STRUCT - DEPRECATED ****/ typedef struct pmix_modex_data { char nspace[PMIX_MAX_NSLEN + 1]; int rank; uint8_t *blob; size_t size; } pmix_modex_data_t; /* utility macros for working with pmix_modex_t structs */ #define PMIX_MODEX_CREATE(m, n) \ do { \ (m) = (pmix_modex_data_t *) calloc((n), sizeof(pmix_modex_data_t)); \ } while (0) #define PMIX_MODEX_RELEASE(m) \ do { \ PMIX_MODEX_DESTRUCT((m)); \ free((m)); \ (m) = NULL; \ } while (0) #define PMIX_MODEX_CONSTRUCT(m) \ do { \ memset((m), 0, sizeof(pmix_modex_data_t)); \ } while (0) #define PMIX_MODEX_DESTRUCT(m) \ do { \ if (NULL != (m)->blob) { \ free((m)->blob); \ (m)->blob = NULL; \ } \ } while (0) #define PMIX_MODEX_FREE(m, n) \ do { \ size_t _s; \ if (NULL != (m)) { \ for (_s = 0; _s < (n); _s++) { \ PMIX_MODEX_DESTRUCT(&((m)[_s])); \ } \ free((m)); \ (m) = NULL; \ } \ } while (0) /* * Implementations of API functions */ pmix_status_t pmix12_bfrop_pack(pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack(pmix_buffer_t *buffer, void *dest, int32_t *max_num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy(void **dest, void *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print(char **output, char *prefix, void *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_payload(pmix_buffer_t *dest, pmix_buffer_t *src); pmix_status_t pmix12_bfrop_value_xfer(pmix_value_t *p, const pmix_value_t *src); void pmix12_bfrop_value_load(pmix_value_t *v, const void *data, pmix_data_type_t type); pmix_status_t pmix12_bfrop_value_unload(pmix_value_t *kv, void **data, size_t *sz); pmix_value_cmp_t pmix12_bfrop_value_cmp(pmix_value_t *p, pmix_value_t *p1); /* * Specialized functions */ pmix_status_t pmix12_bfrop_pack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dst, int32_t *num_vals, pmix_data_type_t type); /* * Internal pack functions */ pmix_status_t pmix12_bfrop_pack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); /* compatibility functions - no corresponding PMIx v1.x definitions */ pmix_status_t pmix12_bfrop_pack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_info_directives(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_proc_state(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_proc_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_pack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type); /* * Internal unpack functions */ pmix_status_t pmix12_bfrop_unpack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); /* compatibility functions - no corresponding PMIx v1.x definitions */ pmix_status_t pmix12_bfrop_unpack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_info_directives(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_proc_state(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_proc_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); pmix_status_t pmix12_bfrop_unpack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, void *dest, int32_t *num_vals, pmix_data_type_t type); /* * Internal copy functions */ pmix_status_t pmix12_bfrop_std_copy(void **dest, void *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_string(char **dest, char *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_value(pmix_value_t **dest, pmix_value_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_array(pmix_info_array_t **dest, pmix_info_array_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_proc(pmix_proc_t **dest, pmix_proc_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_app(pmix_app_t **dest, pmix_app_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_info(pmix_info_t **dest, pmix_info_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_buf(pmix_buffer_t **dest, pmix_buffer_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_kval(pmix_kval_t **dest, pmix_kval_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_modex(pmix_modex_data_t **dest, pmix_modex_data_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_persist(pmix_persistence_t **dest, pmix_persistence_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_bo(pmix_byte_object_t **dest, pmix_byte_object_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_pdata(pmix_pdata_t **dest, pmix_pdata_t *src, pmix_data_type_t type); /* compatibility functions - no corresponding PMIx v1.x definitions */ pmix_status_t pmix12_bfrop_copy_darray(pmix_pdata_t **dest, pmix_data_array_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_proc_info(pmix_pdata_t **dest, pmix_proc_info_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_copy_query(pmix_pdata_t **dest, pmix_query_t *src, pmix_data_type_t type); /* * Internal print functions */ pmix_status_t pmix12_bfrop_print_bool(char **output, char *prefix, bool *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_byte(char **output, char *prefix, uint8_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_string(char **output, char *prefix, char *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_size(char **output, char *prefix, size_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_pid(char **output, char *prefix, pid_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_int(char **output, char *prefix, int *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_int8(char **output, char *prefix, int8_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_int16(char **output, char *prefix, int16_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_int32(char **output, char *prefix, int32_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_int64(char **output, char *prefix, int64_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_uint(char **output, char *prefix, uint *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_uint8(char **output, char *prefix, uint8_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_uint16(char **output, char *prefix, uint16_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_uint32(char **output, char *prefix, uint32_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_uint64(char **output, char *prefix, uint64_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_float(char **output, char *prefix, float *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_double(char **output, char *prefix, double *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_timeval(char **output, char *prefix, struct timeval *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_time(char **output, char *prefix, time_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_value(char **output, char *prefix, pmix_value_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_array(char **output, char *prefix, pmix_info_array_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_proc(char **output, char *prefix, pmix_proc_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_app(char **output, char *prefix, pmix_app_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_info(char **output, char *prefix, pmix_info_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_buf(char **output, char *prefix, pmix_buffer_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_kval(char **output, char *prefix, pmix_kval_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_modex(char **output, char *prefix, pmix_modex_data_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_persist(char **output, char *prefix, pmix_persistence_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_bo(char **output, char *prefix, pmix_byte_object_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_pdata(char **output, char *prefix, pmix_pdata_t *src, pmix_data_type_t type); /* compatibility functions - no corresponding PMIx v1.x definitions */ pmix_status_t pmix12_bfrop_print_scope(char **output, char *prefix, pmix_scope_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_status(char **output, char *prefix, pmix_status_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_ptr(char **output, char *prefix, void *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_cmd(char **output, char *prefix, void *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_info_directives(char **output, char *prefix, void *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_datatype(char **output, char *prefix, pmix_data_type_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_proc_state(char **output, char *prefix, pmix_data_type_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_darray(char **output, char *prefix, pmix_data_array_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_proc_info(char **output, char *prefix, pmix_proc_info_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_query(char **output, char *prefix, pmix_query_t *src, pmix_data_type_t type); pmix_status_t pmix12_bfrop_print_rank(char **output, char *prefix, pmix_rank_t *src, pmix_data_type_t type); /* * Internal helper functions */ pmix_status_t pmix12_bfrop_store_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t type); pmix_status_t pmix12_bfrop_get_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t *type); int pmix12_v2_to_v1_datatype(pmix_data_type_t v2type); pmix_data_type_t pmix12_v1_to_v2_datatype(int v1type); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/bfrops/v12/bfrop_v12.c0000664000175000017500000005240015203536752020674 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-201 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-201 Oak Ridge National Labs. All rights reserved. * Copyright (c) 201-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 201-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "bfrop_v12.h" #include "internal.h" #include "src/mca/bfrops/base/base.h" static pmix_status_t init(void); static void finalize(void); static const char *data_type_string(pmix_data_type_t type); pmix_bfrops_module_t pmix_bfrops_pmix12_module = { .version = "v12", .init = init, .finalize = finalize, .pack = pmix12_bfrop_pack, .unpack = pmix12_bfrop_unpack, .copy = pmix12_bfrop_copy, .print = pmix12_bfrop_print, .copy_payload = pmix12_bfrop_copy_payload, .value_xfer = pmix12_bfrop_value_xfer, .value_load = pmix12_bfrop_value_load, .value_unload = pmix12_bfrop_value_unload, .value_cmp = pmix12_bfrop_value_cmp, .data_type_string = data_type_string }; static pmix_status_t init(void) { /* some standard types don't require anything special */ PMIX_REGISTER_TYPE("PMIX_BOOL", PMIX_BOOL, pmix12_bfrop_pack_bool, pmix12_bfrop_unpack_bool, pmix12_bfrop_std_copy, pmix12_bfrop_print_bool, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE", PMIX_BYTE, pmix12_bfrop_pack_byte, pmix12_bfrop_unpack_byte, pmix12_bfrop_std_copy, pmix12_bfrop_print_byte, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_STRING", PMIX_STRING, pmix12_bfrop_pack_string, pmix12_bfrop_unpack_string, pmix12_bfrop_copy_string, pmix12_bfrop_print_string, &pmix_mca_bfrops_v12_component.types); /* Register the rest of the standard generic types to point to internal functions */ PMIX_REGISTER_TYPE("PMIX_SIZE", PMIX_SIZE, pmix12_bfrop_pack_sizet, pmix12_bfrop_unpack_sizet, pmix12_bfrop_std_copy, pmix12_bfrop_print_size, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_PID", PMIX_PID, pmix12_bfrop_pack_pid, pmix12_bfrop_unpack_pid, pmix12_bfrop_std_copy, pmix12_bfrop_print_pid, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_INT", PMIX_INT, pmix12_bfrop_pack_int, pmix12_bfrop_unpack_int, pmix12_bfrop_std_copy, pmix12_bfrop_print_int, &pmix_mca_bfrops_v12_component.types); /* Register all the standard fixed types to point to base functions */ PMIX_REGISTER_TYPE("PMIX_INT8", PMIX_INT8, pmix12_bfrop_pack_byte, pmix12_bfrop_unpack_byte, pmix12_bfrop_std_copy, pmix12_bfrop_print_int8, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_INT16", PMIX_INT16, pmix12_bfrop_pack_int16, pmix12_bfrop_unpack_int16, pmix12_bfrop_std_copy, pmix12_bfrop_print_int16, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_INT32", PMIX_INT32, pmix12_bfrop_pack_int32, pmix12_bfrop_unpack_int32, pmix12_bfrop_std_copy, pmix12_bfrop_print_int32, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_INT64", PMIX_INT64, pmix12_bfrop_pack_int64, pmix12_bfrop_unpack_int64, pmix12_bfrop_std_copy, pmix12_bfrop_print_int64, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_UINT", PMIX_UINT, pmix12_bfrop_pack_int, pmix12_bfrop_unpack_int, pmix12_bfrop_std_copy, pmix12_bfrop_print_uint, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_UINT8", PMIX_UINT8, pmix12_bfrop_pack_byte, pmix12_bfrop_unpack_byte, pmix12_bfrop_std_copy, pmix12_bfrop_print_uint8, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_UINT16", PMIX_UINT16, pmix12_bfrop_pack_int16, pmix12_bfrop_unpack_int16, pmix12_bfrop_std_copy, pmix12_bfrop_print_uint16, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_UINT32", PMIX_UINT32, pmix12_bfrop_pack_int32, pmix12_bfrop_unpack_int32, pmix12_bfrop_std_copy, pmix12_bfrop_print_uint32, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_UINT64", PMIX_UINT64, pmix12_bfrop_pack_int64, pmix12_bfrop_unpack_int64, pmix12_bfrop_std_copy, pmix12_bfrop_print_uint64, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_FLOAT", PMIX_FLOAT, pmix12_bfrop_pack_float, pmix12_bfrop_unpack_float, pmix12_bfrop_std_copy, pmix12_bfrop_print_float, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_DOUBLE", PMIX_DOUBLE, pmix12_bfrop_pack_double, pmix12_bfrop_unpack_double, pmix12_bfrop_std_copy, pmix12_bfrop_print_double, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_TIMEVAL", PMIX_TIMEVAL, pmix12_bfrop_pack_timeval, pmix12_bfrop_unpack_timeval, pmix12_bfrop_std_copy, pmix12_bfrop_print_timeval, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_TIME", PMIX_TIME, pmix12_bfrop_pack_time, pmix12_bfrop_unpack_time, pmix12_bfrop_std_copy, pmix12_bfrop_print_time, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_STATUS", PMIX_STATUS, pmix12_bfrop_pack_status, pmix12_bfrop_unpack_status, pmix12_bfrop_std_copy, pmix12_bfrop_print_status, &pmix_mca_bfrops_v12_component.types); /* structured values need to be done here as they might * callback into standard and/or derived values */ PMIX_REGISTER_TYPE("PMIX_VALUE", PMIX_VALUE, pmix12_bfrop_pack_value, pmix12_bfrop_unpack_value, pmix12_bfrop_copy_value, pmix12_bfrop_print_value, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_PROC", PMIX_PROC, pmix12_bfrop_pack_proc, pmix12_bfrop_unpack_proc, pmix12_bfrop_copy_proc, pmix12_bfrop_print_proc, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_APP", PMIX_APP, pmix12_bfrop_pack_app, pmix12_bfrop_unpack_app, pmix12_bfrop_copy_app, pmix12_bfrop_print_app, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_INFO", PMIX_INFO, pmix12_bfrop_pack_info, pmix12_bfrop_unpack_info, pmix12_bfrop_copy_info, pmix12_bfrop_print_info, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_PDATA", PMIX_PDATA, pmix12_bfrop_pack_pdata, pmix12_bfrop_unpack_pdata, pmix12_bfrop_copy_pdata, pmix12_bfrop_print_pdata, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_BUFFER", PMIX_BUFFER, pmix12_bfrop_pack_buf, pmix12_bfrop_unpack_buf, pmix12_bfrop_copy_buf, pmix12_bfrop_print_buf, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_BYTE_OBJECT", PMIX_BYTE_OBJECT, pmix12_bfrop_pack_bo, pmix12_bfrop_unpack_bo, pmix12_bfrop_copy_bo, pmix12_bfrop_print_bo, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_KVAL", PMIX_KVAL, pmix12_bfrop_pack_kval, pmix12_bfrop_unpack_kval, pmix12_bfrop_copy_kval, pmix12_bfrop_print_kval, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_MODEX", PMIX_MODEX, pmix12_bfrop_pack_modex, pmix12_bfrop_unpack_modex, pmix12_bfrop_copy_modex, pmix12_bfrop_print_modex, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_PERSIST", PMIX_PERSIST, pmix12_bfrop_pack_persist, pmix12_bfrop_unpack_persist, pmix12_bfrop_std_copy, pmix12_bfrop_print_persist, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_POINTER", PMIX_POINTER, pmix12_bfrop_pack_ptr, pmix12_bfrop_unpack_ptr, pmix12_bfrop_std_copy, pmix12_bfrop_print_ptr, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_SCOPE", PMIX_SCOPE, pmix12_bfrop_pack_scope, pmix12_bfrop_unpack_scope, pmix12_bfrop_std_copy, pmix12_bfrop_print_scope, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_RANGE", PMIX_DATA_RANGE, pmix12_bfrop_pack_range, pmix12_bfrop_unpack_range, pmix12_bfrop_std_copy, pmix12_bfrop_print_ptr, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_COMMAND", PMIX_COMMAND, pmix12_bfrop_pack_cmd, pmix12_bfrop_unpack_cmd, pmix12_bfrop_std_copy, pmix12_bfrop_print_cmd, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_INFO_DIRECTIVES", PMIX_INFO_DIRECTIVES, pmix12_bfrop_pack_info_directives, pmix12_bfrop_unpack_info_directives, pmix12_bfrop_std_copy, pmix12_bfrop_print_info_directives, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_TYPE", PMIX_DATA_TYPE, pmix12_bfrop_pack_datatype, pmix12_bfrop_unpack_datatype, pmix12_bfrop_std_copy, pmix12_bfrop_print_datatype, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_STATE", PMIX_PROC_STATE, pmix12_bfrop_pack_proc_state, pmix12_bfrop_unpack_proc_state, pmix12_bfrop_std_copy, pmix12_bfrop_print_proc_state, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_INFO", PMIX_PROC_INFO, pmix12_bfrop_pack_proc_info, pmix12_bfrop_unpack_proc_info, pmix12_bfrop_copy_proc_info, pmix12_bfrop_print_proc_info, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_DATA_ARRAY", PMIX_DATA_ARRAY, pmix12_bfrop_pack_darray, pmix12_bfrop_unpack_darray, pmix12_bfrop_copy_darray, pmix12_bfrop_print_darray, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_PROC_RANK", PMIX_PROC_RANK, pmix12_bfrop_pack_rank, pmix12_bfrop_unpack_rank, pmix12_bfrop_std_copy, pmix12_bfrop_print_rank, &pmix_mca_bfrops_v12_component.types); PMIX_REGISTER_TYPE("PMIX_QUERY", PMIX_QUERY, pmix12_bfrop_pack_query, pmix12_bfrop_unpack_query, pmix12_bfrop_copy_query, pmix12_bfrop_print_query, &pmix_mca_bfrops_v12_component.types); /**** DEPRECATED ****/ PMIX_REGISTER_TYPE("PMIX_INFO_ARRAY", PMIX_INFO_ARRAY, pmix12_bfrop_pack_array, pmix12_bfrop_unpack_array, pmix12_bfrop_copy_array, pmix12_bfrop_print_array, &pmix_mca_bfrops_v12_component.types); /********************/ return PMIX_SUCCESS; } static void finalize(void) { int n; pmix_bfrop_type_info_t *info; for (n = 0; n < pmix_mca_bfrops_v12_component.types.size; n++) { if (NULL != (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v12_component.types, n))) { PMIX_RELEASE(info); pmix_pointer_array_set_item(&pmix_mca_bfrops_v12_component.types, n, NULL); } } } static const char *data_type_string(pmix_data_type_t type) { pmix_bfrop_type_info_t *info; if (NULL == (info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v12_component.types, type))) { return NULL; } return info->odti_name; } int pmix12_v2_to_v1_datatype(pmix_data_type_t v2type) { int v1type; /* I'm passing the data type to * a PMIx v1 compatible peer. The data type was redefined * in v2, and so we have to do some conversions here */ switch (v2type) { case 20: /* the client thinks this is simply an int */ v1type = 6; break; case 44: /* the client thinks this is PMIX_INFO_ARRAY */ v1type = 22; break; case 40: /* proc rank is just an int in v1 */ v1type = 6; break; case 39: /* data arrays must be converted to info arrays */ v1type = 22; break; case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: /* shift up one */ v1type = v2type + 1; break; default: v1type = v2type; } return v1type; } pmix_status_t pmix12_bfrop_store_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t type) { int v1type; v1type = pmix12_v2_to_v1_datatype(type); return pmix12_bfrop_pack_datatype(regtypes, buffer, &v1type, 1, PMIX_INT); } pmix_data_type_t pmix12_v1_to_v2_datatype(int v1type) { pmix_data_type_t v2type; /* I'm getting the data type that was given to * me by a PMIx v1 compatible peer. The data type was redefined * in v2, and so we have to do some conversions here */ switch (v1type) { case 20: /* the peer thinks this is PMIX_HWLOC_TOPO, which we don't support */ v2type = PMIX_UNDEF; break; case 22: /* the peer thinks this is PMIX_INFO_ARRAY */ v2type = PMIX_INFO_ARRAY; break; case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: /* shift down one */ v2type = v1type - 1; break; default: v2type = v1type; } return v2type; } pmix_status_t pmix12_bfrop_get_data_type(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_data_type_t *type) { int32_t n = 1; int v1type; pmix_status_t rc; rc = pmix12_bfrop_unpack_datatype(regtypes, buffer, &v1type, &n, PMIX_INT); if (UINT16_MAX < v1type) { *type = 0; return PMIX_ERR_UNKNOWN_DATA_TYPE; } if (PMIX_SUCCESS == rc) { *type = pmix12_v1_to_v2_datatype(v1type); } return rc; } void pmix12_bfrop_value_load(pmix_value_t *v, const void *data, pmix_data_type_t type) { pmix_byte_object_t *bo; v->type = type; if (NULL == data) { /* just set the fields to zero */ memset(&v->data, 0, sizeof(v->data)); } else { switch (type) { case PMIX_UNDEF: break; case PMIX_BOOL: memcpy(&(v->data.flag), data, 1); break; case PMIX_BYTE: memcpy(&(v->data.byte), data, 1); break; case PMIX_STRING: v->data.string = strdup(data); break; case PMIX_SIZE: memcpy(&(v->data.size), data, sizeof(size_t)); break; case PMIX_PID: memcpy(&(v->data.pid), data, sizeof(pid_t)); break; case PMIX_INT: memcpy(&(v->data.integer), data, sizeof(int)); break; case PMIX_INT8: memcpy(&(v->data.int8), data, 1); break; case PMIX_INT16: memcpy(&(v->data.int16), data, 2); break; case PMIX_INT32: memcpy(&(v->data.int32), data, 4); break; case PMIX_INT64: memcpy(&(v->data.int64), data, 8); break; case PMIX_UINT: memcpy(&(v->data.uint), data, sizeof(int)); break; case PMIX_UINT8: memcpy(&(v->data.uint8), data, 1); break; case PMIX_UINT16: memcpy(&(v->data.uint16), data, 2); break; case PMIX_UINT32: memcpy(&(v->data.uint32), data, 4); break; case PMIX_UINT64: memcpy(&(v->data.uint64), data, 8); break; case PMIX_FLOAT: memcpy(&(v->data.fval), data, sizeof(float)); break; case PMIX_DOUBLE: memcpy(&(v->data.dval), data, sizeof(double)); break; case PMIX_TIMEVAL: memcpy(&(v->data.tv), data, sizeof(struct timeval)); break; case PMIX_BYTE_OBJECT: bo = (pmix_byte_object_t *) data; v->data.bo.bytes = bo->bytes; memcpy(&(v->data.bo.size), &bo->size, sizeof(size_t)); break; case PMIX_TIME: case PMIX_VALUE: case PMIX_INFO_ARRAY: case PMIX_APP: case PMIX_INFO: case PMIX_PDATA: case PMIX_BUFFER: case PMIX_KVAL: case PMIX_MODEX: case PMIX_PERSIST: case PMIX_PROC: /* silence warnings */ break; } } } pmix_status_t pmix12_bfrop_value_unload(pmix_value_t *kv, void **data, size_t *sz) { pmix_status_t rc; rc = PMIX_SUCCESS; if (NULL == data || (NULL == *data && PMIX_STRING != kv->type && PMIX_BYTE_OBJECT != kv->type)) { rc = PMIX_ERR_BAD_PARAM; } else { switch (kv->type) { case PMIX_UNDEF: rc = PMIX_ERR_UNKNOWN_DATA_TYPE; break; case PMIX_BOOL: memcpy(*data, &(kv->data.flag), 1); *sz = 1; break; case PMIX_BYTE: memcpy(*data, &(kv->data.byte), 1); *sz = 1; break; case PMIX_STRING: if (NULL != kv->data.string) { *data = strdup(kv->data.string); *sz = strlen(kv->data.string); } break; case PMIX_SIZE: memcpy(*data, &(kv->data.size), sizeof(size_t)); *sz = sizeof(size_t); break; case PMIX_PID: memcpy(*data, &(kv->data.pid), sizeof(pid_t)); *sz = sizeof(pid_t); break; case PMIX_INT: memcpy(*data, &(kv->data.integer), sizeof(int)); *sz = sizeof(int); break; case PMIX_INT8: memcpy(*data, &(kv->data.int8), 1); *sz = 1; break; case PMIX_INT16: memcpy(*data, &(kv->data.int16), 2); *sz = 2; break; case PMIX_INT32: memcpy(*data, &(kv->data.int32), 4); *sz = 4; break; case PMIX_INT64: memcpy(*data, &(kv->data.int64), 8); *sz = 8; break; case PMIX_UINT: memcpy(*data, &(kv->data.uint), sizeof(int)); *sz = sizeof(int); break; case PMIX_UINT8: memcpy(*data, &(kv->data.uint8), 1); *sz = 1; break; case PMIX_UINT16: memcpy(*data, &(kv->data.uint16), 2); *sz = 2; break; case PMIX_UINT32: memcpy(*data, &(kv->data.uint32), 4); *sz = 4; break; case PMIX_UINT64: memcpy(*data, &(kv->data.uint64), 8); *sz = 8; break; case PMIX_FLOAT: memcpy(*data, &(kv->data.fval), sizeof(float)); *sz = sizeof(float); break; case PMIX_DOUBLE: memcpy(*data, &(kv->data.dval), sizeof(double)); *sz = sizeof(double); break; case PMIX_TIMEVAL: memcpy(*data, &(kv->data.tv), sizeof(struct timeval)); *sz = sizeof(struct timeval); break; case PMIX_BYTE_OBJECT: if (NULL != kv->data.bo.bytes && 0 < kv->data.bo.size) { *data = kv->data.bo.bytes; *sz = kv->data.bo.size; } else { *data = NULL; *sz = 0; } break; case PMIX_TIME: case PMIX_VALUE: case PMIX_INFO_ARRAY: case PMIX_APP: case PMIX_INFO: case PMIX_PDATA: case PMIX_BUFFER: case PMIX_KVAL: case PMIX_MODEX: case PMIX_PERSIST: case PMIX_PROC: /* silence warnings */ rc = PMIX_ERROR; break; } } return rc; } pmix-6.1.1~rc2/src/mca/bfrops/v12/bfrop_v12.h0000664000175000017500000000226215203536752020702 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2017 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_BFROPS_V1_H #define PMIX_BFROPS_V1_H #include "src/mca/bfrops/bfrops.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_bfrops_base_component_t pmix_mca_bfrops_v12_component; extern pmix_bfrops_module_t pmix_bfrops_pmix12_module; END_C_DECLS #endif /* PMIX_BFROPS_V1_H */ pmix-6.1.1~rc2/src/mca/bfrops/v12/pack.c0000664000175000017500000010565615203536752020026 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2011-2013 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_ARPA_INET_H # include #endif #include "bfrop_v12.h" #include "internal.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" pmix_status_t pmix12_bfrop_pack(pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t rc; pmix_pointer_array_t *regtypes = &pmix_mca_bfrops_v12_component.types; /* check for error */ if (NULL == buffer) { return PMIX_ERR_BAD_PARAM; } /* Pack the number of values */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix12_bfrop_store_data_type(regtypes, buffer, PMIX_INT32))) { return rc; } } if (PMIX_SUCCESS != (rc = pmix12_bfrop_pack_int32(regtypes, buffer, &num_vals, 1, PMIX_INT32))) { return rc; } /* Pack the value(s) */ return pmix12_bfrop_pack_buffer(regtypes, buffer, src, num_vals, type); } pmix_status_t pmix12_bfrop_pack_buffer(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t rc; pmix_bfrop_type_info_t *info; int v1type; pmix_output_verbose(20, pmix_globals.debug_output, "pmix12_bfrop_pack_buffer( %p, %p, %lu, %d )\n", (void *) buffer, src, (long unsigned int) num_vals, (int) type); /* some v1 types are simply declared differently */ switch (type) { case PMIX_COMMAND: v1type = PMIX_UINT32; break; case PMIX_SCOPE: case PMIX_DATA_RANGE: v1type = PMIX_UINT; break; case PMIX_PROC_RANK: case PMIX_PERSIST: v1type = PMIX_INT; break; case PMIX_INFO_ARRAY: v1type = 22; break; default: v1type = type; } /* Pack the declared data type */ if (PMIX_BFROP_BUFFER_FULLY_DESC == buffer->type) { if (PMIX_SUCCESS != (rc = pmix12_bfrop_store_data_type(regtypes, buffer, v1type))) { return rc; } } /* if it is an info array, we have to set the type back * so the pack routine will get the correct function */ if (PMIX_INFO_ARRAY == type) { v1type = PMIX_INFO_ARRAY; } /* Lookup the pack function for this type and call it */ info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v12_component.types, v1type); if (NULL == info) { return PMIX_ERR_PACK_FAILURE; } return info->odti_pack_fn(regtypes, buffer, src, num_vals, v1type); } /* PACK FUNCTIONS FOR GENERIC SYSTEM TYPES */ /* * BOOL */ pmix_status_t pmix12_bfrop_pack_bool(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { uint8_t *dst; int32_t i; bool *s = (bool *) src; pmix_output_verbose(20, pmix_globals.debug_output, "pmix12_bfrop_pack_bool * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = (uint8_t *) pmix_bfrop_buffer_extend(buffer, num_vals))) { return PMIX_ERR_OUT_OF_RESOURCE; } /* store the data */ for (i = 0; i < num_vals; i++) { if (s[i]) { dst[i] = 1; } else { dst[i] = 0; } } /* update buffer pointers */ buffer->pack_ptr += num_vals; buffer->bytes_used += num_vals; return PMIX_SUCCESS; } /* * INT */ pmix_status_t pmix12_bfrop_pack_int(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_INT))) { return ret; } /* Turn around and pack the real type */ return pmix12_bfrop_pack_buffer(regtypes, buffer, src, num_vals, BFROP_TYPE_INT); } /* * SIZE_T */ pmix_status_t pmix12_bfrop_pack_sizet(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them. */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_SIZE_T))) { return ret; } return pmix12_bfrop_pack_buffer(regtypes, buffer, src, num_vals, BFROP_TYPE_SIZE_T); } /* * PID_T */ pmix_status_t pmix12_bfrop_pack_pid(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(type); /* System types need to always be described so we can properly unpack them. */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_store_data_type(regtypes, buffer, BFROP_TYPE_PID_T))) { return ret; } /* Turn around and pack the real type */ return pmix12_bfrop_pack_buffer(regtypes, buffer, src, num_vals, BFROP_TYPE_PID_T); } /* PACK FUNCTIONS FOR NON-GENERIC SYSTEM TYPES */ /* * BYTE, CHAR, INT8 */ pmix_status_t pmix12_bfrop_pack_byte(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { char *dst; pmix_output_verbose(20, pmix_globals.debug_output, "pmix12_bfrop_pack_byte * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals))) { return PMIX_ERR_OUT_OF_RESOURCE; } /* store the data */ memcpy(dst, src, num_vals); /* update buffer pointers */ buffer->pack_ptr += num_vals; buffer->bytes_used += num_vals; return PMIX_SUCCESS; } /* * INT16 */ pmix_status_t pmix12_bfrop_pack_int16(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint16_t tmp, *srctmp = (uint16_t *) src; char *dst; pmix_output_verbose(20, pmix_globals.debug_output, "pmix12_bfrop_pack_int16 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals * sizeof(tmp)))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { tmp = pmix_htons(srctmp[i]); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += num_vals * sizeof(tmp); buffer->bytes_used += num_vals * sizeof(tmp); return PMIX_SUCCESS; } /* * INT32 */ pmix_status_t pmix12_bfrop_pack_int32(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint32_t tmp, *srctmp = (uint32_t *) src; char *dst; pmix_output_verbose(20, pmix_globals.debug_output, "pmix12_bfrop_pack_int32 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, num_vals * sizeof(tmp)))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { tmp = htonl(srctmp[i]); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += num_vals * sizeof(tmp); buffer->bytes_used += num_vals * sizeof(tmp); return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_datatype(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { return pmix12_bfrop_pack_int32(regtypes, buffer, src, num_vals, type); } /* * INT64 */ pmix_status_t pmix12_bfrop_pack_int64(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int32_t i; uint64_t tmp, tmp2; char *dst; size_t bytes_packed = num_vals * sizeof(tmp); pmix_output_verbose(20, pmix_globals.debug_output, "pmix12_bfrop_pack_int64 * %d\n", num_vals); PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* check to see if buffer needs extending */ if (NULL == (dst = pmix_bfrop_buffer_extend(buffer, bytes_packed))) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < num_vals; ++i) { memcpy(&tmp2, (char *) src + i * sizeof(uint64_t), sizeof(uint64_t)); tmp = pmix_hton64(tmp2); memcpy(dst, &tmp, sizeof(tmp)); dst += sizeof(tmp); } buffer->pack_ptr += bytes_packed; buffer->bytes_used += bytes_packed; return PMIX_SUCCESS; } /* * STRING */ pmix_status_t pmix12_bfrop_pack_string(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int ret = PMIX_SUCCESS; int32_t i, len; char **ssrc = (char **) src; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); for (i = 0; i < num_vals; ++i) { if (NULL == ssrc[i]) { /* got zero-length string/NULL pointer - store NULL */ len = 0; if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int32(regtypes, buffer, &len, 1, PMIX_INT32))) { return ret; } } else { len = (int32_t) strlen(ssrc[i]) + 1; if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int32(regtypes, buffer, &len, 1, PMIX_INT32))) { return ret; } if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_byte(regtypes, buffer, ssrc[i], len, PMIX_BYTE))) { return ret; } } } return PMIX_SUCCESS; } /* FLOAT */ pmix_status_t pmix12_bfrop_pack_float(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret = PMIX_SUCCESS; int32_t i; float *ssrc = (float *) src; char *convert; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); for (i = 0; i < num_vals; ++i) { if (0 > asprintf(&convert, "%f", ssrc[i])) { return PMIX_ERR_NOMEM; } if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_string(regtypes, buffer, &convert, 1, PMIX_STRING))) { free(convert); return ret; } free(convert); } return PMIX_SUCCESS; } /* DOUBLE */ pmix_status_t pmix12_bfrop_pack_double(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret = PMIX_SUCCESS; int32_t i; double *ssrc = (double *) src; char *convert; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); for (i = 0; i < num_vals; ++i) { if (0 > asprintf(&convert, "%f", ssrc[i])) { return PMIX_ERR_NOMEM; } if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_string(regtypes, buffer, &convert, 1, PMIX_STRING))) { free(convert); return ret; } free(convert); } return PMIX_SUCCESS; } /* TIMEVAL */ pmix_status_t pmix12_bfrop_pack_timeval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { int64_t tmp[2]; pmix_status_t ret = PMIX_SUCCESS; int32_t i; struct timeval *ssrc = (struct timeval *) src; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); for (i = 0; i < num_vals; ++i) { tmp[0] = (int64_t) ssrc[i].tv_sec; tmp[1] = (int64_t) ssrc[i].tv_usec; if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int64(regtypes, buffer, tmp, 2, PMIX_INT64))) { return ret; } } return PMIX_SUCCESS; } /* TIME */ pmix_status_t pmix12_bfrop_pack_time(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret = PMIX_SUCCESS; int32_t i; time_t *ssrc = (time_t *) src; uint64_t ui64; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* time_t is a system-dependent size, so cast it * to uint64_t as a generic safe size */ for (i = 0; i < num_vals; ++i) { ui64 = (uint64_t) ssrc[i]; if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int64(regtypes, buffer, &ui64, 1, PMIX_UINT64))) { return ret; } } return PMIX_SUCCESS; } /* PACK FUNCTIONS FOR GENERIC PMIX TYPES */ static pmix_status_t pack_val(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, pmix_value_t *p) { pmix_status_t ret; pmix_info_array_t array; int rank; switch (p->type) { case PMIX_BOOL: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.flag, 1, PMIX_BOOL))) { return ret; } break; case PMIX_BYTE: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.byte, 1, PMIX_BYTE))) { return ret; } break; case PMIX_STRING: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.string, 1, PMIX_STRING))) { return ret; } break; case PMIX_SIZE: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.size, 1, PMIX_SIZE))) { return ret; } break; case PMIX_PID: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.pid, 1, PMIX_PID))) { return ret; } break; case PMIX_INT: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.integer, 1, PMIX_INT))) { return ret; } break; case PMIX_INT8: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.int8, 1, PMIX_INT8))) { return ret; } break; case PMIX_INT16: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.int16, 1, PMIX_INT16))) { return ret; } break; case PMIX_INT32: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.int32, 1, PMIX_INT32))) { return ret; } break; case PMIX_INT64: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.int64, 1, PMIX_INT64))) { return ret; } break; case PMIX_UINT: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.uint, 1, PMIX_UINT))) { return ret; } break; case PMIX_UINT8: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.uint8, 1, PMIX_UINT8))) { return ret; } break; case PMIX_UINT16: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.uint16, 1, PMIX_UINT16))) { return ret; } break; case PMIX_UINT32: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.uint32, 1, PMIX_UINT32))) { return ret; } break; case PMIX_UINT64: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.uint64, 1, PMIX_UINT64))) { return ret; } break; case PMIX_FLOAT: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.fval, 1, PMIX_FLOAT))) { return ret; } break; case PMIX_DOUBLE: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.dval, 1, PMIX_DOUBLE))) { return ret; } break; case PMIX_TIMEVAL: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.tv, 1, PMIX_TIMEVAL))) { return ret; } break; case PMIX_BYTE_OBJECT: if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &p->data.bo, 1, PMIX_BYTE_OBJECT))) { return ret; } break; case PMIX_DATA_ARRAY: /* must convert this to an in info array for v1.2 */ if (PMIX_INFO != p->data.darray->type) { return PMIX_ERR_NOT_SUPPORTED; } array.size = p->data.darray->size; array.array = (pmix_info_t *) p->data.darray->array; if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &array, 1, PMIX_INFO_ARRAY))) { return ret; } break; case PMIX_PROC_RANK: /* must convert this to an int */ rank = p->data.rank; if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_buffer(regtypes, buffer, &rank, 1, PMIX_INT))) { return ret; } break; default: pmix_output(0, "PACK-PMIX-VALUE: UNSUPPORTED TYPE %d", (int) p->type); return PMIX_ERROR; } return PMIX_SUCCESS; } /* * PMIX_VALUE */ pmix_status_t pmix12_bfrop_pack_value(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_value_t *ptr; int32_t i; pmix_status_t ret; int v1type; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); ptr = (pmix_value_t *) src; for (i = 0; i < num_vals; ++i) { /* pack the type - unfortunately, v1.2 directly packed the int instead of * using the store_data_type function. This means we lose the translation! * So get it here */ v1type = pmix12_v2_to_v1_datatype(ptr[i].type); if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int(regtypes, buffer, &v1type, 1, PMIX_INT))) { return ret; } /* now pack the right field */ if (PMIX_SUCCESS != (ret = pack_val(regtypes, buffer, &ptr[i]))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_info_t *info; int32_t i; pmix_status_t ret; char *foo; int v1type; info = (pmix_info_t *) src; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); for (i = 0; i < num_vals; ++i) { /* pack key */ foo = info[i].key; if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_string(regtypes, buffer, &foo, 1, PMIX_STRING))) { return ret; } /* pack the type - unfortunately, v1.2 directly packed the int instead of * using the store_data_type function. This means we lose the translation! * So get it here */ v1type = pmix12_v2_to_v1_datatype(info[i].value.type); if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int(regtypes, buffer, &v1type, 1, PMIX_INT))) { return ret; } /* pack value */ if (PMIX_SUCCESS != (ret = pack_val(regtypes, buffer, &info[i].value))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_pdata(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_pdata_t *pdata; int32_t i; pmix_status_t ret; char *foo; int v1type; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); pdata = (pmix_pdata_t *) src; for (i = 0; i < num_vals; ++i) { /* pack the proc */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_proc(regtypes, buffer, &pdata[i].proc, 1, PMIX_PROC))) { return ret; } /* pack key */ foo = pdata[i].key; if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_string(regtypes, buffer, &foo, 1, PMIX_STRING))) { return ret; } /* pack the type - unfortunately, v1.2 directly packed the int instead of * using the store_data_type function. This means we lose the translation! * So get it here */ v1type = pmix12_v2_to_v1_datatype(pdata[i].value.type); if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int(regtypes, buffer, &v1type, 1, PMIX_INT))) { return ret; } /* pack value */ if (PMIX_SUCCESS != (ret = pack_val(regtypes, buffer, &pdata[i].value))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_buf(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_buffer_t *ptr; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); ptr = (pmix_buffer_t *) src; for (i = 0; i < num_vals; ++i) { /* pack the number of bytes */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_sizet(regtypes, buffer, &ptr[i].bytes_used, 1, PMIX_SIZE))) { return ret; } /* pack the bytes */ if (0 < ptr[i].bytes_used) { if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_byte(regtypes, buffer, ptr[i].base_ptr, ptr[i].bytes_used, PMIX_BYTE))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_proc(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_proc_t *proc; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); proc = (pmix_proc_t *) src; for (i = 0; i < num_vals; ++i) { char *ptr = proc[i].nspace; if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_string(regtypes, buffer, &ptr, 1, PMIX_STRING))) { return ret; } if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int(regtypes, buffer, &proc[i].rank, 1, PMIX_INT))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_app(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_app_t *app; int32_t i, j, nvals; pmix_status_t ret; int argc; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); app = (pmix_app_t *) src; for (i = 0; i < num_vals; ++i) { if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_string(regtypes, buffer, &app[i].cmd, 1, PMIX_STRING))) { return ret; } /* argv */ argc = PMIx_Argv_count(app[i].argv); if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int(regtypes, buffer, &argc, 1, PMIX_INT))) { return ret; } for (j = 0; j < argc; j++) { if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_string(regtypes, buffer, &app[i].argv[j], 1, PMIX_STRING))) { return ret; } } /* env */ nvals = PMIx_Argv_count(app[i].env); if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int32(regtypes, buffer, &nvals, 1, PMIX_INT32))) { return ret; } for (j = 0; j < nvals; j++) { if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_string(regtypes, buffer, &app[i].env[j], 1, PMIX_STRING))) { return ret; } } /* maxprocs */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_int(regtypes, buffer, &app[i].maxprocs, 1, PMIX_INT))) { return ret; } /* info array */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_sizet(regtypes, buffer, &app[i].ninfo, 1, PMIX_SIZE))) { return ret; } if (0 < app[i].ninfo) { if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_info(regtypes, buffer, app[i].info, app[i].ninfo, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_kval(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_kval_t *ptr; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); ptr = (pmix_kval_t *) src; for (i = 0; i < num_vals; ++i) { /* pack the key */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_string(regtypes, buffer, &ptr[i].key, 1, PMIX_STRING))) { return ret; } /* pack the value */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_value(regtypes, buffer, ptr[i].value, 1, ptr[i].value->type))) { return ret; } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_array(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_info_array_t *ptr; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); ptr = (pmix_info_array_t *) src; for (i = 0; i < num_vals; ++i) { /* pack the size */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_sizet(regtypes, buffer, &ptr[i].size, 1, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { /* pack the values */ if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_info(regtypes, buffer, ptr[i].array, ptr[i].size, PMIX_INFO))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_modex(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_modex_data_t *ptr; int32_t i; pmix_status_t ret; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); ptr = (pmix_modex_data_t *) src; for (i = 0; i < num_vals; ++i) { if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_sizet(regtypes, buffer, &ptr[i].size, 1, PMIX_SIZE))) { return ret; } if (0 < ptr[i].size) { if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_byte(regtypes, buffer, ptr[i].blob, ptr[i].size, PMIX_UINT8))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_persist(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, type); return pmix12_bfrop_pack_int(regtypes, buffer, src, num_vals, PMIX_INT); } pmix_status_t pmix12_bfrop_pack_bo(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_status_t ret; int i; pmix_byte_object_t *bo; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); bo = (pmix_byte_object_t *) src; for (i = 0; i < num_vals; i++) { if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_sizet(regtypes, buffer, &bo[i].size, 1, PMIX_SIZE))) { return ret; } if (0 < bo[i].size) { if (PMIX_SUCCESS != (ret = pmix12_bfrop_pack_byte(regtypes, buffer, bo[i].bytes, bo[i].size, PMIX_BYTE))) { return ret; } } } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_ptr(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { /* v1.x has no concept of packing a pointer, so just return */ PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, src, num_vals, type); return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_scope(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_scope_t *scope = (pmix_scope_t *) src; unsigned int *v1scope; pmix_status_t ret; int i; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* v1.2 packed scope as PMIX_UINT, so we have to convert */ v1scope = (unsigned int *) malloc(num_vals * sizeof(unsigned int)); if (NULL == v1scope) { return PMIX_ERR_NOMEM; } for (i = 0; i < num_vals; i++) { v1scope[i] = (unsigned int) scope[i]; } ret = pmix12_bfrop_pack_int(regtypes, buffer, (void *) v1scope, num_vals, PMIX_UINT); free(v1scope); return ret; } pmix_status_t pmix12_bfrop_pack_status(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* v1.2 declares pmix_status_t as an enum, which translates to int and * matches that of v2 */ return pmix12_bfrop_pack_int(regtypes, buffer, src, num_vals, PMIX_INT); } pmix_status_t pmix12_bfrop_pack_range(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_data_range_t *range = (pmix_data_range_t *) src; unsigned int *v1range; pmix_status_t ret; int i; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* v1.2 packed data range as PMIX_UINT, so we have to convert */ v1range = (unsigned int *) malloc(num_vals * sizeof(unsigned int)); if (NULL == v1range) { return PMIX_ERR_NOMEM; } for (i = 0; i < num_vals; i++) { v1range[i] = (unsigned int) range[i]; } ret = pmix12_bfrop_pack_int(regtypes, buffer, (void *) v1range, num_vals, PMIX_UINT); free(v1range); return ret; } pmix_status_t pmix12_bfrop_pack_cmd(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { pmix_cmd_t *cmd = (pmix_cmd_t *) src; int *v1cmd; pmix_status_t ret; int i; PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* v1.2 commands were enum (i.e., int), while they are uint8_t in v2 */ v1cmd = (int *) malloc(num_vals * sizeof(int)); if (NULL == v1cmd) { return PMIX_ERR_NOMEM; } for (i = 0; i < num_vals; i++) { v1cmd[i] = cmd[i]; } ret = pmix12_bfrop_pack_int(regtypes, buffer, (void *) v1cmd, num_vals, PMIX_INT); free(v1cmd); return ret; } pmix_status_t pmix12_bfrop_pack_info_directives(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, src, num_vals, type); /* v1.x has no concept of an info directive, so just return */ return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_proc_state(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, src, num_vals, type); /* v1.x has no concept of proc state, so just return */ return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_pack_darray(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, src, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_pack_proc_info(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, src, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_pack_query(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, buffer, src, num_vals, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_pack_rank(pmix_pointer_array_t *regtypes, pmix_buffer_t *buffer, const void *src, int32_t num_vals, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(regtypes, type); /* v1 rank is just an int, not a separate data type - it is defined * to be an unint32 in v2 */ return pmix12_bfrop_pack_int(regtypes, buffer, src, num_vals, PMIX_INT); } pmix-6.1.1~rc2/src/mca/bfrops/v12/Makefile.am0000664000175000017500000000361115203536752020764 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = \ bfrop_v12.h \ internal.h sources = \ bfrop_v12_component.c \ bfrop_v12.c \ pack.c \ unpack.c \ copy.c \ print.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_bfrops_v12_DSO lib = lib_sources = component = pmix_mca_bfrops_v12.la component_sources = $(headers) $(sources) else lib = libpmix_mca_bfrops_v12.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_bfrops_v12_la_SOURCES = $(component_sources) pmix_mca_bfrops_v12_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_bfrops_v12_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_bfrops_v12_la_SOURCES = $(lib_sources) libpmix_mca_bfrops_v12_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/bfrops/v12/print.c0000664000175000017500000010366715203536752020244 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_stdint.h" #include #ifdef HAVE_TIME_H # include #endif #include "bfrop_v12.h" #include "internal.h" #include "src/mca/bfrops/base/base.h" pmix_status_t pmix12_bfrop_print(char **output, char *prefix, void *src, pmix_data_type_t type) { pmix_bfrop_type_info_t *info; /* check for error */ if (NULL == output) { return PMIX_ERR_BAD_PARAM; } /* Lookup the print function for this type and call it */ info = (pmix_bfrop_type_info_t *) pmix_pointer_array_get_item(&pmix_mca_bfrops_v12_component.types, type); if (NULL == info) { return PMIX_ERR_UNKNOWN_DATA_TYPE; } return info->odti_print_fn(output, prefix, src, type); } /* * STANDARD PRINT FUNCTIONS FOR SYSTEM TYPES */ pmix_status_t pmix12_bfrop_print_bool(char **output, char *prefix, bool *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_BOOL\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_BOOL\tValue: %s", prefix, (*src) ? "TRUE" : "FALSE")) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_byte(char **output, char *prefix, uint8_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_BYTE\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_BYTE\tValue: %x", prefix, *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_string(char **output, char *prefix, char *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_STRING\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_STRING\tValue: %s", prefx, src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_size(char **output, char *prefix, size_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_SIZE\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_SIZE\tValue: %lu", prefx, (unsigned long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_pid(char **output, char *prefix, pid_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_PID\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_PID\tValue: %lu", prefx, (unsigned long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_int(char **output, char *prefix, int *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_INT\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_INT\tValue: %ld", prefx, (long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_uint(char **output, char *prefix, uint *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_UINT\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_UINT\tValue: %lu", prefx, (unsigned long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_uint8(char **output, char *prefix, uint8_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_UINT8\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_UINT8\tValue: %u", prefx, (unsigned int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_uint16(char **output, char *prefix, uint16_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_UINT16\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_UINT16\tValue: %u", prefx, (unsigned int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_uint32(char **output, char *prefix, uint32_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_UINT32\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_UINT32\tValue: %u", prefx, (unsigned int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_int8(char **output, char *prefix, int8_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_INT8\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_INT8\tValue: %d", prefx, (int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_int16(char **output, char *prefix, int16_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_INT16\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_INT16\tValue: %d", prefx, (int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_int32(char **output, char *prefix, int32_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_INT32\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_INT32\tValue: %d", prefx, (int) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_uint64(char **output, char *prefix, uint64_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_UINT64\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_UINT64\tValue: %lu", prefx, (unsigned long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_int64(char **output, char *prefix, int64_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_INT64\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_INT64\tValue: %ld", prefx, (long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_float(char **output, char *prefix, float *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_FLOAT\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_FLOAT\tValue: %f", prefx, *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_double(char **output, char *prefix, double *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_DOUBLE\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_DOUBLE\tValue: %f", prefx, *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_time(char **output, char *prefix, time_t *src, pmix_data_type_t type) { char *prefx; char *t; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_TIME\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } t = ctime(src); t[strlen(t) - 1] = '\0'; // remove trailing newline if (0 > asprintf(output, "%sData type: PMIX_TIME\tValue: %s", prefx, t)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_timeval(char **output, char *prefix, struct timeval *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_TIMEVAL\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_TIMEVAL\tValue: %ld.%06ld", prefx, (long) src->tv_sec, (long) src->tv_usec)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } /* PRINT FUNCTIONS FOR GENERIC PMIX TYPES */ /* * PMIX_VALUE */ pmix_status_t pmix12_bfrop_print_value(char **output, char *prefix, pmix_value_t *src, pmix_data_type_t type) { char *prefx; int rc; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_VALUE\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } switch (src->type) { case PMIX_BYTE: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_BYTE\tValue: %x", prefx, src->data.byte); break; case PMIX_STRING: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_STRING\tValue: %s", prefx, src->data.string); break; case PMIX_SIZE: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_SIZE\tValue: %lu", prefx, (unsigned long) src->data.size); break; case PMIX_PID: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_PID\tValue: %lu", prefx, (unsigned long) src->data.pid); break; case PMIX_INT: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_INT\tValue: %d", prefx, src->data.integer); break; case PMIX_INT8: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_INT8\tValue: %d", prefx, (int) src->data.int8); break; case PMIX_INT16: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_INT16\tValue: %d", prefx, (int) src->data.int16); break; case PMIX_INT32: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_INT32\tValue: %d", prefx, src->data.int32); break; case PMIX_INT64: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_INT64\tValue: %ld", prefx, (long) src->data.int64); break; case PMIX_UINT: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UINT\tValue: %u", prefx, src->data.uint); break; case PMIX_UINT8: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UINT8\tValue: %u", prefx, (unsigned int) src->data.uint8); break; case PMIX_UINT16: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UINT16\tValue: %u", prefx, (unsigned int) src->data.uint16); break; case PMIX_UINT32: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UINT32\tValue: %u", prefx, src->data.uint32); break; case PMIX_UINT64: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_UINT64\tValue: %lu", prefx, (unsigned long) src->data.uint64); break; case PMIX_FLOAT: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_FLOAT\tValue: %f", prefx, src->data.fval); break; case PMIX_DOUBLE: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_DOUBLE\tValue: %f", prefx, src->data.dval); break; case PMIX_TIMEVAL: rc = asprintf(output, "%sPMIX_VALUE: Data type: PMIX_TIMEVAL\tValue: %ld.%06ld", prefx, (long) src->data.tv.tv_sec, (long) src->data.tv.tv_usec); break; default: rc = asprintf(output, "%sPMIX_VALUE: Data type: UNKNOWN\tValue: UNPRINTABLE", prefx); break; } if (prefx != prefix) { free(prefx); } if (0 > rc) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_info(char **output, char *prefix, pmix_info_t *src, pmix_data_type_t type) { char *tmp; int rc; PMIX_HIDE_UNUSED_PARAMS(type); pmix12_bfrop_print_value(&tmp, NULL, &src->value, PMIX_VALUE); rc = asprintf(output, "%sKEY: %s %s", prefix, src->key, (NULL == tmp) ? "PMIX_VALUE: NULL" : tmp); if (NULL != tmp) { free(tmp); } if (0 > rc) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_pdata(char **output, char *prefix, pmix_pdata_t *src, pmix_data_type_t type) { char *tmp1, *tmp2; int rc; PMIX_HIDE_UNUSED_PARAMS(type); pmix12_bfrop_print_proc(&tmp1, NULL, &src->proc, PMIX_PROC); pmix12_bfrop_print_value(&tmp2, NULL, &src->value, PMIX_VALUE); rc = asprintf(output, "%s %s KEY: %s %s", prefix, tmp1, src->key, (NULL == tmp2) ? "NULL" : tmp2); if (NULL != tmp1) { free(tmp1); } if (NULL != tmp2) { free(tmp2); } if (0 > rc) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_buf(char **output, char *prefix, pmix_buffer_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_app(char **output, char *prefix, pmix_app_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_proc(char **output, char *prefix, pmix_proc_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } if (0 > asprintf(output, "%sPROC: %s:%d", prefx, src->nspace, src->rank)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_kval(char **output, char *prefix, pmix_kval_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_array(char **output, char *prefix, pmix_info_array_t *src, pmix_data_type_t type) { size_t j; char *tmp, *tmp2, *tmp3, *pfx; pmix_info_t *s1; PMIX_HIDE_UNUSED_PARAMS(type); if (0 > asprintf(&tmp, "%sARRAY SIZE: %ld", prefix, (long) src->size)) { return PMIX_ERR_NOMEM; } if (0 > asprintf(&pfx, "\n%s\t", (NULL == prefix) ? "" : prefix)) { free(tmp); return PMIX_ERR_NOMEM; } s1 = (pmix_info_t *) src->array; for (j = 0; j < src->size; j++) { pmix12_bfrop_print_info(&tmp2, pfx, &s1[j], PMIX_INFO); if (0 > asprintf(&tmp3, "%s%s", tmp, tmp2)) { free(tmp); free(tmp2); free(pfx); return PMIX_ERR_NOMEM; } free(tmp); free(tmp2); tmp = tmp3; } *output = tmp; free(pfx); return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_modex(char **output, char *prefix, pmix_modex_data_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_persist(char **output, char *prefix, pmix_persistence_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_PERSIST\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_PERSIST\tValue: %ld", prefx, (long) *src)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_bo(char **output, char *prefix, pmix_byte_object_t *src, pmix_data_type_t type) { char *prefx; PMIX_HIDE_UNUSED_PARAMS(type); /* deal with NULL prefix */ if (NULL == prefix) { if (0 > asprintf(&prefx, " ")) { return PMIX_ERR_NOMEM; } } else { prefx = prefix; } /* if src is NULL, just print data type and return */ if (NULL == src) { if (0 > asprintf(output, "%sData type: PMIX_BYTE_OBJECT\tValue: NULL pointer", prefx)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } if (0 > asprintf(output, "%sData type: PMIX_BYTE_OBJECT\tSize: %ld", prefx, (long) src->size)) { if (prefx != prefix) { free(prefx); } return PMIX_ERR_NOMEM; } if (prefx != prefix) { free(prefx); } return PMIX_SUCCESS; } pmix_status_t pmix12_bfrop_print_scope(char **output, char *prefix, pmix_scope_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_print_status(char **output, char *prefix, pmix_status_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_print_ptr(char **output, char *prefix, void *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_print_cmd(char **output, char *prefix, void *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_print_info_directives(char **output, char *prefix, void *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_print_datatype(char **output, char *prefix, pmix_data_type_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_print_proc_state(char **output, char *prefix, pmix_data_type_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_print_darray(char **output, char *prefix, pmix_data_array_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_print_proc_info(char **output, char *prefix, pmix_proc_info_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_print_query(char **output, char *prefix, pmix_query_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix_status_t pmix12_bfrop_print_rank(char **output, char *prefix, pmix_rank_t *src, pmix_data_type_t type) { PMIX_HIDE_UNUSED_PARAMS(output, prefix, src, type); return PMIX_ERR_NOT_SUPPORTED; } pmix-6.1.1~rc2/src/mca/bfrops/v12/bfrop_v12_component.c0000664000175000017500000000640515203536752022762 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennbfropsee and The University * of Tennbfropsee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include "bfrop_v12.h" #include "src/mca/bfrops/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_error.h" extern pmix_bfrops_module_t pmix_bfrops_pmix12_module; static pmix_status_t component_open(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_close(void); static pmix_bfrops_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_bfrops_base_component_t pmix_mca_bfrops_v12_component = { .base = { PMIX_BFROPS_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "v12", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .priority = 5, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, bfrops, v12) pmix_status_t component_open(void) { /* setup the types array */ PMIX_CONSTRUCT(&pmix_mca_bfrops_v12_component.types, pmix_pointer_array_t); return PMIX_SUCCESS; } pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = pmix_mca_bfrops_v12_component.priority; *module = (pmix_mca_base_module_t *) &pmix_bfrops_pmix12_module; return PMIX_SUCCESS; } pmix_status_t component_close(void) { PMIX_DESTRUCT(&pmix_mca_bfrops_v12_component.types); return PMIX_SUCCESS; } static pmix_bfrops_module_t *assign_module(void) { return &pmix_bfrops_pmix12_module; } pmix-6.1.1~rc2/src/mca/mca.h0000664000175000017500000003353615203536752015747 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Top-level interface for all pmix MCA components. */ #ifndef PMIX_MCA_H #define PMIX_MCA_H #include "src/include/pmix_config.h" /** * Common type for all MCA modules. * * An instance of this type is always the first element in MCA * modules, allowing the module to be associated with a * particular version of a specific framework, and to publish its own * name and version. */ struct pmix_mca_base_module_2_0_0_t { int dummy_value; }; /** Unversioned convenience typedef; use this name in frameworks/components to stay forward source-compatible */ typedef struct pmix_mca_base_module_2_0_0_t pmix_mca_base_module_t; /** Versioned convenience typedef */ typedef struct pmix_mca_base_module_2_0_0_t pmix_mca_base_module_2_0_0_t; /** * MCA component open function. * * @retval PMIX_SUCCESS This component can be used in the process. * * @retval PMIX_ERR_NOT_AVAILABLE Silently ignore this component for * the duration of the process (it may even be unloaded from the * process). * * @retval anything_else The MCA base will print an error message * ignore this component for the duration of the process (it may even * be unloaded from the process). * * All MCA components can have an "open" function that is invoked once * per process, when the component is located and loaded. * * This function should avoid registering MCA parameters (use the * component "register" function for that; i.e., * mca_base_register_component_params_2_0_0_fn_t for that). Legacy * components still register MCA params in their component "open" * function, but their authors should update them to use the component * "register" function. * * This function can also be used to allocate any resources necessary * for the component (e.g., heap memory). * * This function should return PMIX_SUCCESS if it wishes to remain * loaded in the process. Any other return value will cause the MCA * base to unload the component. Although most components do not use * this mechanism to force themselves to be unloaded (because if they * are immediately unloaded, ompi_info will not display them), the * mechanism is available should the need arise. * * If the component a) has no MCA parameters to register, b) no * resources to allocate, and c) can always be used in a process * (albeit perhaps not selected), it may provide NULL for this * function. In this cause, the MCA will act as if it called the open * function and it returned PMIX_SUCCESS. */ typedef int (*pmix_mca_base_open_component_1_0_0_fn_t)(void); /** * MCA component close function. * * @retval PMIX_SUCCESS The component successfully shut down. * * @retval any_other_value Some error occurred, but is likely to be * ignored. * * This function is invoked on a component after all of its modules * have been finalized (according to the rules of its framework) and * the component will never be used in the process again; the * component may be unloaded from the process memory after the close * function has been invoked. * * This function is typically used to release any resources still in * use by the component. * * If the component has no resources to free, it may provide NULL for * this function. In this case, the MCA will act as if it called the * close function and it returned PMIX_SUCCESS. */ typedef int (*pmix_mca_base_close_component_1_0_0_fn_t)(void); /** * MCA component query function. * * @retval PMIX_SUCCESS The component successfully queried. * * @retval any_other_value Some error occurred, but is likely to be * ignored. * * @param module The module to be used if this component is selected. * * @param priority The priority of this component. * * This function is used by the mca_base_select function to find the * highest priority component to select. Frameworks are free to * implement their own query function, but must also implement their * own select function as a result. */ typedef int (*pmix_mca_base_query_component_2_0_0_fn_t)(pmix_mca_base_module_2_0_0_t **module, int *priority); /** * MCA component parameter registration function. * * @retval PMIX_SUCCESS This component successfully registered its * parameters and can be used in this process. * @retval PMIX_ERR_BAD_PARAM Indicates that the register function * failed because an MCA parameter got an invalid/incorrect value. * * @retval anything_else The MCA will ignore this component for the * duration of the process. * * If a component has a non-NULL parameter registration function, it * will be invoked to register all MCA parameters associated with the * component. This function is invoked *before* the component "open" * function is invoked. * * The registration function should not allocate any resources that * need to be freed (aside from registering MCA parameters). * Specifically, strings that are passed to the MCA parameter * registration functions are all internally copied; there's no need * for the caller to keep them after registering a parameter. Hence, * it is possible that the registration function will be the *only* * function invoked on a component; component authors should take care * that no resources are leaked in this case. * * This function should return PMIX_SUCCESS if it wishes to remain * loaded in the process. Any other return value will cause the MCA * base to unload the component. Although most components do not use * this mechanism to force themselves to be unloaded (because if they * are immediately unloaded, ompi_info will not display them), the * mechanism is available should the need arise. * * Note that if the function returns PMIX_ERR_BAD_PARAM, it is * possible (likely?) that the component didn't register all of its * parameters. When this happens, ompi_info (and friends) will stop * execution and print out all existing registered parameters from the * entire framework (since ompi_info doesn't track individual * component register failures). This allows a user to know exactly * what value is incorrect, and from where it was set (e.g., via an * MCA params file). * * If the component a) has no MCA parameters to register, b) no * resources to allocate, and c) can always be used in a process * (albeit perhaps not selected), it may provide NULL for this * function. In this cause, the MCA will act as if it called the * registration function and it returned PMIX_SUCCESS. */ typedef int (*pmix_mca_base_register_component_params_2_0_0_fn_t)(void); /** * Maximum length of MCA project string names. */ #define PMIX_MCA_BASE_MAX_PROJECT_NAME_LEN 15 /** * Maximum length of MCA framework string names. */ #define PMIX_MCA_BASE_MAX_TYPE_NAME_LEN 31 /** * Maximum length of MCA component string names. */ #define PMIX_MCA_BASE_MAX_COMPONENT_NAME_LEN 63 /** * Common type for all MCA components. * * An instance of this type is always the first element in MCA * components, allowing the component to be associated with a * particular version of a specific framework, and to publish its own * name and version. */ struct pmix_mca_base_component_2_1_0_t { int pmix_mca_major_version; /**< Major number of the MCA. */ int pmix_mca_minor_version; /**< Minor number of the MCA. */ int pmix_mca_release_version; /**< Release number of the MCA. */ char pmix_mca_project_name[PMIX_MCA_BASE_MAX_PROJECT_NAME_LEN + 1]; /**< String name of the project that this component belongs to. */ int pmix_mca_project_major_version; /**< Major version number of the project that this component belongs to. */ int pmix_mca_project_minor_version; /**< Minor version number of the project that this component belongs to. */ int pmix_mca_project_release_version; /**< Release version number of the project that this component belongs to. */ char pmix_mca_type_name[PMIX_MCA_BASE_MAX_TYPE_NAME_LEN + 1]; /**< String name of the framework that this component belongs to. */ int pmix_mca_type_major_version; /**< Major version number of the framework that this component belongs to. */ int pmix_mca_type_minor_version; /**< Minor version number of the framework that this component belongs to. */ int pmix_mca_type_release_version; /**< Release version number of the framework that this component belongs to. */ char pmix_mca_component_name[PMIX_MCA_BASE_MAX_COMPONENT_NAME_LEN + 1]; /**< This comopnent's string name. */ int pmix_mca_component_major_version; /**< This component's major version number. */ int pmix_mca_component_minor_version; /**< This component's minor version number. */ int pmix_mca_component_release_version; /**< This component's release version number. */ pmix_mca_base_open_component_1_0_0_fn_t pmix_mca_open_component; /**< Method for opening this component. */ pmix_mca_base_close_component_1_0_0_fn_t pmix_mca_close_component; /**< Method for closing this component. */ pmix_mca_base_query_component_2_0_0_fn_t pmix_mca_query_component; /**< Method for querying this component. */ pmix_mca_base_register_component_params_2_0_0_fn_t pmix_mca_register_component_params; /**< Method for registering the component's MCA parameters */ /** Extra space to allow for expansion in the future without breaking older components. */ char reserved[32]; }; #define PMIX_BASE_COMPONENT_STATIC_INIT \ { \ .pmix_mca_major_version = 0, \ .pmix_mca_minor_version = 0, \ .pmix_mca_release_version = 0, \ .pmix_mca_project_name = {0}, \ .pmix_mca_type_major_version = 0, \ .pmix_mca_type_minor_version = 0, \ .pmix_mca_type_release_version = 0, \ .pmix_mca_component_name = {0}, \ .pmix_mca_component_major_version = 0, \ .pmix_mca_component_minor_version = 0, \ .pmix_mca_component_release_version = 0, \ .pmix_mca_open_component = NULL, \ .pmix_mca_close_component = NULL, \ .pmix_mca_query_component = NULL, \ .pmix_mca_register_component_params = NULL, \ .reserved = {0} \ } /** Unversioned convenience typedef; use this name in frameworks/components to stay forward source-compatible */ typedef struct pmix_mca_base_component_2_1_0_t pmix_mca_base_component_t; /** Versioned convenience typedef */ typedef struct pmix_mca_base_component_2_1_0_t pmix_mca_base_component_2_1_0_t; /** * Macro for framework author convenience. * * This macro is used by frameworks defining their component types, * indicating that they subscribe to the MCA version 2.0.0. See * component header files (e.g., coll.h) for examples of its usage. */ #define PMIX_MCA_BASE_VERSION_MAJOR 2 #define PMIX_MCA_BASE_VERSION_MINOR 1 #define PMIX_MCA_BASE_VERSION_RELEASE 0 #define PMIX_MCA_BASE_MAKE_VERSION(level, MAJOR, MINOR, RELEASE) \ .pmix_mca_##level##_major_version = MAJOR, .pmix_mca_##level##_minor_version = MINOR, \ .pmix_mca_##level##_release_version = RELEASE #define PMIX_MCA_BASE_VERSION_2_1_0(PROJECT, project_major, project_minor, project_release, TYPE, \ type_major, type_minor, type_release) \ .pmix_mca_major_version = PMIX_MCA_BASE_VERSION_MAJOR, \ .pmix_mca_minor_version = PMIX_MCA_BASE_VERSION_MINOR, \ .pmix_mca_release_version = PMIX_MCA_BASE_VERSION_RELEASE, .pmix_mca_project_name = PROJECT, \ PMIX_MCA_BASE_MAKE_VERSION(project, project_major, project_minor, project_release), \ .pmix_mca_type_name = TYPE, \ PMIX_MCA_BASE_MAKE_VERSION(type, type_major, type_minor, type_release) #define PMIX_MCA_BASE_VERSION_1_0_0(type, type_major, type_minor, type_release) \ PMIX_MCA_BASE_VERSION_2_1_0("pmix", PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, \ PMIX_RELEASE_VERSION, type, type_major, type_minor, type_release) #define PMIX_MCA_BASE_COMPONENT_DECLARE_STAMP(project, framework, component, suffix) \ project ## _mca ## _ ## framework ## _ ## component ## _ ##suffix #define PMIX_MCA_BASE_COMPONENT_DECLARE_EXPANDER(project, framework, component, suffix) \ PMIX_MCA_BASE_COMPONENT_DECLARE_STAMP(project, framework, component, suffix) #define PMIX_MCA_BASE_COMPONENT_INIT(project, framework, comp_name) \ const pmix_mca_base_component_t *PMIX_MCA_BASE_COMPONENT_DECLARE_EXPANDER(project, framework, comp_name, component_ptr) = \ (const pmix_mca_base_component_t *)&PMIX_MCA_BASE_COMPONENT_DECLARE_EXPANDER(project, framework, comp_name, component); #endif /* PMIX_MCA_H */ pmix-6.1.1~rc2/src/mca/psensor/0000775000175000017500000000000015203536752016515 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/psensor/file/0000775000175000017500000000000015203536752017434 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/psensor/file/psensor_file.h0000664000175000017500000000142015203536752022272 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * File movement sensor */ #ifndef PMIX_PSENSOR_FILE_H #define PMIX_PSENSOR_FILE_H #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/mca/psensor/psensor.h" BEGIN_C_DECLS typedef struct { pmix_psensor_base_component_t super; pmix_list_t trackers; } pmix_psensor_file_component_t; PMIX_EXPORT extern pmix_psensor_file_component_t pmix_mca_psensor_file_component; extern pmix_psensor_base_module_t pmix_psensor_file_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/psensor/file/psensor_file.c0000664000175000017500000002557715203536752022310 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2011-2012 Los Alamos National Security, LLC. * All rights reserved. * * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #include #include #include #ifdef HAVE_TIME_H # include #endif #include #include #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_show_help.h" #include "psensor_file.h" #include "src/mca/psensor/base/base.h" /* declare the API functions */ static pmix_status_t start(pmix_peer_t *requestor, pmix_status_t error, const pmix_info_t *monitor, const pmix_info_t directives[], size_t ndirs); static pmix_status_t stop(pmix_peer_t *requestor, char *id); /* instantiate the module */ pmix_psensor_base_module_t pmix_psensor_file_module = { .start = start, .stop = stop }; /* define a tracking object */ typedef struct { pmix_list_item_t super; pmix_peer_t *requestor; char *id; bool event_active; pmix_event_t ev; pmix_event_t cdev; struct timeval tv; int tick; char *file; bool file_size; bool file_access; bool file_mod; size_t last_size; time_t last_access; time_t last_mod; uint32_t ndrops; uint32_t nmisses; pmix_status_t error; pmix_data_range_t range; pmix_info_t *info; size_t ninfo; } file_tracker_t; static void ft_constructor(file_tracker_t *ft) { ft->requestor = NULL; ft->id = NULL; ft->event_active = false; ft->tv.tv_sec = 0; ft->tv.tv_usec = 0; ft->tick = 0; ft->file_size = false; ft->file_access = false; ft->file_mod = false; ft->last_size = 0; ft->last_access = 0; ft->last_mod = 0; ft->ndrops = 0; ft->nmisses = 0; ft->error = PMIX_SUCCESS; ft->range = PMIX_RANGE_NAMESPACE; ft->info = NULL; ft->ninfo = 0; } static void ft_destructor(file_tracker_t *ft) { if (NULL != ft->requestor) { PMIX_RELEASE(ft->requestor); } if (NULL != ft->id) { free(ft->id); } if (ft->event_active) { pmix_event_del(&ft->ev); } if (NULL != ft->file) { free(ft->file); } if (NULL != ft->info) { PMIX_INFO_FREE(ft->info, ft->ninfo); } } PMIX_CLASS_INSTANCE(file_tracker_t, pmix_list_item_t, ft_constructor, ft_destructor); /* define a local caddy */ typedef struct { pmix_object_t super; pmix_event_t ev; pmix_peer_t *requestor; char *id; } file_caddy_t; static void cd_con(file_caddy_t *p) { p->requestor = NULL; p->id = NULL; } static void cd_des(file_caddy_t *p) { if (NULL != (p->requestor)) { PMIX_RELEASE(p->requestor); } if (NULL != p->id) { free(p->id); } } PMIX_CLASS_INSTANCE(file_caddy_t, pmix_object_t, cd_con, cd_des); static void file_sample(int sd, short args, void *cbdata); static void add_tracker(int sd, short flags, void *cbdata) { file_tracker_t *ft = (file_tracker_t *) cbdata; PMIX_ACQUIRE_OBJECT(fd); PMIX_HIDE_UNUSED_PARAMS(sd, flags); /* add the tracker to our list */ pmix_list_append(&pmix_mca_psensor_file_component.trackers, &ft->super); /* setup the timer event */ pmix_event_evtimer_set(pmix_psensor_base.evbase, &ft->ev, file_sample, ft); pmix_event_evtimer_add(&ft->ev, &ft->tv); ft->event_active = true; } /* * Start monitoring of local processes */ static pmix_status_t start(pmix_peer_t *requestor, pmix_status_t error, const pmix_info_t *monitor, const pmix_info_t directives[], size_t ndirs) { file_tracker_t *ft; size_t n; PMIX_HIDE_UNUSED_PARAMS(error); pmix_output_verbose(1, pmix_psensor_base_framework.framework_output, "[%s:%d] checking file monitoring for requestor %s:%d", pmix_globals.myid.nspace, pmix_globals.myid.rank, requestor->info->pname.nspace, requestor->info->pname.rank); /* if they didn't ask to monitor a file, then nothing for us to do */ if (0 != strcmp(monitor->key, PMIX_MONITOR_FILE)) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* setup to track this monitoring operation */ ft = PMIX_NEW(file_tracker_t); PMIX_RETAIN(requestor); ft->requestor = requestor; ft->file = strdup(monitor->value.data.string); /* check the directives to see if what they want monitored */ for (n = 0; n < ndirs; n++) { if (0 == strcmp(directives[n].key, PMIX_MONITOR_FILE_SIZE)) { ft->file_size = PMIX_INFO_TRUE(&directives[n]); } else if (0 == strcmp(directives[n].key, PMIX_MONITOR_FILE_ACCESS)) { ft->file_access = PMIX_INFO_TRUE(&directives[n]); } else if (0 == strcmp(directives[n].key, PMIX_MONITOR_FILE_MODIFY)) { ft->file_mod = PMIX_INFO_TRUE(&directives[n]); } else if (0 == strcmp(directives[n].key, PMIX_MONITOR_FILE_DROPS)) { ft->ndrops = directives[n].value.data.uint32; } else if (0 == strcmp(directives[n].key, PMIX_MONITOR_FILE_CHECK_TIME)) { ft->tv.tv_sec = directives[n].value.data.uint32; } else if (0 == strcmp(directives[n].key, PMIX_RANGE)) { ft->range = directives[n].value.data.range; } } if (0 == ft->tv.tv_sec || (!ft->file_size && !ft->file_access && !ft->file_mod)) { /* didn't specify a sample rate, or what should be sampled */ PMIX_RELEASE(ft); return PMIX_ERR_BAD_PARAM; } /* need to push into our event base to add this to our trackers */ pmix_event_assign(&ft->cdev, pmix_psensor_base.evbase, -1, EV_WRITE, add_tracker, ft); PMIX_POST_OBJECT(ft); pmix_event_active(&ft->cdev, EV_WRITE, 1); return PMIX_SUCCESS; } static void del_tracker(int sd, short flags, void *cbdata) { file_caddy_t *cd = (file_caddy_t *) cbdata; file_tracker_t *ft, *ftnext; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, flags); /* remove the tracker from our list */ PMIX_LIST_FOREACH_SAFE (ft, ftnext, &pmix_mca_psensor_file_component.trackers, file_tracker_t) { if (ft->requestor != cd->requestor) { continue; } if (NULL == cd->id || (NULL != ft->id && 0 == strcmp(ft->id, cd->id))) { pmix_list_remove_item(&pmix_mca_psensor_file_component.trackers, &ft->super); PMIX_RELEASE(ft); } } PMIX_RELEASE(cd); } static pmix_status_t stop(pmix_peer_t *requestor, char *id) { file_caddy_t *cd; cd = PMIX_NEW(file_caddy_t); PMIX_RETAIN(requestor); cd->requestor = requestor; if (NULL != id) { cd->id = strdup(id); } /* need to push into our event base to add this to our trackers */ pmix_event_assign(&cd->ev, pmix_psensor_base.evbase, -1, EV_WRITE, del_tracker, cd); PMIX_POST_OBJECT(cd); pmix_event_active(&cd->ev, EV_WRITE, 1); return PMIX_SUCCESS; } static void opcbfunc(pmix_status_t status, void *cbdata) { file_tracker_t *ft = (file_tracker_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_RELEASE(ft); } static void file_sample(int sd, short args, void *cbdata) { file_tracker_t *ft = (file_tracker_t *) cbdata; struct stat buf; pmix_status_t rc; pmix_proc_t source; PMIX_ACQUIRE_OBJECT(ft); PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(1, pmix_psensor_base_framework.framework_output, "[%s:%d] sampling file %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, ft->file); /* stat the file and get its info */ /* coverity[TOCTOU] */ if (0 > stat(ft->file, &buf)) { /* cannot stat file */ pmix_output_verbose(1, pmix_psensor_base_framework.framework_output, "[%s:%d] could not stat %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, ft->file); /* re-add the timer, in case this file shows up */ pmix_event_evtimer_add(&ft->ev, &ft->tv); return; } pmix_output_verbose(1, pmix_psensor_base_framework.framework_output, "[%s:%d] size %lu access %s\tmod %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, (unsigned long) buf.st_size, ctime(&buf.st_atime), ctime(&buf.st_mtime)); if (ft->file_size) { if (buf.st_size == (int64_t) ft->last_size) { ft->nmisses++; } else { ft->nmisses = 0; ft->last_size = buf.st_size; } } else if (ft->file_access) { if (buf.st_atime == ft->last_access) { ft->nmisses++; } else { ft->nmisses = 0; ft->last_access = buf.st_atime; } } else if (ft->file_mod) { if (buf.st_mtime == ft->last_mod) { ft->nmisses++; } else { ft->nmisses = 0; ft->last_mod = buf.st_mtime; } } pmix_output_verbose(1, pmix_psensor_base_framework.framework_output, "[%s:%d] sampled file %s misses %d", pmix_globals.myid.nspace, pmix_globals.myid.rank, ft->file, ft->nmisses); if (ft->nmisses == ft->ndrops) { if (4 < pmix_output_get_verbosity(pmix_psensor_base_framework.framework_output)) { pmix_show_help("help-pmix-psensor-file.txt", "file-stalled", true, ft->file, ft->last_size, ctime(&ft->last_access), ctime(&ft->last_mod)); } /* stop monitoring this client */ pmix_list_remove_item(&pmix_mca_psensor_file_component.trackers, &ft->super); /* generate an event */ pmix_strncpy(source.nspace, ft->requestor->info->pname.nspace, PMIX_MAX_NSLEN); source.rank = ft->requestor->info->pname.rank; rc = PMIx_Notify_event(PMIX_MONITOR_FILE_ALERT, &source, ft->range, ft->info, ft->ninfo, opcbfunc, ft); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } return; } /* re-add the timer */ pmix_event_evtimer_add(&ft->ev, &ft->tv); } pmix-6.1.1~rc2/src/mca/psensor/file/help-pmix-psensor-file.txt0000664000175000017500000000071315203536752024505 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. # # Copyright (c) 2017 Intel, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English general help file for the file sensor # [file-stalled] A specified file is not changing, indicating a possibly stalled application: File: %s Last size: %lu Last access: %sLast modification: %s pmix-6.1.1~rc2/src/mca/psensor/file/Makefile.am0000664000175000017500000000220315203536752021465 0ustar alastairalastair# # Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # EXTRA_DIST = help-pmix-psensor-file.txt sources = \ psensor_file.c \ psensor_file.h \ psensor_file_component.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_psensor_file_DSO component_noinst = component_install = pmix_mca_psensor_file.la else component_noinst = libpmix_mca_psensor_file.la component_install = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component_install) pmix_mca_psensor_file_la_SOURCES = $(sources) pmix_mca_psensor_file_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_psensor_file_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(component_noinst) libpmix_mca_psensor_file_la_SOURCES =$(sources) libpmix_mca_psensor_file_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/psensor/file/psensor_file_component.c0000664000175000017500000000345715203536752024363 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/mca/psensor/base/base.h" #include "src/mca/psensor/file/psensor_file.h" /* * Local functions */ static int psensor_file_open(void); static int psensor_file_close(void); static int psensor_file_query(pmix_mca_base_module_t **module, int *priority); pmix_psensor_file_component_t pmix_mca_psensor_file_component = { .super = { PMIX_PSENSOR_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "file", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ psensor_file_open, /* component open */ psensor_file_close, /* component close */ psensor_file_query /* component query */ } }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, psensor, file) static int psensor_file_open(void) { PMIX_CONSTRUCT(&pmix_mca_psensor_file_component.trackers, pmix_list_t); return PMIX_SUCCESS; } static int psensor_file_query(pmix_mca_base_module_t **module, int *priority) { *priority = 20; /* irrelevant */ *module = (pmix_mca_base_module_t *) &pmix_psensor_file_module; return PMIX_SUCCESS; } /** * Close all subsystems. */ static int psensor_file_close(void) { PMIX_LIST_DESTRUCT(&pmix_mca_psensor_file_component.trackers); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/psensor/heartbeat/0000775000175000017500000000000015203536752020454 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/psensor/heartbeat/psensor_heartbeat.h0000664000175000017500000000217515203536752024342 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Heartbeat sensor */ #ifndef PMIX_PSENSOR_HEARTBEAT_H #define PMIX_PSENSOR_HEARTBEAT_H #include "src/include/pmix_config.h" #include "src/include/pmix_types.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/mca/psensor/psensor.h" BEGIN_C_DECLS typedef struct { pmix_psensor_base_component_t super; bool recv_active; pmix_list_t trackers; } pmix_psensor_heartbeat_component_t; PMIX_EXPORT extern pmix_psensor_heartbeat_component_t pmix_mca_psensor_heartbeat_component; extern pmix_psensor_base_module_t pmix_psensor_heartbeat_module; void pmix_psensor_heartbeat_recv_beats(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/psensor/heartbeat/psensor_heartbeat.c0000664000175000017500000002616415203536752024341 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2012 Los Alamos National Security, LLC. All rights * reserved. * * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #ifdef HAVE_STRING_H # include #endif /* HAVE_STRING_H */ #include #include #include #include "src/include/pmix_globals.h" #include "src/mca/ptl/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_show_help.h" #include "psensor_heartbeat.h" #include "src/mca/psensor/base/base.h" /* declare the API functions */ static pmix_status_t heartbeat_start(pmix_peer_t *requestor, pmix_status_t error, const pmix_info_t *monitor, const pmix_info_t directives[], size_t ndirs); static pmix_status_t heartbeat_stop(pmix_peer_t *requestor, char *id); /* instantiate the module */ pmix_psensor_base_module_t pmix_psensor_heartbeat_module = { .start = heartbeat_start, .stop = heartbeat_stop }; /* tracker object */ typedef struct { pmix_list_item_t super; pmix_peer_t *requestor; char *id; bool event_active; pmix_event_t ev; pmix_event_t cdev; struct timeval tv; uint32_t nbeats; uint32_t ndrops; uint32_t nmissed; pmix_status_t error; pmix_data_range_t range; pmix_info_t *info; size_t ninfo; bool stopped; } pmix_heartbeat_trkr_t; static void ft_constructor(pmix_heartbeat_trkr_t *ft) { ft->requestor = NULL; ft->id = NULL; ft->event_active = false; ft->tv.tv_sec = 0; ft->tv.tv_usec = 0; ft->nbeats = 0; ft->ndrops = 0; ft->nmissed = 0; ft->error = PMIX_SUCCESS; ft->range = PMIX_RANGE_NAMESPACE; ft->info = NULL; ft->ninfo = 0; ft->stopped = false; } static void ft_destructor(pmix_heartbeat_trkr_t *ft) { if (NULL != ft->requestor) { PMIX_RELEASE(ft->requestor); } if (NULL != ft->id) { free(ft->id); } if (ft->event_active) { pmix_event_del(&ft->ev); } if (NULL != ft->info) { PMIX_INFO_FREE(ft->info, ft->ninfo); } } PMIX_CLASS_INSTANCE(pmix_heartbeat_trkr_t, pmix_list_item_t, ft_constructor, ft_destructor); /* define a local caddy */ typedef struct { pmix_object_t super; pmix_event_t ev; pmix_peer_t *requestor; char *id; } heartbeat_caddy_t; static void cd_con(heartbeat_caddy_t *p) { p->requestor = NULL; p->id = NULL; } static void cd_des(heartbeat_caddy_t *p) { if (NULL != (p->requestor)) { PMIX_RELEASE(p->requestor); } if (NULL != p->id) { free(p->id); } } PMIX_CLASS_INSTANCE(heartbeat_caddy_t, pmix_object_t, cd_con, cd_des); typedef struct { pmix_object_t super; pmix_event_t ev; pmix_peer_t *peer; } pmix_psensor_beat_t; static void bcon(pmix_psensor_beat_t *p) { p->peer = NULL; } static void bdes(pmix_psensor_beat_t *p) { if (NULL != p->peer) { PMIX_RELEASE(p->peer); } } PMIX_CLASS_INSTANCE(pmix_psensor_beat_t, pmix_object_t, bcon, bdes); static void check_heartbeat(int fd, short dummy, void *arg); static void add_tracker(int sd, short flags, void *cbdata) { pmix_heartbeat_trkr_t *ft = (pmix_heartbeat_trkr_t *) cbdata; PMIX_ACQUIRE_OBJECT(ft); PMIX_HIDE_UNUSED_PARAMS(sd, flags); /* add the tracker to our list */ pmix_list_append(&pmix_mca_psensor_heartbeat_component.trackers, &ft->super); /* setup the timer event */ pmix_event_evtimer_set(pmix_psensor_base.evbase, &ft->ev, check_heartbeat, ft); pmix_event_evtimer_add(&ft->ev, &ft->tv); ft->event_active = true; } static pmix_status_t heartbeat_start(pmix_peer_t *requestor, pmix_status_t error, const pmix_info_t *monitor, const pmix_info_t directives[], size_t ndirs) { pmix_heartbeat_trkr_t *ft; size_t n; pmix_ptl_posted_recv_t *rcv; pmix_output_verbose(1, pmix_psensor_base_framework.framework_output, "[%s:%d] checking heartbeat monitoring for requestor %s:%d", pmix_globals.myid.nspace, pmix_globals.myid.rank, requestor->info->pname.nspace, requestor->info->pname.rank); /* if they didn't ask for heartbeats, then nothing for us to do */ if (0 != strcmp(monitor->key, PMIX_MONITOR_HEARTBEAT)) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* setup to track this monitoring operation */ ft = PMIX_NEW(pmix_heartbeat_trkr_t); PMIX_RETAIN(requestor); ft->requestor = requestor; ft->error = error; /* check the directives to see what they want monitored */ for (n = 0; n < ndirs; n++) { if (0 == strcmp(directives[n].key, PMIX_MONITOR_HEARTBEAT_TIME)) { ft->tv.tv_sec = directives[n].value.data.uint32; } else if (0 == strcmp(directives[n].key, PMIX_MONITOR_HEARTBEAT_DROPS)) { ft->ndrops = directives[n].value.data.uint32; } else if (0 == strcmp(directives[n].key, PMIX_RANGE)) { ft->range = directives[n].value.data.range; } } if (0 == ft->tv.tv_sec) { /* didn't specify a sample rate, or what should be sampled */ PMIX_RELEASE(ft); return PMIX_ERR_BAD_PARAM; } /* if the recv hasn't been posted, so so now */ if (!pmix_mca_psensor_heartbeat_component.recv_active) { /* setup to receive heartbeats */ rcv = PMIX_NEW(pmix_ptl_posted_recv_t); rcv->tag = PMIX_PTL_TAG_HEARTBEAT; rcv->cbfunc = pmix_psensor_heartbeat_recv_beats; /* add it to the beginning of the list of recvs */ pmix_list_prepend(&pmix_ptl_base.posted_recvs, &rcv->super); pmix_mca_psensor_heartbeat_component.recv_active = true; } /* need to push into our event base to add this to our trackers */ pmix_event_assign(&ft->cdev, pmix_psensor_base.evbase, -1, EV_WRITE, add_tracker, ft); PMIX_POST_OBJECT(ft); pmix_event_active(&ft->cdev, EV_WRITE, 1); return PMIX_SUCCESS; } static void del_tracker(int sd, short flags, void *cbdata) { heartbeat_caddy_t *cd = (heartbeat_caddy_t *) cbdata; pmix_heartbeat_trkr_t *ft, *ftnext; PMIX_ACQUIRE_OBJECT(cd); PMIX_HIDE_UNUSED_PARAMS(sd, flags); /* remove the tracker from our list */ PMIX_LIST_FOREACH_SAFE (ft, ftnext, &pmix_mca_psensor_heartbeat_component.trackers, pmix_heartbeat_trkr_t) { if (ft->requestor != cd->requestor) { continue; } if (NULL == cd->id || (NULL != ft->id && 0 == strcmp(ft->id, cd->id))) { pmix_list_remove_item(&pmix_mca_psensor_heartbeat_component.trackers, &ft->super); PMIX_RELEASE(ft); } } PMIX_RELEASE(cd); } static pmix_status_t heartbeat_stop(pmix_peer_t *requestor, char *id) { heartbeat_caddy_t *cd; cd = PMIX_NEW(heartbeat_caddy_t); PMIX_RETAIN(requestor); cd->requestor = requestor; if (NULL != id) { cd->id = strdup(id); } /* need to push into our event base to remove this from our trackers */ pmix_event_assign(&cd->ev, pmix_psensor_base.evbase, -1, EV_WRITE, del_tracker, cd); PMIX_POST_OBJECT(cd); pmix_event_active(&cd->ev, EV_WRITE, 1); return PMIX_SUCCESS; } static void opcbfunc(pmix_status_t status, void *cbdata) { pmix_heartbeat_trkr_t *ft = (pmix_heartbeat_trkr_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_RELEASE(ft); // maintain accounting } /* this function automatically gets periodically called * by the event library so we can check on the state * of the various procs we are monitoring */ static void check_heartbeat(int fd, short dummy, void *cbdata) { pmix_heartbeat_trkr_t *ft = (pmix_heartbeat_trkr_t *) cbdata; pmix_status_t rc; pmix_proc_t source; PMIX_ACQUIRE_OBJECT(ft); PMIX_HIDE_UNUSED_PARAMS(fd, dummy); pmix_output_verbose(1, pmix_psensor_base_framework.framework_output, "[%s:%d] sensor:check_heartbeat for proc %s:%d", pmix_globals.myid.nspace, pmix_globals.myid.rank, ft->requestor->info->pname.nspace, ft->requestor->info->pname.rank); if (0 == ft->nbeats && !ft->stopped) { /* no heartbeat recvd in last window */ pmix_output_verbose(1, pmix_psensor_base_framework.framework_output, "[%s:%d] sensor:check_heartbeat failed for proc %s:%d", pmix_globals.myid.nspace, pmix_globals.myid.rank, ft->requestor->info->pname.nspace, ft->requestor->info->pname.rank); /* generate an event */ pmix_strncpy(source.nspace, ft->requestor->info->pname.nspace, PMIX_MAX_NSLEN); source.rank = ft->requestor->info->pname.rank; /* ensure the tracker remains throughout the process */ PMIX_RETAIN(ft); /* mark that the process appears stopped so we don't * continue to report it */ ft->stopped = true; rc = PMIx_Notify_event(PMIX_MONITOR_HEARTBEAT_ALERT, &source, ft->range, ft->info, ft->ninfo, opcbfunc, ft); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } else { pmix_output_verbose(1, pmix_psensor_base_framework.framework_output, "[%s:%d] sensor:check_heartbeat detected %d beats for proc %s:%d", pmix_globals.myid.nspace, pmix_globals.myid.rank, ft->nbeats, ft->requestor->info->pname.nspace, ft->requestor->info->pname.rank); } /* reset for next period */ ft->nbeats = 0; /* reset the timer */ pmix_event_evtimer_add(&ft->ev, &ft->tv); } static void add_beat(int sd, short args, void *cbdata) { pmix_psensor_beat_t *b = (pmix_psensor_beat_t *) cbdata; pmix_heartbeat_trkr_t *ft; PMIX_ACQUIRE_OBJECT(b); PMIX_HIDE_UNUSED_PARAMS(sd, args); /* find this peer in our trackers */ PMIX_LIST_FOREACH (ft, &pmix_mca_psensor_heartbeat_component.trackers, pmix_heartbeat_trkr_t) { if (ft->requestor == b->peer) { /* increment the beat count */ ++ft->nbeats; /* ensure we know that the proc is alive */ ft->stopped = false; break; } } PMIX_RELEASE(b); } void pmix_psensor_heartbeat_recv_beats(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_psensor_beat_t *b; PMIX_HIDE_UNUSED_PARAMS(hdr, buf, cbdata); b = PMIX_NEW(pmix_psensor_beat_t); PMIX_RETAIN(peer); b->peer = peer; /* shift this to our thread for processing */ pmix_event_assign(&b->ev, pmix_psensor_base.evbase, -1, EV_WRITE, add_beat, b); PMIX_POST_OBJECT(b); pmix_event_active(&b->ev, EV_WRITE, 1); } pmix-6.1.1~rc2/src/mca/psensor/heartbeat/Makefile.am0000664000175000017500000000222315203536752022507 0ustar alastairalastair# # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # # Copyright (c) 2017-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # sources = \ psensor_heartbeat.c \ psensor_heartbeat.h \ psensor_heartbeat_component.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_psensor_heartbeat_DSO component_noinst = component_install = pmix_mca_psensor_heartbeat.la else component_noinst = libpmix_mca_psensor_heartbeat.la component_install = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component_install) pmix_mca_psensor_heartbeat_la_SOURCES = $(sources) pmix_mca_psensor_heartbeat_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_psensor_heartbeat_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(component_noinst) libpmix_mca_psensor_heartbeat_la_SOURCES =$(sources) libpmix_mca_psensor_heartbeat_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/psensor/heartbeat/psensor_heartbeat_component.c0000664000175000017500000000361015203536752026412 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/mca/psensor/base/base.h" #include "src/mca/psensor/heartbeat/psensor_heartbeat.h" #include "src/mca/ptl/ptl.h" /* * Local functions */ static int heartbeat_open(void); static int heartbeat_close(void); static int heartbeat_query(pmix_mca_base_module_t **module, int *priority); pmix_psensor_heartbeat_component_t pmix_mca_psensor_heartbeat_component = { .super = { PMIX_PSENSOR_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "heartbeat", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ heartbeat_open, /* component open */ heartbeat_close, /* component close */ heartbeat_query /* component query */ } }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, psensor, heartbeat) /** * component open/close/init function */ static int heartbeat_open(void) { PMIX_CONSTRUCT(&pmix_mca_psensor_heartbeat_component.trackers, pmix_list_t); return PMIX_SUCCESS; } static int heartbeat_query(pmix_mca_base_module_t **module, int *priority) { *priority = 5; // irrelevant *module = (pmix_mca_base_module_t *) &pmix_psensor_heartbeat_module; return PMIX_SUCCESS; } /** * Close all subsystems. */ static int heartbeat_close(void) { PMIX_LIST_DESTRUCT(&pmix_mca_psensor_heartbeat_component.trackers); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/psensor/psensor.h0000664000175000017500000000465415203536752020370 0ustar alastairalastair/* * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * @file: * */ #ifndef PMIX_PSENSOR_H_ #define PMIX_PSENSOR_H_ #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/mca/mca.h" BEGIN_C_DECLS /* * Component functions - all MUST be provided! */ /* start a sensor operation: * * requestor - the process requesting this operation * * monitor - a PMIx attribute specifying what is to be monitored * * directives - an array of pmix_info_t specifying relevant limits on values, and action * to be taken when limits exceeded. Can include * user-provided "id" string */ typedef pmix_status_t (*pmix_psensor_base_module_start_fn_t)(pmix_peer_t *requestor, pmix_status_t error, const pmix_info_t *monitor, const pmix_info_t directives[], size_t ndirs); /* stop a sensor operation: * * requestor - the process requesting this operation * * id - the "id" string provided by the user at the time the * affected monitoring operation was started. A NULL indicates * that all operations started by this requestor are to * be terminated */ typedef pmix_status_t (*pmix_psensor_base_module_stop_fn_t)(pmix_peer_t *requestor, char *id); /* API module */ /* * Ver 1.0 */ typedef struct pmix_psensor_base_module_1_0_0_t { pmix_psensor_base_module_start_fn_t start; pmix_psensor_base_module_stop_fn_t stop; } pmix_psensor_base_module_t; /* * the standard component data structure */ typedef pmix_mca_base_component_t pmix_psensor_base_component_t; /* * Macro for use in components that are of type sensor v1.0.0 */ #define PMIX_PSENSOR_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("psensor", 1, 0, 0) /* Global structure for accessing sensor functions */ PMIX_EXPORT extern pmix_psensor_base_module_t pmix_psensor; /* holds API function pointers */ END_C_DECLS #endif /* MCA_SENSOR_H */ pmix-6.1.1~rc2/src/mca/psensor/base/0000775000175000017500000000000015203536752017427 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/psensor/base/psensor_base_select.c0000664000175000017500000000722515203536752023623 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/mca/psensor/base/base.h" /* Function for selecting a prioritized list of components * from all those that are available. */ int pmix_psensor_base_select(void) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_psensor_base_component_t *component = NULL; pmix_psensor_active_module_t *newactive, *active; pmix_mca_base_module_t *mod; int pri; bool inserted; if (pmix_psensor_base.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_psensor_base.selected = true; /* Query all available components and ask if they have a module */ PMIX_LIST_FOREACH (cli, &pmix_psensor_base_framework.framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_psensor_base_component_t *) cli->cli_component; pmix_output_verbose(5, pmix_psensor_base_framework.framework_output, "mca:psensor:select: checking available component %s", component->pmix_mca_component_name); /* get the module for this component */ if (PMIX_SUCCESS != component->pmix_mca_query_component(&mod, &pri)) { continue; } /* add to our prioritized list of available actives */ newactive = PMIX_NEW(pmix_psensor_active_module_t); newactive->priority = pri; newactive->component = component; newactive->module = (pmix_psensor_base_module_t *) mod; /* maintain priority order */ inserted = false; PMIX_LIST_FOREACH (active, &pmix_psensor_base.actives, pmix_psensor_active_module_t) { if (newactive->priority > active->priority) { pmix_list_insert_pos(&pmix_psensor_base.actives, (pmix_list_item_t *) active, &newactive->super); inserted = true; break; } } if (!inserted) { /* must be lowest priority - add to end */ pmix_list_append(&pmix_psensor_base.actives, &newactive->super); } } if (4 < pmix_output_get_verbosity(pmix_psensor_base_framework.framework_output)) { pmix_output(0, "Final PSENSOR priorities"); /* show the prioritized list */ PMIX_LIST_FOREACH (active, &pmix_psensor_base.actives, pmix_psensor_active_module_t) { pmix_output(0, "\tPSENSOR: %s Priority: %d", active->component->pmix_mca_component_name, active->priority); } } return PMIX_SUCCESS; ; } pmix-6.1.1~rc2/src/mca/psensor/base/psensor_base_stubs.c0000664000175000017500000000510515203536752023477 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/util/pmix_error.h" #include "src/mca/psensor/base/base.h" pmix_status_t pmix_psensor_base_start(pmix_peer_t *requestor, pmix_status_t error, const pmix_info_t *monitor, const pmix_info_t directives[], size_t ndirs) { pmix_psensor_active_module_t *mod; pmix_status_t rc; bool didit = false; pmix_output_verbose(5, pmix_psensor_base_framework.framework_output, "%s:%d sensor:base: starting sensors", pmix_globals.myid.nspace, pmix_globals.myid.rank); /* call the start function of all modules in priority order */ PMIX_LIST_FOREACH (mod, &pmix_psensor_base.actives, pmix_psensor_active_module_t) { if (NULL != mod->module->start) { rc = mod->module->start(requestor, error, monitor, directives, ndirs); if (PMIX_SUCCESS != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { return rc; } didit = true; } } /* if none of the components could do it, then report * not supported upwards so the server knows to ask * the host to try */ if (!didit) { return PMIX_ERR_NOT_SUPPORTED; } return PMIX_SUCCESS; } pmix_status_t pmix_psensor_base_stop(pmix_peer_t *requestor, char *id) { pmix_psensor_active_module_t *mod; pmix_status_t rc, ret = PMIX_SUCCESS; pmix_output_verbose(5, pmix_psensor_base_framework.framework_output, "%s:%d sensor:base: stopping sensors", pmix_globals.myid.nspace, pmix_globals.myid.rank); /* call the stop function of all modules in priority order */ PMIX_LIST_FOREACH (mod, &pmix_psensor_base.actives, pmix_psensor_active_module_t) { if (NULL != mod->module->stop) { rc = mod->module->stop(requestor, id); if (PMIX_SUCCESS != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { if (PMIX_SUCCESS == ret) { ret = rc; } /* need to continue to ensure that all * sensors have been stopped */ } } } return ret; } pmix-6.1.1~rc2/src/mca/psensor/base/psensor_base_frame.c0000664000175000017500000000660315203536752023435 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include #include "src/class/pmix_list.h" #include "src/include/pmix_types.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/runtime/pmix_progress_threads.h" #include "src/mca/psensor/base/base.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public mca_base_component_t struct. */ #include "src/mca/psensor/base/static-components.h" /* * Global variables */ pmix_psensor_base_module_t pmix_psensor = { .start = pmix_psensor_base_start, .stop = pmix_psensor_base_stop }; pmix_psensor_base_t pmix_psensor_base = { .actives = PMIX_LIST_STATIC_INIT, .evbase = NULL, .selected = false }; static bool use_separate_thread = false; static int pmix_psensor_register(pmix_mca_base_register_flag_t flags) { (void) flags; (void) pmix_mca_base_var_register("pmix", "psensor", "base", "use_separate_thread", "Use a separate thread for monitoring local procs", PMIX_MCA_BASE_VAR_TYPE_BOOL, &use_separate_thread); return PMIX_SUCCESS; } static int pmix_psensor_base_close(void) { pmix_psensor_base.selected = false; PMIX_LIST_DESTRUCT(&pmix_psensor_base.actives); if (use_separate_thread && NULL != pmix_psensor_base.evbase) { (void) pmix_progress_thread_stop("PSENSOR"); } /* Close all remaining available components */ return pmix_mca_base_framework_components_close(&pmix_psensor_base_framework, NULL); } /** * Function for finding and opening either all MCA components, or the one * that was specifically requested via a MCA parameter. */ static int pmix_psensor_base_open(pmix_mca_base_open_flag_t flags) { /* construct the list of modules */ PMIX_CONSTRUCT(&pmix_psensor_base.actives, pmix_list_t); if (use_separate_thread) { /* create an event base and progress thread for us */ pmix_psensor_base.evbase = pmix_progress_thread_init("PSENSOR"); if (NULL == pmix_psensor_base.evbase) { return PMIX_ERROR; } } else { pmix_psensor_base.evbase = pmix_globals.evbase; } /* Open up all available components */ return pmix_mca_base_framework_components_open(&pmix_psensor_base_framework, flags); } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, psensor, "PMIx Monitoring Sensors", pmix_psensor_register, pmix_psensor_base_open, pmix_psensor_base_close, pmix_mca_psensor_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); PMIX_CLASS_INSTANCE(pmix_psensor_active_module_t, pmix_list_item_t, NULL, NULL); pmix-6.1.1~rc2/src/mca/psensor/base/base.h0000664000175000017500000000334615203536752020520 0ustar alastairalastair/* * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2013 Los Alamos National Security, LLC. All rights reserved. * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: */ #ifndef PMIX_PSENSOR_BASE_H_ #define PMIX_PSENSOR_BASE_H_ #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/mca.h" #include "src/mca/psensor/psensor.h" BEGIN_C_DECLS /* * MCA Framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_psensor_base_framework; PMIX_EXPORT int pmix_psensor_base_select(void); /* define a struct to hold framework-global values */ typedef struct { pmix_list_t actives; pmix_event_base_t *evbase; bool selected; } pmix_psensor_base_t; typedef struct { pmix_list_item_t super; pmix_psensor_base_component_t *component; pmix_psensor_base_module_t *module; int priority; } pmix_psensor_active_module_t; PMIX_CLASS_DECLARATION(pmix_psensor_active_module_t); PMIX_EXPORT extern pmix_psensor_base_t pmix_psensor_base; PMIX_EXPORT pmix_status_t pmix_psensor_base_start(pmix_peer_t *requestor, pmix_status_t error, const pmix_info_t *monitor, const pmix_info_t directives[], size_t ndirs); PMIX_EXPORT pmix_status_t pmix_psensor_base_stop(pmix_peer_t *requestor, char *id); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/psensor/base/Makefile.am0000664000175000017500000000070515203536752021465 0ustar alastairalastair# # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. # # Copyright (c) 2017 Intel, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers += \ base/base.h libmca_psensor_la_SOURCES += \ base/psensor_base_frame.c \ base/psensor_base_select.c \ base/psensor_base_stubs.c pmix-6.1.1~rc2/src/mca/psensor/Makefile.am0000664000175000017500000000117015203536752020550 0ustar alastairalastair# # Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved. # # Copyright (c) 2017 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(LTDLINCL) # main library setup noinst_LTLIBRARIES = libmca_psensor.la libmca_psensor_la_SOURCES = # local files headers = psensor.h libmca_psensor_la_SOURCES += $(headers) # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.am distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/pcompress/0000775000175000017500000000000015203536752017037 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pcompress/owner.txt0000664000175000017500000000024415203536752020732 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner:project status:maintenance pmix-6.1.1~rc2/src/mca/pcompress/zlibng/0000775000175000017500000000000015203536752020324 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pcompress/zlibng/owner.txt0000664000175000017500000000024415203536752022217 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner:project status:maintenance pmix-6.1.1~rc2/src/mca/pcompress/zlibng/compress_zlibng.c0000664000175000017500000001475315203536752023702 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * * Copyright (c) 2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018 Amazon.com, Inc. or its affiliates. All Rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include #include #include #if HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #include #include "src/include/pmix_stdint.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "pmix_common.h" #include "src/util/pmix_basename.h" #include "src/mca/pcompress/base/base.h" #include "compress_zlibng.h" static bool zlibng_compress(const uint8_t *inbytes, size_t inlen, uint8_t **outbytes, size_t *outlen); static bool zlibng_decompress(uint8_t **outbytes, size_t *outlen, const uint8_t *inbytes, size_t inlen); static bool compress_string(char *instring, uint8_t **outbytes, size_t *nbytes); static bool decompress_string(char **outstring, uint8_t *inbytes, size_t len); pmix_compress_base_module_t pmix_pcompress_zlibng_module = { .compress = zlibng_compress, .decompress = zlibng_decompress, .compress_string = compress_string, .decompress_string = decompress_string, }; static bool zlibng_compress(const uint8_t *inbytes, size_t inlen, uint8_t **outbytes, size_t *outlen) { zng_stream strm; size_t len, len2; uint8_t *tmp, *ptr; uint32_t len3; int rc; /* set default output */ *outbytes = NULL; *outlen = 0; if (inlen < pmix_compress_base.compress_limit || inlen >= UINT32_MAX) { return false; } len3 = inlen; /* setup the stream */ memset(&strm, 0, sizeof(strm)); if (Z_OK != zng_deflateInit(&strm, 9)) { return false; } /* get an upper bound on the required output storage */ len = zng_deflateBound(&strm, inlen); if (NULL == (tmp = (uint8_t *) malloc(len))) { (void) zng_deflateEnd(&strm); return false; } strm.next_in = (uint8_t*)inbytes; strm.avail_in = inlen; /* allocating the upper bound guarantees zlibng will * always successfully compress into the available space */ strm.avail_out = len; strm.next_out = tmp; rc = zng_deflate(&strm, Z_FINISH); (void) zng_deflateEnd(&strm); if (Z_STREAM_END != rc) { free(tmp); return false; } /* allocate 4 bytes beyond the size reqd by zlibng so we * can pass the size of the uncompressed block to the * decompress side */ len2 = len - strm.avail_out + sizeof(uint32_t); /* if this isn't going to result in a smaller footprint, * then don't do it */ if (len2 >= inlen) { free(tmp); return false; } ptr = (uint8_t *) malloc(len2); if (NULL == ptr) { free(tmp); return false; } *outbytes = ptr; *outlen = len2; /* fold the uncompressed length into the buffer */ memcpy(ptr, &len3, sizeof(uint32_t)); ptr += sizeof(uint32_t); /* bring over the compressed data */ memcpy(ptr, tmp, len2 - sizeof(uint32_t)); free(tmp); pmix_output_verbose(2, pmix_pcompress_base_framework.framework_output, "COMPRESS INPUT BLOCK OF LEN %" PRIsize_t " OUTPUT SIZE %" PRIsize_t "", inlen, len2 - sizeof(uint32_t)); return true; // we did the compression } static bool compress_string(char *instring, uint8_t **outbytes, size_t *nbytes) { uint32_t inlen; /* setup the stream */ inlen = strlen(instring); /* compress the string */ return zlibng_compress((uint8_t *) instring, inlen, outbytes, nbytes); } static bool doit(uint8_t **outbytes, size_t len2, const uint8_t *inbytes, size_t inlen) { uint8_t *dest; zng_stream strm; int rc; /* set the default error answer */ *outbytes = NULL; /* setting destination to the fully decompressed size */ dest = (uint8_t *) malloc(len2); if (NULL == dest) { return false; } memset(dest, 0, len2); memset(&strm, 0, sizeof(strm)); if (Z_OK != zng_inflateInit(&strm)) { free(dest); return false; } strm.avail_in = inlen; strm.next_in = (uint8_t*)inbytes; strm.avail_out = len2; strm.next_out = dest; rc = zng_inflate(&strm, Z_FINISH); zng_inflateEnd(&strm); if (Z_STREAM_END == rc) { *outbytes = dest; return true; } free(dest); return false; } static bool zlibng_decompress(uint8_t **outbytes, size_t *outlen, const uint8_t *inbytes, size_t inlen) { uint32_t len2, input_len; bool rc; uint8_t *input; /* set the default error answer */ *outlen = 0; /* the first 4 bytes contains the uncompressed size */ memcpy(&len2, inbytes, sizeof(uint32_t)); pmix_output_verbose(2, pmix_pcompress_base_framework.framework_output, "DECOMPRESSING INPUT OF LEN %" PRIsize_t " OUTPUT %u", inlen, len2); input = (uint8_t *) (inbytes + sizeof(uint32_t)); // step over the size input_len = inlen - sizeof(uint32_t); rc = doit(outbytes, len2, input, input_len); if (rc) { *outlen = len2; return true; } return false; } static bool decompress_string(char **outstring, uint8_t *inbytes, size_t len) { uint32_t len2, input_len; bool rc; uint8_t *input; /* the first 4 bytes contains the uncompressed size */ memcpy(&len2, inbytes, sizeof(uint32_t)); if (len2 == UINT32_MAX) { /* set the default error answer */ *outstring = NULL; return false; } /* add one to hold the NUL terminator */ ++len2; /* decompress the bytes */ input = (uint8_t *) (inbytes + sizeof(uint32_t)); // step over the size input_len = len - sizeof(uint32_t); rc = doit((uint8_t **) outstring, len2, input, input_len); if (rc) { /* ensure this is NUL terminated! */ (*outstring)[len2 - 1] = '\0'; return true; } /* set the default error answer */ *outstring = NULL; return false; } pmix-6.1.1~rc2/src/mca/pcompress/zlibng/configure.m40000664000175000017500000000436515203536752022557 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2013 Los Alamos National Security, LLC. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2024 Nanook Consulting All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_pcompress_zlibng_CONFIG([action-if-can-compile], # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pcompress_zlibng_CONFIG],[ AC_CONFIG_FILES([src/mca/pcompress/zlibng/Makefile]) AC_ARG_WITH([zlibng], [AS_HELP_STRING([--with-zlibng=DIR], [Search for zlib-ng headers and libraries in DIR ])]) AC_ARG_WITH([zlibng-libdir], [AS_HELP_STRING([--with-zlibng-libdir=DIR], [Search for zlib-ng libraries in DIR ])]) pmix_zlibng_support=0 OAC_CHECK_PACKAGE([zlibng], [pcompress_zlibng], [zlib-ng.h], [z-ng], [zng_deflate], [pmix_zlibng_support=1], [pmix_zlibng_support=0]) if test ! -z "$with_zlibng" && test "$with_zlibng" != "no" && test "$pmix_zlibng_support" != "1"; then AC_MSG_WARN([ZLIB-NG SUPPORT REQUESTED AND NOT FOUND]) AC_MSG_ERROR([CANNOT CONTINUE]) fi AC_MSG_CHECKING([will zlib-ng support be built]) AS_IF([test "$pmix_zlibng_support" = "1"], [$1 AC_MSG_RESULT([yes])], [$2 AC_MSG_RESULT([no])]) PMIX_SUMMARY_ADD([External Packages], [ZLIBNG], [], [${pcompress_zlibng_SUMMARY}]) # substitute in the things needed to build pcompress/zlibng AC_SUBST([pcompress_zlibng_CPPFLAGS]) AC_SUBST([pcompress_zlibng_LDFLAGS]) AC_SUBST([pcompress_zlibng_LIBS]) PMIX_EMBEDDED_LIBS="$PMIX_EMBEDDED_LIBS $pcompress_zlibng_LIBS" PMIX_EMBEDDED_LDFLAGS="$PMIX_EMBEDDED_LDFLAGS $pcompress_zlibng_LDFLAGS" PMIX_EMBEDDED_CPPFLAGS="$PMIX_EMBEDDED_CPPFLAGS $pcompress_zlibng_CPPFLAGS" ])dnl pmix-6.1.1~rc2/src/mca/pcompress/zlibng/compress_zlibng_component.c0000664000175000017500000000344015203536752025753 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "compress_zlibng.h" #include "pmix_common.h" #include "src/mca/pcompress/base/base.h" /* * Public string for version number */ const char *pmix_compress_zlibng_component_version_string = "PMIX COMPRESS zlibng MCA component version " PMIX_VERSION; /* * Local functionality */ static int compress_zlibng_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointer to our public functions in it */ PMIX_EXPORT pmix_mca_base_component_t pmix_mca_pcompress_zlibng_component = { /* Handle the general mca_component_t struct containing * meta information about the component zlibng */ PMIX_COMPRESS_BASE_VERSION_2_0_0, /* Component name and version */ .pmix_mca_component_name = "zlibng", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_query_component = compress_zlibng_query }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pcompress, zlibng) static int compress_zlibng_query(pmix_mca_base_module_t **module, int *priority) { *module = (pmix_mca_base_module_t *) &pmix_pcompress_zlibng_module; *priority = 75; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pcompress/zlibng/Makefile.am0000664000175000017500000000303015203536752022354 0ustar alastairalastair# # Copyright (c) 2004-2010 The Trustees of Indiana University. # All rights reserved. # Copyright (c) 2014-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017 IBM Corporation. All rights reserved. # Copyright (c) 2019 Intel, Inc. All rights reserved. # Copyright (c) 2022-2024 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(pcompress_zlibng_CPPFLAGS) sources = \ compress_zlibng.h \ compress_zlibng_component.c \ compress_zlibng.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pcompress_zlibng_DSO component_noinst = component_install = pmix_mca_pcompress_zlibng.la else component_noinst = libpmix_mca_pcompress_zlibng.la component_install = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component_install) pmix_mca_pcompress_zlibng_la_SOURCES = $(sources) pmix_mca_pcompress_zlibng_la_LDFLAGS = -module -avoid-version $(pcompress_zlibng_LDFLAGS) pmix_mca_pcompress_zlibng_la_LIBADD = $(pcompress_zlibng_LIBS) if NEED_LIBPMIX pmix_mca_pcompress_zlibng_la_LIBADD += $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(component_noinst) libpmix_mca_pcompress_zlibng_la_SOURCES = $(sources) libpmix_mca_pcompress_zlibng_la_LDFLAGS = -module -avoid-version $(pcompress_zlibng_LDFLAGS) libpmix_mca_pcompress_zlibng_la_LIBADD = $(pcompress_zlibng_LIBS) pmix-6.1.1~rc2/src/mca/pcompress/zlibng/compress_zlibng.h0000664000175000017500000000173015203536752023676 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2022-2024 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * ZLIBNG COMPRESS component * * Uses the zlib-ng library */ #ifndef MCA_COMPRESS_ZLIBNG_EXPORT_H #define MCA_COMPRESS_ZLIBNG_EXPORT_H #include "pmix_config.h" #include "src/util/pmix_output.h" #include "src/mca/mca.h" #include "src/mca/pcompress/pcompress.h" #if defined(c_plusplus) || defined(__cplusplus) extern "C" { #endif /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_mca_base_component_t pmix_mca_pcompress_zlibng_component; extern pmix_compress_base_module_t pmix_pcompress_zlibng_module; #if defined(c_plusplus) || defined(__cplusplus) } #endif #endif /* MCA_COMPRESS_ZLIBNG_EXPORT_H */ pmix-6.1.1~rc2/src/mca/pcompress/base/0000775000175000017500000000000015203536752017751 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pcompress/base/owner.txt0000664000175000017500000000024415203536752021644 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner:project status:maintenance pmix-6.1.1~rc2/src/mca/pcompress/base/pcompress_base_frame.c0000664000175000017500000001015415203536752024275 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "src/include/pmix_globals.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pcompress/base/base.h" #include "src/mca/pcompress/base/static-components.h" #include "src/mca/ptl/ptl_types.h" #include "src/util/pmix_show_help.h" /* * Globals */ static bool compress_block(const uint8_t *inblock, size_t size, uint8_t **outbytes, size_t *nbytes) { (void) inblock; (void) size; (void) outbytes; (void) nbytes; if (!pmix_compress_base.silent && !PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) { pmix_show_help("help-pcompress.txt", "unavailable", true); pmix_compress_base.silent = true; } return false; } static bool decompress_block(uint8_t **outbytes, size_t *outlen, const uint8_t *inbytes, size_t len) { (void) outbytes; (void) outlen; (void) inbytes; (void) len; return false; } static bool compress_string(char *instring, uint8_t **outbytes, size_t *nbytes) { (void) instring; (void) outbytes; (void) nbytes; if (!pmix_compress_base.silent && !PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) { pmix_show_help("help-pcompress.txt", "unavailable", true); pmix_compress_base.silent = true; } return false; } static bool decompress_string(char **outstring, uint8_t *inbytes, size_t len) { (void) outstring; (void) inbytes; (void) len; return false; } pmix_compress_base_module_t pmix_compress = { .compress = compress_block, .decompress = decompress_block, .compress_string = compress_string, .decompress_string = decompress_string }; pmix_compress_base_t pmix_compress_base = { .compress_limit = 0, .selected = false, .silent = false }; static int pmix_compress_base_register(pmix_mca_base_register_flag_t flags) { (void) flags; pmix_compress_base.compress_limit = 4096; (void) pmix_mca_base_var_register("pmix", "pcompress", "base", "limit", "Threshold beyond which data will be compressed", PMIX_MCA_BASE_VAR_TYPE_SIZE_T, &pmix_compress_base.compress_limit); pmix_compress_base.silent = false; (void) pmix_mca_base_var_register("pmix", "pcompress", "base", "silence_warning", "Do not warn if compression unavailable", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_compress_base.silent); return PMIX_SUCCESS; } /** * Function for finding and opening either all MCA components, * or the one that was specifically requested via a MCA parameter. */ static int pmix_compress_base_open(pmix_mca_base_open_flag_t flags) { /* Open up all available components */ return pmix_mca_base_framework_components_open(&pmix_pcompress_base_framework, flags); } static int pmix_compress_base_close(void) { pmix_compress_base.selected = false; /* Call the component's finalize routine */ if (NULL != pmix_compress.finalize) { pmix_compress.finalize(); } /* Close all available modules that are open */ return pmix_mca_base_framework_components_close(&pmix_pcompress_base_framework, NULL); } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, pcompress, "PCOMPRESS MCA", pmix_compress_base_register, pmix_compress_base_open, pmix_compress_base_close, pmix_mca_pcompress_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); pmix-6.1.1~rc2/src/mca/pcompress/base/pcompress_base_select.c0000664000175000017500000000401015203536752024454 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #ifdef HAVE_UNISTD_H # include "unistd.h" #endif #include "pmix_common.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/mca/pcompress/base/base.h" #include "src/util/pmix_output.h" int pmix_compress_base_select(void) { int ret = PMIX_SUCCESS; pmix_mca_base_component_t *best_component = NULL; pmix_compress_base_module_t *best_module = NULL; if (pmix_compress_base.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_compress_base.selected = true; /* * Select the best component */ if (PMIX_SUCCESS != pmix_mca_base_select("pcompress", pmix_pcompress_base_framework.framework_output, &pmix_pcompress_base_framework.framework_components, (pmix_mca_base_module_t **) &best_module, (pmix_mca_base_component_t **) &best_component, NULL)) { /* This will only happen if no component was selected, * in which case we use the default one */ goto cleanup; } /* Initialize the winner */ if (NULL != best_module) { if (NULL != best_module->init) { if (PMIX_SUCCESS != (ret = best_module->init())) { goto cleanup; } } pmix_compress = *best_module; } cleanup: return ret; } pmix-6.1.1~rc2/src/mca/pcompress/base/base.h0000664000175000017500000000615715203536752021045 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_COMPRESS_BASE_H #define PMIX_COMPRESS_BASE_H #include "pmix_config.h" #include "src/mca/pcompress/pcompress.h" #include "src/util/pmix_environ.h" #include "src/mca/base/pmix_base.h" /* * Global functions for MCA overall COMPRESS */ #if defined(c_plusplus) || defined(__cplusplus) extern "C" { #endif /* define a macro for quickly checking if a string exceeds the * compression limit */ #define PMIX_STRING_SIZE_CHECK(s) \ (PMIX_STRING == (s)->type && NULL != (s)->data.string \ && pmix_compress_base.compress_limit < strlen((s)->data.string)) #define PMIX_VALUE_COMPRESSED_STRING_UNPACK(s) \ do { \ char *tmp; \ /* if this is a compressed string, then uncompress it */ \ if (PMIX_COMPRESSED_STRING == (s)->type) { \ pmix_compress.decompress_string(&tmp, (uint8_t *) (s)->data.bo.bytes, \ (s)->data.bo.size); \ if (NULL == tmp) { \ PMIX_ERROR_LOG(PMIX_ERR_NOMEM); \ rc = PMIX_ERR_NOMEM; \ PMIX_VALUE_RELEASE(s); \ val = NULL; \ } else { \ PMIX_VALUE_DESTRUCT(s); \ (s)->data.string = tmp; \ (s)->type = PMIX_STRING; \ } \ } \ } while (0) typedef struct { size_t compress_limit; bool selected; bool silent; } pmix_compress_base_t; PMIX_EXPORT extern pmix_compress_base_t pmix_compress_base; /** * Select an available component. * * @retval OPAL_SUCCESS Upon Success * @retval OPAL_NOT_FOUND If no component can be selected * @retval OPAL_ERROR Upon other failure * */ PMIX_EXPORT int pmix_compress_base_select(void); /** * Globals */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_pcompress_base_framework; PMIX_EXPORT extern pmix_compress_base_module_t pmix_compress; #if defined(c_plusplus) || defined(__cplusplus) } #endif #endif /* PMIX_COMPRESS_BASE_H */ pmix-6.1.1~rc2/src/mca/pcompress/base/Makefile.am0000664000175000017500000000117115203536752022005 0ustar alastairalastair# # Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2019 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers += \ base/base.h libmca_pcompress_la_SOURCES += \ base/pcompress_base_frame.c \ base/pcompress_base_select.c EXTRA_DIST = base/help-pcompress.txt pmix-6.1.1~rc2/src/mca/pcompress/base/help-pcompress.txt0000664000175000017500000000132515203536752023454 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2021 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is a US/English help file # [unavailable] PMIx was unable to find a usable compression library on the system. We will therefore be unable to compress large data streams. This may result in longer-than-normal startup times and larger memory footprints. We will continue, but strongly recommend installing zlib or a comparable compression library for better user experience. You can suppress this warning by adding "pcompress_base_silence_warning=1" to your PMIx MCA default parameter file, or by adding "PMIX_MCA_pcompress_base_silence_warning=1" to your environment. pmix-6.1.1~rc2/src/mca/pcompress/zlib/0000775000175000017500000000000015203536752017777 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pcompress/zlib/owner.txt0000664000175000017500000000024415203536752021672 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner:project status:maintenance pmix-6.1.1~rc2/src/mca/pcompress/zlib/compress_zlib.c0000664000175000017500000001465515203536752023031 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * * Copyright (c) 2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018 Amazon.com, Inc. or its affiliates. All Rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include #include #include #if HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #include #include "src/include/pmix_stdint.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "pmix_common.h" #include "src/util/pmix_basename.h" #include "src/mca/pcompress/base/base.h" #include "compress_zlib.h" static bool zlib_compress(const uint8_t *inbytes, size_t inlen, uint8_t **outbytes, size_t *outlen); static bool zlib_decompress(uint8_t **outbytes, size_t *outlen, const uint8_t *inbytes, size_t inlen); static bool compress_string(char *instring, uint8_t **outbytes, size_t *nbytes); static bool decompress_string(char **outstring, uint8_t *inbytes, size_t len); pmix_compress_base_module_t pmix_pcompress_zlib_module = { .compress = zlib_compress, .decompress = zlib_decompress, .compress_string = compress_string, .decompress_string = decompress_string, }; static bool zlib_compress(const uint8_t *inbytes, size_t inlen, uint8_t **outbytes, size_t *outlen) { z_stream strm; size_t len, len2; uint8_t *tmp, *ptr; uint32_t len3; int rc; /* set default output */ *outbytes = NULL; *outlen = 0; if (inlen < pmix_compress_base.compress_limit || inlen >= UINT32_MAX) { return false; } len3 = inlen; /* setup the stream */ memset(&strm, 0, sizeof(strm)); if (Z_OK != deflateInit(&strm, 9)) { return false; } /* get an upper bound on the required output storage */ len = deflateBound(&strm, inlen); if (NULL == (tmp = (uint8_t *) malloc(len))) { (void) deflateEnd(&strm); return false; } strm.next_in = (uint8_t*)inbytes; strm.avail_in = inlen; /* allocating the upper bound guarantees zlib will * always successfully compress into the available space */ strm.avail_out = len; strm.next_out = tmp; rc = deflate(&strm, Z_FINISH); (void) deflateEnd(&strm); if (Z_STREAM_END != rc) { free(tmp); return false; } /* allocate 4 bytes beyond the size reqd by zlib so we * can pass the size of the uncompressed block to the * decompress side */ len2 = len - strm.avail_out + sizeof(uint32_t); /* if this isn't going to result in a smaller footprint, * then don't do it */ if (len2 >= inlen) { free(tmp); return false; } ptr = (uint8_t *) malloc(len2); if (NULL == ptr) { free(tmp); return false; } *outbytes = ptr; *outlen = len2; /* fold the uncompressed length into the buffer */ memcpy(ptr, &len3, sizeof(uint32_t)); ptr += sizeof(uint32_t); /* bring over the compressed data */ memcpy(ptr, tmp, len2 - sizeof(uint32_t)); free(tmp); pmix_output_verbose(2, pmix_pcompress_base_framework.framework_output, "COMPRESS INPUT BLOCK OF LEN %" PRIsize_t " OUTPUT SIZE %" PRIsize_t "", inlen, len2 - sizeof(uint32_t)); return true; // we did the compression } static bool compress_string(char *instring, uint8_t **outbytes, size_t *nbytes) { uint32_t inlen; /* setup the stream */ inlen = strlen(instring); /* compress the string */ return zlib_compress((uint8_t *) instring, inlen, outbytes, nbytes); } static bool doit(uint8_t **outbytes, size_t len2, const uint8_t *inbytes, size_t inlen) { uint8_t *dest; z_stream strm; int rc; /* set the default error answer */ *outbytes = NULL; /* setting destination to the fully decompressed size */ dest = (uint8_t *) malloc(len2); if (NULL == dest) { return false; } memset(dest, 0, len2); memset(&strm, 0, sizeof(strm)); if (Z_OK != inflateInit(&strm)) { free(dest); return false; } strm.avail_in = inlen; strm.next_in = (uint8_t*)inbytes; strm.avail_out = len2; strm.next_out = dest; rc = inflate(&strm, Z_FINISH); inflateEnd(&strm); if (Z_STREAM_END == rc) { *outbytes = dest; return true; } free(dest); return false; } static bool zlib_decompress(uint8_t **outbytes, size_t *outlen, const uint8_t *inbytes, size_t inlen) { uint32_t len2, input_len; bool rc; uint8_t *input; /* set the default error answer */ *outlen = 0; /* the first 4 bytes contains the uncompressed size */ memcpy(&len2, inbytes, sizeof(uint32_t)); pmix_output_verbose(2, pmix_pcompress_base_framework.framework_output, "DECOMPRESSING INPUT OF LEN %" PRIsize_t " OUTPUT %u", inlen, len2); input = (uint8_t *) (inbytes + sizeof(uint32_t)); // step over the size input_len = inlen - sizeof(uint32_t); rc = doit(outbytes, len2, input, input_len); if (rc) { *outlen = len2; return true; } return false; } static bool decompress_string(char **outstring, uint8_t *inbytes, size_t len) { uint32_t len2, input_len; bool rc; uint8_t *input; /* the first 4 bytes contains the uncompressed size */ memcpy(&len2, inbytes, sizeof(uint32_t)); if (len2 == UINT32_MAX) { /* set the default error answer */ *outstring = NULL; return false; } /* add one to hold the NUL terminator */ ++len2; /* decompress the bytes */ input = (uint8_t *) (inbytes + sizeof(uint32_t)); // step over the size input_len = len - sizeof(uint32_t); rc = doit((uint8_t **) outstring, len2, input, input_len); if (rc) { /* ensure this is NUL terminated! */ (*outstring)[len2 - 1] = '\0'; return true; } /* set the default error answer */ *outstring = NULL; return false; } pmix-6.1.1~rc2/src/mca/pcompress/zlib/configure.m40000664000175000017500000000425515203536752022230 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2013 Los Alamos National Security, LLC. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2024 Nanook Consulting All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_pcompress_zlib_CONFIG([action-if-can-compile], # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pcompress_zlib_CONFIG],[ AC_CONFIG_FILES([src/mca/pcompress/zlib/Makefile]) AC_ARG_WITH([zlib], [AS_HELP_STRING([--with-zlib=DIR], [Search for zlib headers and libraries in DIR ])]) AC_ARG_WITH([zlib-libdir], [AS_HELP_STRING([--with-zlib-libdir=DIR], [Search for zlib libraries in DIR ])]) pmix_zlib_support=0 OAC_CHECK_PACKAGE([zlib], [pcompress_zlib], [zlib.h], [z], [deflate], [pmix_zlib_support=1], [pmix_zlib_support=0]) if test ! -z "$with_zlib" && test "$with_zlib" != "no" && test "$pmix_zlib_support" != "1"; then AC_MSG_WARN([ZLIB SUPPORT REQUESTED AND NOT FOUND]) AC_MSG_ERROR([CANNOT CONTINUE]) fi AC_MSG_CHECKING([will zlib support be built]) AS_IF([test "$pmix_zlib_support" = "1"], [$1 AC_MSG_RESULT([yes])], [$2 AC_MSG_RESULT([no])]) PMIX_SUMMARY_ADD([External Packages], [ZLIB], [], [${pcompress_zlib_SUMMARY}]) # substitute in the things needed to build pcompress/zlib AC_SUBST([pcompress_zlib_CPPFLAGS]) AC_SUBST([pcompress_zlib_LDFLAGS]) AC_SUBST([pcompress_zlib_LIBS]) PMIX_EMBEDDED_LIBS="$PMIX_EMBEDDED_LIBS $pcompress_zlib_LIBS" PMIX_EMBEDDED_LDFLAGS="$PMIX_EMBEDDED_LDFLAGS $pcompress_zlib_LDFLAGS" PMIX_EMBEDDED_CPPFLAGS="$PMIX_EMBEDDED_CPPFLAGS $pcompress_zlib_CPPFLAGS" ])dnl pmix-6.1.1~rc2/src/mca/pcompress/zlib/compress_zlib.h0000664000175000017500000000171215203536752023024 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * ZLIB COMPRESS component * * Uses the zlib library */ #ifndef MCA_COMPRESS_ZLIB_EXPORT_H #define MCA_COMPRESS_ZLIB_EXPORT_H #include "pmix_config.h" #include "src/util/pmix_output.h" #include "src/mca/mca.h" #include "src/mca/pcompress/pcompress.h" #if defined(c_plusplus) || defined(__cplusplus) extern "C" { #endif /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_mca_base_component_t pmix_mca_pcompress_zlib_component; extern pmix_compress_base_module_t pmix_pcompress_zlib_module; #if defined(c_plusplus) || defined(__cplusplus) } #endif #endif /* MCA_COMPRESS_ZLIB_EXPORT_H */ pmix-6.1.1~rc2/src/mca/pcompress/zlib/Makefile.am0000664000175000017500000000276515203536752022045 0ustar alastairalastair# # Copyright (c) 2004-2010 The Trustees of Indiana University. # All rights reserved. # Copyright (c) 2014-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017 IBM Corporation. All rights reserved. # Copyright (c) 2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(pcompress_zlib_CPPFLAGS) sources = \ compress_zlib.h \ compress_zlib_component.c \ compress_zlib.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pcompress_zlib_DSO component_noinst = component_install = pmix_mca_pcompress_zlib.la else component_noinst = libpmix_mca_pcompress_zlib.la component_install = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component_install) pmix_mca_pcompress_zlib_la_SOURCES = $(sources) pmix_mca_pcompress_zlib_la_LDFLAGS = -module -avoid-version $(pcompress_zlib_LDFLAGS) pmix_mca_pcompress_zlib_la_LIBADD = $(pcompress_zlib_LIBS) if NEED_LIBPMIX pmix_mca_pcompress_zlib_la_LIBADD += $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(component_noinst) libpmix_mca_pcompress_zlib_la_SOURCES = $(sources) libpmix_mca_pcompress_zlib_la_LDFLAGS = -module -avoid-version $(pcompress_zlib_LDFLAGS) libpmix_mca_pcompress_zlib_la_LIBADD = $(pcompress_zlib_LIBS) pmix-6.1.1~rc2/src/mca/pcompress/zlib/compress_zlib_component.c0000664000175000017500000000341215203536752025100 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2010 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "compress_zlib.h" #include "pmix_common.h" #include "src/mca/pcompress/base/base.h" /* * Public string for version number */ const char *pmix_compress_zlib_component_version_string = "PMIX COMPRESS zlib MCA component version " PMIX_VERSION; /* * Local functionality */ static int compress_zlib_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointer to our public functions in it */ PMIX_EXPORT pmix_mca_base_component_t pmix_mca_pcompress_zlib_component = { /* Handle the general mca_component_t struct containing * meta information about the component zlib */ PMIX_COMPRESS_BASE_VERSION_2_0_0, /* Component name and version */ .pmix_mca_component_name = "zlib", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_query_component = compress_zlib_query }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pcompress, zlib) static int compress_zlib_query(pmix_mca_base_module_t **module, int *priority) { *module = (pmix_mca_base_module_t *) &pmix_pcompress_zlib_module; *priority = 50; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pcompress/Makefile.am0000664000175000017500000000210215203536752021066 0ustar alastairalastair# # Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2010-2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # main library setup noinst_LTLIBRARIES = libmca_pcompress.la libmca_pcompress_la_SOURCES = # local files headers = pcompress.h libmca_pcompress_la_SOURCES += $(headers) # Ensure that the man pages are rebuilt if the pmix_config.h file # changes; a "good enough" way to know if configure was run again (and # therefore the release date or version may have changed) $(nodist_man_MANS): $(top_builddir)/pmix/include/pmix_config.h # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.am distclean-local: rm -f base/static-components.h rm -f $(nodist_man_MANS) pmix-6.1.1~rc2/src/mca/pcompress/pcompress.h0000664000175000017500000000747115203536752021234 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * * Copyright (c) 2019-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Compression Framework * * General Description: * * The PMIX Compress framework has been created to provide an abstract interface * to the compression agent library on the host machine. This framework is useful * when distributing files that can be compressed before sending to dimish the * load on the network. * */ #ifndef PMIX_MCA_COMPRESS_H #define PMIX_MCA_COMPRESS_H #include "pmix_config.h" #include "src/class/pmix_object.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #if defined(c_plusplus) || defined(__cplusplus) extern "C" { #endif /** * Module initialization function. * Returns PMIX_SUCCESS */ typedef int (*pmix_compress_base_module_init_fn_t)(void); /** * Module finalization function. * Returns PMIX_SUCCESS */ typedef int (*pmix_compress_base_module_finalize_fn_t)(void); /** * Compress a string * * Arguments: * */ typedef bool (*pmix_compress_base_module_compress_string_fn_t)(char *instring, uint8_t **outbytes, size_t *nbytes); typedef bool (*pmix_compress_base_module_decompress_string_fn_t)(char **outstring, uint8_t *inbytes, size_t len); typedef size_t (*pmix_compress_base_module_get_decompressed_strlen_fn_t)(const pmix_byte_object_t *bo); /** * Compress a block * * Arguments: * */ typedef bool (*pmix_compress_base_module_compress_fn_t)(const uint8_t *inbytes, size_t size, uint8_t **outbytes, size_t *nbytes); typedef bool (*pmix_compress_base_module_decompress_fn_t)(uint8_t **outbytes, size_t *outlen, const uint8_t *inbytes, size_t len); typedef size_t (*pmix_compress_base_module_get_decompressed_size_fn_t)(const pmix_byte_object_t *bo); /** * Structure for COMPRESS components. */ typedef pmix_mca_base_component_t pmix_compress_base_component_t; /** * Structure for COMPRESS modules */ struct pmix_compress_base_module_1_0_0_t { /** Initialization Function */ pmix_compress_base_module_init_fn_t init; /** Finalization Function */ pmix_compress_base_module_finalize_fn_t finalize; /** Compress interface */ pmix_compress_base_module_compress_fn_t compress; /** Decompress Interface */ pmix_compress_base_module_decompress_fn_t decompress; pmix_compress_base_module_get_decompressed_size_fn_t get_decompressed_size; /* COMPRESS STRING */ pmix_compress_base_module_compress_string_fn_t compress_string; pmix_compress_base_module_decompress_string_fn_t decompress_string; pmix_compress_base_module_get_decompressed_strlen_fn_t get_decompressed_strlen; }; typedef struct pmix_compress_base_module_1_0_0_t pmix_compress_base_module_1_0_0_t; typedef struct pmix_compress_base_module_1_0_0_t pmix_compress_base_module_t; PMIX_EXPORT extern pmix_compress_base_module_t pmix_compress; /** * Macro for use in components that are of type COMPRESS */ #define PMIX_COMPRESS_BASE_VERSION_2_0_0 PMIX_MCA_BASE_VERSION_1_0_0("pcompress", 2, 0, 0) #if defined(c_plusplus) || defined(__cplusplus) } #endif #endif /* PMIX_COMPRESS_H */ pmix-6.1.1~rc2/src/mca/pnet/0000775000175000017500000000000015203536752015772 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pnet/opa/0000775000175000017500000000000015203536752016551 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pnet/opa/pnet_opa_component.c0000664000175000017500000001016015203536752022602 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/pnet/base/base.h" #include "src/util/pmix_argv.h" #include "pnet_opa.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_register(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_pnet_opa_component_t pmix_mca_pnet_opa_component = { .super = { PMIX_PNET_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "opa", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_register_component_params = component_register, .pmix_mca_query_component = component_query, }, .include = NULL, .exclude = NULL }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pnet, opa) static pmix_status_t component_register(void) { pmix_mca_base_component_t *component = &pmix_mca_pnet_opa_component.super; pmix_mca_pnet_opa_component.incparms = "HFI_*,PSM2_*"; (void) pmix_mca_base_component_var_register( component, "include_envars", "Comma-delimited list of envars to harvest (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pnet_opa_component.incparms); if (NULL != pmix_mca_pnet_opa_component.incparms) { pmix_mca_pnet_opa_component.include = PMIx_Argv_split(pmix_mca_pnet_opa_component.incparms, ','); } pmix_mca_pnet_opa_component.excparms = NULL; (void) pmix_mca_base_component_var_register( component, "exclude_envars", "Comma-delimited list of envars to exclude (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pnet_opa_component.excparms); if (NULL != pmix_mca_pnet_opa_component.excparms) { pmix_mca_pnet_opa_component.exclude = PMIx_Argv_split(pmix_mca_pnet_opa_component.excparms, ','); } return PMIX_SUCCESS; } static pmix_status_t component_open(void) { pmix_status_t rc; rc = pmix_hwloc_check_vendor(&pmix_globals.topology, 0x8086, 0x208); return rc; } static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 10; *module = (pmix_mca_base_module_t *) &pmix_opa_module; return PMIX_SUCCESS; } static pmix_status_t component_close(void) { return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pnet/opa/configure.m40000664000175000017500000000130715203536752020775 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_pmix_pnet_opa_CONFIG([action-if-can-compile], # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pnet_opa_CONFIG], [ AC_CONFIG_FILES([src/mca/pnet/opa/Makefile]) AS_IF([test "yes" = "yes"], [$1 pmix_pnet_opa=yes], [$2 pmix_pnet_opa=no]) PMIX_SUMMARY_ADD([Transports], [OmniPath], [], [$pmix_pnet_opa]) ])dnl pmix-6.1.1~rc2/src/mca/pnet/opa/pnet_opa.c0000664000175000017500000003536515203536752020536 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/pcompress/pcompress.h" #include "src/mca/preg/preg.h" #include "src/util/pmix_alfg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_environ.h" #include "pnet_opa.h" #include "src/mca/pnet/base/base.h" #include "src/mca/pnet/pnet.h" static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); static pmix_status_t setup_local_network(pmix_nspace_env_cache_t *nptr, pmix_info_t info[], size_t ninfo); static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory); static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs); pmix_pnet_module_t pmix_opa_module = { .name = "opa", .allocate = allocate, .setup_local_network = setup_local_network, .collect_inventory = collect_inventory, .deliver_inventory = deliver_inventory }; /* some network transports require a little bit of information to * "pre-condition" them - i.e., to setup their individual transport * connections so they can generate their endpoint addresses. This * function provides a means for doing so. The resulting info is placed * into the app_context's env array so it will automatically be pushed * into the environment of every MPI process when launched. */ static inline void transports_use_rand(uint64_t *unique_key) { pmix_rng_buff_t rng; pmix_srand(&rng, (unsigned int) time(NULL)); unique_key[0] = pmix_rand(&rng); unique_key[1] = pmix_rand(&rng); } static char *transports_print(uint64_t *unique_key) { unsigned int *int_ptr; size_t i, j, string_key_len, written_len; char *string_key = NULL, *format = NULL; /* string is two 64 bit numbers printed in hex with a dash between * and zero padding. */ string_key_len = (sizeof(uint64_t) * 2) * 2 + strlen("-") + 1; string_key = (char *) malloc(string_key_len); if (NULL == string_key) { return NULL; } string_key[0] = '\0'; written_len = 0; /* get a format string based on the length of an unsigned int. We * want to have zero padding for sizeof(unsigned int) * 2 * characters -- when printing as a hex number, each byte is * represented by 2 hex characters. Format will contain something * that looks like %08lx, where the number 8 might be a different * number if the system has a different sized long (8 would be for * sizeof(int) == 4)). */ if (0 > asprintf(&format, "%%0%dx", (int) (sizeof(unsigned int)) * 2)) { free(string_key); return NULL; } /* print the first number */ int_ptr = (unsigned int *) &unique_key[0]; for (i = 0; i < sizeof(uint64_t) / sizeof(unsigned int); ++i) { if (0 == int_ptr[i]) { /* inject some energy */ for (j = 0; j < sizeof(unsigned int); j++) { int_ptr[i] |= j << j; } } pmix_snprintf(string_key + written_len, string_key_len - written_len, format, int_ptr[i]); written_len = strlen(string_key); } /* print the middle dash */ pmix_snprintf(string_key + written_len, string_key_len - written_len, "-"); written_len = strlen(string_key); /* print the second number */ int_ptr = (unsigned int *) &unique_key[1]; for (i = 0; i < sizeof(uint64_t) / sizeof(unsigned int); ++i) { if (0 == int_ptr[i]) { /* inject some energy */ for (j = 0; j < sizeof(unsigned int); j++) { int_ptr[i] |= j << j; } } pmix_snprintf(string_key + written_len, string_key_len - written_len, format, int_ptr[i]); written_len = strlen(string_key); } free(format); return string_key; } /* NOTE: if there is any binary data to be transferred, then * this function MUST pack it for transport as the host will * not know how to do so */ static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist) { uint64_t unique_key[2]; char *string_key; int fd_rand; size_t bytes_read, n, m, p; pmix_buffer_t mydata; // Buffer used to store information to be transmitted (scratch storage) pmix_kval_t *kv; pmix_envar_t envar; pmix_byte_object_t bo; bool envars = false, seckeys = false; pmix_status_t rc; pmix_info_t *iptr; pmix_list_t cache; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:opa:allocate for nspace %s", nptr->nspace); if (NULL == info) { return PMIX_ERR_TAKE_NEXT_OPTION; } PMIX_ENVAR_CONSTRUCT(&envar); for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ENVARS)) { envars = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ALL)) { envars = PMIX_INFO_TRUE(&info[n]); seckeys = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_NONENVARS)) { seckeys = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_ALLOC_NETWORK)) { iptr = (pmix_info_t *) info[n].value.data.darray->array; m = info[n].value.data.darray->size; for (p = 0; p < m; p++) { if (PMIX_CHECK_KEY(&iptr[p], PMIX_ALLOC_NETWORK_SEC_KEY)) { seckeys = PMIX_INFO_TRUE(&iptr[p]); } else if (PMIX_CHECK_KEY(&iptr[p], PMIX_ALLOC_NETWORK_ID)) { /* need to track the request by this ID */ } else if (PMIX_CHECK_KEY(&iptr[p], PMIX_SETUP_APP_ENVARS)) { envars = PMIX_INFO_TRUE(&iptr[p]); } else if (PMIX_CHECK_KEY(&iptr[p], PMIX_SETUP_APP_ALL)) { envars = PMIX_INFO_TRUE(&iptr[p]); seckeys = PMIX_INFO_TRUE(&iptr[p]); } else if (PMIX_CHECK_KEY(&iptr[p], PMIX_SETUP_APP_NONENVARS)) { seckeys = PMIX_INFO_TRUE(&iptr[p]); } } } } /* setup a buffer - we will pack the info into it for transmission to * the backend compute node daemons */ PMIX_CONSTRUCT(&mydata, pmix_buffer_t); if (seckeys) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: opa providing seckeys"); /* put the number here - or else create an appropriate string. this just needs to * eventually be a string variable */ if (-1 == (fd_rand = open("/dev/urandom", O_RDONLY))) { transports_use_rand(unique_key); } else { bytes_read = read(fd_rand, (char *) unique_key, 16); if (bytes_read != 16) { transports_use_rand(unique_key); } close(fd_rand); } if (NULL == (string_key = transports_print(unique_key))) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); PMIX_DESTRUCT(&mydata); return PMIX_ERR_OUT_OF_RESOURCE; } PMIX_ENVAR_LOAD(&envar, "OMPI_MCA_orte_precondition_transports", string_key, ':'); PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &mydata, &envar, 1, PMIX_ENVAR); free(string_key); PMIX_ENVAR_DESTRUCT(&envar); } if (envars) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: opa harvesting envars %s excluding %s", (NULL == pmix_mca_pnet_opa_component.incparms) ? "NONE" : pmix_mca_pnet_opa_component.incparms, (NULL == pmix_mca_pnet_opa_component.excparms) ? "NONE" : pmix_mca_pnet_opa_component.excparms); /* harvest envars to pass along */ PMIX_CONSTRUCT(&cache, pmix_list_t); if (NULL != pmix_mca_pnet_opa_component.include) { rc = pmix_util_harvest_envars(pmix_mca_pnet_opa_component.include, pmix_mca_pnet_opa_component.exclude, &cache); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&cache); PMIX_DESTRUCT(&mydata); return rc; } /* pack anything that was found */ PMIX_LIST_FOREACH (kv, &cache, pmix_kval_t) { PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &mydata, &kv->value->data.envar, 1, PMIX_ENVAR); } PMIX_LIST_DESTRUCT(&cache); } } // unload the buffer PMIX_UNLOAD_BUFFER(&mydata, bo.bytes, bo.size); // if nothing was packed, then we have nothing to send if (0 == bo.size) { PMIX_DESTRUCT(&mydata); return PMIX_SUCCESS; } /* load all our results into a buffer for xmission to the backend */ PMIX_KVAL_NEW(kv, PMIX_PNET_OPA_BLOB); if (NULL == kv || NULL == kv->value) { PMIX_DESTRUCT(&mydata); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_BYTE_OBJECT; /* to help scalability, compress this blob */ if (pmix_compress.compress((uint8_t *) bo.bytes, bo.size, (uint8_t **) &kv->value->data.bo.bytes, &kv->value->data.bo.size)) { kv->value->type = PMIX_COMPRESSED_BYTE_OBJECT; } else { kv->value->data.bo.bytes = bo.bytes; kv->value->data.bo.size = bo.size; } PMIX_DESTRUCT(&mydata); pmix_list_append(ilist, &kv->super); return PMIX_SUCCESS; } /* PMIx_server_setup_local_support calls the "setup_local_network" function. * The Standard requires that this come _after_ the host calls the * PMIx_server_register_nspace function to ensure that any required information * is available to the components. Thus, we have the PMIX_NODE_MAP and * PMIX_PROC_MAP available to us and can use them here. * * When the host calls "setup_local_support", it passes down an array * containing the information the "lead" server (e.g., "mpirun") collected * from PMIx_server_setup_application. In this case, we search for a blob * that our "allocate" function may have included in that info. */ static pmix_status_t setup_local_network(pmix_nspace_env_cache_t *ns, pmix_info_t info[], size_t ninfo) { size_t n; pmix_buffer_t bkt; int32_t cnt; pmix_status_t rc = PMIX_SUCCESS; uint8_t *data; size_t size; bool release = false; pmix_envar_list_item_t *ev; pmix_proc_t proc; pmix_kval_t *kv; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:opa:setup_local with %lu info", (unsigned long) ninfo); /* prep the unpack buffer */ PMIX_CONSTRUCT(&bkt, pmix_buffer_t); for (n = 0; n < ninfo; n++) { /* look for my key */ if (PMIX_CHECK_KEY(&info[n], PMIX_PNET_OPA_BLOB)) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:opa:setup_local found my blob"); /* if this is a compressed byte object, decompress it */ if (PMIX_COMPRESSED_BYTE_OBJECT == info[n].value.type) { pmix_compress.decompress(&data, &size, (uint8_t *) info[n].value.data.bo.bytes, info[n].value.data.bo.size); release = true; } else { data = (uint8_t *) info[n].value.data.bo.bytes; size = info[n].value.data.bo.size; } PMIX_LOAD_BUFFER_NON_DESTRUCT(pmix_globals.mypeer, &bkt, data, size); /* all we packed was envars, so just cycle thru */ ev = PMIX_NEW(pmix_envar_list_item_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &ev->envar, &cnt, PMIX_ENVAR); while (PMIX_SUCCESS == rc) { pmix_list_append(&ns->envars, &ev->super); /* if this is the transport key, save it */ if (0 == strncmp(ev->envar.envar, "OMPI_MCA_orte_precondition_transports", PMIX_MAX_KEYLEN)) { /* add it to the job-level info */ PMIX_LOAD_PROCID(&proc, ns->ns->nspace, PMIX_RANK_WILDCARD); PMIX_KVAL_NEW(kv, PMIX_CREDENTIAL); kv->value->type = PMIX_STRING; kv->value->data.string = strdup(ev->envar.value); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &proc, PMIX_INTERNAL, kv); PMIX_RELEASE(kv); // maintain refcount if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } /* get the next envar */ ev = PMIX_NEW(pmix_envar_list_item_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &ev->envar, &cnt, PMIX_ENVAR); } if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { rc = PMIX_SUCCESS; } // we will have created one more envar than we want PMIX_RELEASE(ev); /* we are done */ break; } } if (release) { free(data); } return rc; } static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory) { /* search the topology for OPA NICs */ PMIX_HIDE_UNUSED_PARAMS(directives, ndirs, inventory); return PMIX_SUCCESS; } static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs) { /* look for our inventory blob */ PMIX_HIDE_UNUSED_PARAMS(info, ninfo, directives, ndirs); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pnet/opa/pnet_opa.h0000664000175000017500000000162715203536752020535 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PNET_OPA_H #define PMIX_PNET_OPA_H #include "src/include/pmix_config.h" #include "src/mca/pnet/pnet.h" BEGIN_C_DECLS typedef struct { pmix_pnet_base_component_t super; char *incparms; char *excparms; char **include; char **exclude; } pmix_pnet_opa_component_t; /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_pnet_opa_component_t pmix_mca_pnet_opa_component; extern pmix_pnet_module_t pmix_opa_module; /* define a key for any blob we need to send in a launch msg */ #define PMIX_PNET_OPA_BLOB "pmix.pnet.opa.blob" /* define an inventory key */ #define PMIX_PNET_OPA_INVENTORY_KEY "pmix.pnet.opa.inventory" END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pnet/opa/Makefile.am0000664000175000017500000000363515203536752020614 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = pnet_opa.h sources = \ pnet_opa_component.c \ pnet_opa.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pnet_opa_DSO lib = lib_sources = component = pmix_mca_pnet_opa.la component_sources = $(headers) $(sources) else lib = libpmix_mca_pnet_opa.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_pnet_opa_la_SOURCES = $(component_sources) pmix_mca_pnet_opa_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_pnet_opa_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_pnet_opa_la_SOURCES = $(lib_sources) libpmix_mca_pnet_opa_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/pnet/nvd/0000775000175000017500000000000015203536752016561 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pnet/nvd/pnet_nvd_component.c0000664000175000017500000001050415203536752022624 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/pnet/base/base.h" #include "src/util/pmix_argv.h" #include "pnet_nvd.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_register(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_pnet_nvd_component_t pmix_mca_pnet_nvd_component = { .super = { PMIX_PNET_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "nvd", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_register_component_params = component_register, .pmix_mca_query_component = component_query, }, .include = NULL, .exclude = NULL }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pnet, nvd) static pmix_status_t component_register(void) { pmix_mca_base_component_t *component = &pmix_mca_pnet_nvd_component.super; pmix_mca_pnet_nvd_component.incparms = "UCX_*,HCOLL_*,UCC_*,SHARP_*,NCCL_*"; (void) pmix_mca_base_component_var_register( component, "include_envars", "Comma-delimited list of envars to harvest (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pnet_nvd_component.incparms); if (NULL != pmix_mca_pnet_nvd_component.incparms) { pmix_mca_pnet_nvd_component.include = PMIx_Argv_split(pmix_mca_pnet_nvd_component.incparms, ','); } pmix_mca_pnet_nvd_component.excparms = NULL; (void) pmix_mca_base_component_var_register( component, "exclude_envars", "Comma-delimited list of envars to exclude (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pnet_nvd_component.excparms); if (NULL != pmix_mca_pnet_nvd_component.excparms) { pmix_mca_pnet_nvd_component.exclude = PMIx_Argv_split(pmix_mca_pnet_nvd_component.excparms, ','); } return PMIX_SUCCESS; } static pmix_status_t component_open(void) { pmix_status_t rc; // currently under Mellanox rc = pmix_hwloc_check_vendor(&pmix_globals.topology, 0x15b3, 0x207); if (PMIX_SUCCESS != rc) { // future could be under NVIDIA rc = pmix_hwloc_check_vendor(&pmix_globals.topology, 0x10de, 0x207); } return rc; } static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 10; *module = (pmix_mca_base_module_t *) &pmix_pnet_nvd_module; return PMIX_SUCCESS; } static pmix_status_t component_close(void) { return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pnet/nvd/pnet_nvd.c0000664000175000017500000002207215203536752020545 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/pcompress/pcompress.h" #include "src/mca/preg/preg.h" #include "src/util/pmix_alfg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "pnet_nvd.h" #include "src/mca/pnet/base/base.h" #include "src/mca/pnet/pnet.h" static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); static pmix_status_t setup_local_network(pmix_nspace_env_cache_t *nptr, pmix_info_t info[], size_t ninfo); static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory); static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs); pmix_pnet_module_t pmix_pnet_nvd_module = { .name = "nvd", .allocate = allocate, .setup_local_network = setup_local_network, .collect_inventory = collect_inventory, .deliver_inventory = deliver_inventory }; /* NOTE: if there is any binary data to be transferred, then * this function MUST pack it for transport as the host will * not know how to do so */ static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist) { pmix_buffer_t mydata; // Buffer used to store information to be transmitted (scratch storage) pmix_kval_t *kv; pmix_byte_object_t bo; bool envars = false; pmix_status_t rc; pmix_list_t cache; size_t n; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:nvd:allocate for nspace %s", nptr->nspace); if (NULL == info) { return PMIX_ERR_TAKE_NEXT_OPTION; } for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ENVARS)) { envars = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ALL)) { envars = PMIX_INFO_TRUE(&info[n]); } } /* setup a buffer - we will pack the info into it for transmission to * the backend compute node daemons */ PMIX_CONSTRUCT(&mydata, pmix_buffer_t); if (envars) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: nvd harvesting envars %s excluding %s", (NULL == pmix_mca_pnet_nvd_component.incparms) ? "NONE" : pmix_mca_pnet_nvd_component.incparms, (NULL == pmix_mca_pnet_nvd_component.excparms) ? "NONE" : pmix_mca_pnet_nvd_component.excparms); /* harvest envars to pass along */ PMIX_CONSTRUCT(&cache, pmix_list_t); if (NULL != pmix_mca_pnet_nvd_component.include) { rc = pmix_util_harvest_envars(pmix_mca_pnet_nvd_component.include, pmix_mca_pnet_nvd_component.exclude, &cache); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&cache); PMIX_DESTRUCT(&mydata); return rc; } /* pack anything that was found */ PMIX_LIST_FOREACH (kv, &cache, pmix_kval_t) { PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &mydata, &kv->value->data.envar, 1, PMIX_ENVAR); } PMIX_LIST_DESTRUCT(&cache); } } /* load all our results into a buffer for xmission to the backend */ PMIX_KVAL_NEW(kv, PMIX_PNET_NVD_BLOB); if (NULL == kv || NULL == kv->value) { PMIX_DESTRUCT(&mydata); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_BYTE_OBJECT; PMIX_UNLOAD_BUFFER(&mydata, bo.bytes, bo.size); /* to help scalability, compress this blob */ if (pmix_compress.compress((uint8_t *) bo.bytes, bo.size, (uint8_t **) &kv->value->data.bo.bytes, &kv->value->data.bo.size)) { kv->value->type = PMIX_COMPRESSED_BYTE_OBJECT; } else { kv->value->data.bo.bytes = bo.bytes; kv->value->data.bo.size = bo.size; } PMIX_DESTRUCT(&mydata); pmix_list_append(ilist, &kv->super); return PMIX_SUCCESS; } /* PMIx_server_setup_local_support calls the "setup_local_network" function. * The Standard requires that this come _after_ the host calls the * PMIx_server_register_nspace function to ensure that any required information * is available to the components. Thus, we have the PMIX_NODE_MAP and * PMIX_PROC_MAP available to us and can use them here. * * When the host calls "setup_local_support", it passes down an array * containing the information the "lead" server (e.g., "mpirun") collected * from PMIx_server_setup_application. In this case, we search for a blob * that our "allocate" function may have included in that info. */ static pmix_status_t setup_local_network(pmix_nspace_env_cache_t *ns, pmix_info_t info[], size_t ninfo) { size_t n; pmix_buffer_t bkt; int32_t cnt; pmix_status_t rc = PMIX_SUCCESS; uint8_t *data; size_t size; bool release = false; pmix_envar_list_item_t *ev; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:nvd:setup_local with %lu info", (unsigned long) ninfo); /* prep the unpack buffer */ PMIX_CONSTRUCT(&bkt, pmix_buffer_t); for (n = 0; n < ninfo; n++) { /* look for my key */ if (PMIX_CHECK_KEY(&info[n], PMIX_PNET_NVD_BLOB)) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:nvd:setup_local found my blob"); /* if this is a compressed byte object, decompress it */ if (PMIX_COMPRESSED_BYTE_OBJECT == info[n].value.type) { pmix_compress.decompress(&data, &size, (uint8_t *) info[n].value.data.bo.bytes, info[n].value.data.bo.size); release = true; } else { data = (uint8_t *) info[n].value.data.bo.bytes; size = info[n].value.data.bo.size; } PMIX_LOAD_BUFFER_NON_DESTRUCT(pmix_globals.mypeer, &bkt, data, size); /* all we packed was envars, so just cycle thru */ ev = PMIX_NEW(pmix_envar_list_item_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &ev->envar, &cnt, PMIX_ENVAR); while (PMIX_SUCCESS == rc) { pmix_list_append(&ns->envars, &ev->super); /* get the next envar */ ev = PMIX_NEW(pmix_envar_list_item_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &ev->envar, &cnt, PMIX_ENVAR); } // we will have created one more envar than we want PMIX_RELEASE(ev); /* we are done */ break; } } if (release) { free(data); } return rc; } static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory) { pmix_status_t rc = PMIX_SUCCESS; PMIX_HIDE_UNUSED_PARAMS(directives,ndirs, inventory); /* search the topology for Mellanox/NVIDIA NICs */ hwloc_obj_t device; if (NULL == pmix_globals.topology.source || 0 != strncasecmp(pmix_globals.topology.source, "hwloc", 5) || NULL == pmix_globals.topology.topology) { return PMIX_ERR_NOT_SUPPORTED; } device = hwloc_get_next_pcidev(pmix_globals.topology.topology, NULL); while (NULL != device) { if (0x207 == device->attr->pcidev.class_id && (device->attr->pcidev.vendor_id == 0x15b3 || device->attr->pcidev.vendor_id == 0x10de)) { /* add this to the inventory */ return PMIX_SUCCESS; } device = hwloc_get_next_pcidev(pmix_globals.topology.topology, device); } return rc; } static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs) { /* look for our inventory blob */ PMIX_HIDE_UNUSED_PARAMS(info, ninfo, directives, ndirs); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pnet/nvd/configure.m40000664000175000017500000000222015203536752021000 0ustar alastairalastair# -*- shell-script -*- # # Copyright (C) 2015-2017 Mellanox Technologies, Inc. # All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2016 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_pmix_pnet_nvd_CONFIG(prefix, [action-if-found], [action-if-not-found]) # -------------------------------------------------------- AC_DEFUN([MCA_pmix_pnet_nvd_CONFIG],[ PMIX_VAR_SCOPE_PUSH([pmix_nvd_happy]) AC_CONFIG_FILES([src/mca/pnet/nvd/Makefile]) AS_IF([test "yes" = "no"], [$1 pmix_nvd_happy=yes], [$2 pmix_nvd_happy=no]) PMIX_SUMMARY_ADD([Transports], [NVIDIA], [], [$pmix_nvd_happy]) PMIX_VAR_SCOPE_POP ]) pmix-6.1.1~rc2/src/mca/pnet/nvd/pnet_nvd.h0000664000175000017500000000163415203536752020553 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PNET_NVD_H #define PMIX_PNET_NVD_H #include "src/include/pmix_config.h" #include "src/mca/pnet/pnet.h" BEGIN_C_DECLS typedef struct { pmix_pnet_base_component_t super; char *incparms; char *excparms; char **include; char **exclude; } pmix_pnet_nvd_component_t; /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_pnet_nvd_component_t pmix_mca_pnet_nvd_component; extern pmix_pnet_module_t pmix_pnet_nvd_module; /* define a key for any blob we need to send in a launch msg */ #define PMIX_PNET_NVD_BLOB "pmix.pnet.nvd.blob" /* define an inventory key */ #define PMIX_PNET_NVD_INVENTORY_KEY "pmix.pnet.nvd.inventory" END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pnet/nvd/Makefile.am0000664000175000017500000000363515203536752020624 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = pnet_nvd.h sources = \ pnet_nvd_component.c \ pnet_nvd.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pnet_nvd_DSO lib = lib_sources = component = pmix_mca_pnet_nvd.la component_sources = $(headers) $(sources) else lib = libpmix_mca_pnet_nvd.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_pnet_nvd_la_SOURCES = $(component_sources) pmix_mca_pnet_nvd_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_pnet_nvd_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_pnet_nvd_la_SOURCES = $(lib_sources) libpmix_mca_pnet_nvd_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/pnet/base/0000775000175000017500000000000015203536752016704 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pnet/base/pnet_base_select.c0000664000175000017500000001142115203536752022346 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/mca/pnet/base/base.h" /* Function for selecting a prioritized list of components * from all those that are available. */ int pmix_pnet_base_select(void) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_mca_base_component_t *component = NULL; pmix_mca_base_module_t *module = NULL; pmix_pnet_module_t *nmodule; pmix_pnet_base_active_module_t *newmodule, *mod; int rc, priority; bool inserted; if (pmix_pnet_globals.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_pnet_globals.selected = true; /* Query all available components and ask if they have a module */ PMIX_LIST_FOREACH (cli, &pmix_pnet_base_framework.framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_mca_base_component_t *) cli->cli_component; pmix_output_verbose(5, pmix_pnet_base_framework.framework_output, "mca:pnet:select: checking available component %s", component->pmix_mca_component_name); /* If there's no query function, skip it */ if (NULL == component->pmix_mca_query_component) { pmix_output_verbose( 5, pmix_pnet_base_framework.framework_output, "mca:pnet:select: Skipping component [%s]. It does not implement a query function", component->pmix_mca_component_name); continue; } /* Query the component */ pmix_output_verbose(5, pmix_pnet_base_framework.framework_output, "mca:pnet:select: Querying component [%s]", component->pmix_mca_component_name); rc = component->pmix_mca_query_component(&module, &priority); /* If no module was returned, then skip component */ if (PMIX_SUCCESS != rc || NULL == module) { pmix_output_verbose( 5, pmix_pnet_base_framework.framework_output, "mca:pnet:select: Skipping component [%s]. Query failed to return a module", component->pmix_mca_component_name); continue; } /* If we got a module, keep it */ nmodule = (pmix_pnet_module_t *) module; /* let it initialize */ if (NULL != nmodule->init && PMIX_SUCCESS != nmodule->init()) { continue; } /* add to the list of selected modules */ newmodule = PMIX_NEW(pmix_pnet_base_active_module_t); newmodule->pri = priority; newmodule->module = nmodule; newmodule->component = (pmix_pnet_base_component_t *) cli->cli_component; /* maintain priority order */ inserted = false; PMIX_LIST_FOREACH (mod, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { if (priority > mod->pri) { pmix_list_insert_pos(&pmix_pnet_globals.actives, (pmix_list_item_t *) mod, &newmodule->super); inserted = true; break; } } if (!inserted) { /* must be lowest priority - add to end */ pmix_list_append(&pmix_pnet_globals.actives, &newmodule->super); } } if (4 < pmix_output_get_verbosity(pmix_pnet_base_framework.framework_output)) { pmix_output(0, "Final pnet priorities"); /* show the prioritized list */ PMIX_LIST_FOREACH (mod, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { pmix_output(0, "\tpnet: %s Priority: %d", mod->component->pmix_mca_component_name, mod->pri); } } return PMIX_SUCCESS; ; } pmix-6.1.1~rc2/src/mca/pnet/base/base.h0000664000175000017500000001061015203536752017765 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PNET_BASE_H_ #define PMIX_PNET_BASE_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/class/pmix_pointer_array.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/mca.h" #include "src/mca/pnet/pnet.h" BEGIN_C_DECLS /* * MCA Framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_pnet_base_framework; /** * PNET select function * * Cycle across available components and construct the list * of active modules */ PMIX_EXPORT pmix_status_t pmix_pnet_base_select(void); /** * Track an active component / module */ struct pmix_pnet_base_active_module_t { pmix_list_item_t super; int pri; pmix_pnet_module_t *module; pmix_pnet_base_component_t *component; }; typedef struct pmix_pnet_base_active_module_t pmix_pnet_base_active_module_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_pnet_base_active_module_t); typedef struct { pmix_list_item_t super; char *name; size_t index; /* provide access to the component * APIs that are managing this * fabric plane */ pmix_pnet_module_t *module; /* allow the component to add * whatever structures it needs */ void *payload; } pmix_pnet_fabric_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_pnet_fabric_t); /* framework globals */ struct pmix_pnet_globals_t { pmix_list_t actives; pmix_list_t fabrics; pmix_list_t nspaces; bool selected; }; typedef struct pmix_pnet_globals_t pmix_pnet_globals_t; PMIX_EXPORT extern pmix_pnet_globals_t pmix_pnet_globals; PMIX_EXPORT pmix_status_t pmix_pnet_base_allocate(char *nspace, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); PMIX_EXPORT pmix_status_t pmix_pnet_base_setup_local_network(char *nspace, pmix_info_t info[], size_t ninfo); PMIX_EXPORT pmix_status_t pmix_pnet_base_setup_fork(const pmix_proc_t *peer, char ***env); PMIX_EXPORT void pmix_pnet_base_child_finalized(pmix_proc_t *peer); PMIX_EXPORT void pmix_pnet_base_local_app_finalized(pmix_namespace_t *nptr); PMIX_EXPORT void pmix_pnet_base_deregister_nspace(char *nspace); PMIX_EXPORT pmix_status_t pmix_pnet_base_collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory); PMIX_EXPORT pmix_status_t pmix_pnet_base_deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs); PMIX_EXPORT pmix_status_t pmix_pnet_base_harvest_envars(char **incvars, char **excvars, pmix_list_t *ilist); PMIX_EXPORT pmix_status_t pmix_pnet_base_register_fabric(pmix_fabric_t *fabric, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata); PMIX_EXPORT pmix_status_t pmix_pnet_base_deregister_fabric(pmix_fabric_t *fabric); PMIX_EXPORT pmix_status_t pmix_pnet_base_update_fabric(pmix_fabric_t *fabric); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pnet/base/Makefile.include0000664000175000017500000000221515203536752021766 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2016 Intel, Inc. All rights reserved # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from # src/Makefile.am headers += \ base/base.h sources += \ base/pnet_base_frame.c \ base/pnet_base_select.c \ base/pnet_base_fns.c pmix-6.1.1~rc2/src/mca/pnet/base/pnet_base_frame.c0000664000175000017500000001013515203536752022162 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2009 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pnet/base/base.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public mca_base_component_t struct. */ #include "src/mca/pnet/base/static-components.h" /* Instantiate the global vars */ pmix_pnet_globals_t pmix_pnet_globals = { .actives = PMIX_LIST_STATIC_INIT, .fabrics = PMIX_LIST_STATIC_INIT }; pmix_pnet_API_module_t pmix_pnet = { .allocate = pmix_pnet_base_allocate, .setup_local_network = pmix_pnet_base_setup_local_network, .setup_fork = pmix_pnet_base_setup_fork, .child_finalized = pmix_pnet_base_child_finalized, .local_app_finalized = pmix_pnet_base_local_app_finalized, .deregister_nspace = pmix_pnet_base_deregister_nspace, .collect_inventory = pmix_pnet_base_collect_inventory, .deliver_inventory = pmix_pnet_base_deliver_inventory, .register_fabric = pmix_pnet_base_register_fabric, .update_fabric = pmix_pnet_base_update_fabric, .deregister_fabric = pmix_pnet_base_deregister_fabric }; static pmix_status_t pmix_pnet_close(void) { pmix_pnet_base_active_module_t *active, *prev; pmix_pnet_globals.selected = false; PMIX_LIST_FOREACH_SAFE (active, prev, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { pmix_list_remove_item(&pmix_pnet_globals.actives, &active->super); if (NULL != active->module->finalize) { active->module->finalize(); } PMIX_RELEASE(active); } PMIX_LIST_DESTRUCT(&pmix_pnet_globals.actives); PMIX_LIST_DESTRUCT(&pmix_pnet_globals.fabrics); PMIX_LIST_DESTRUCT(&pmix_pnet_globals.nspaces); return pmix_mca_base_framework_components_close(&pmix_pnet_base_framework, NULL); } static pmix_status_t pmix_pnet_open(pmix_mca_base_open_flag_t flags) { /* initialize globals */ PMIX_CONSTRUCT(&pmix_pnet_globals.actives, pmix_list_t); PMIX_CONSTRUCT(&pmix_pnet_globals.fabrics, pmix_list_t); PMIX_CONSTRUCT(&pmix_pnet_globals.nspaces, pmix_list_t); /* Open up all available components */ return pmix_mca_base_framework_components_open(&pmix_pnet_base_framework, flags); } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, pnet, "PMIx Network Operations", NULL, pmix_pnet_open, pmix_pnet_close, pmix_mca_pnet_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); PMIX_CLASS_INSTANCE(pmix_pnet_base_active_module_t, pmix_list_item_t, NULL, NULL); static void ftcon(pmix_pnet_fabric_t *p) { p->name = NULL; p->index = 0; p->module = NULL; p->payload = NULL; } static void ftdes(pmix_pnet_fabric_t *p) { if (NULL != p->name) { free(p->name); } } PMIX_CLASS_INSTANCE(pmix_pnet_fabric_t, pmix_list_item_t, ftcon, ftdes); pmix-6.1.1~rc2/src/mca/pnet/base/pnet_base_fns.c0000664000175000017500000003207715203536752021667 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/class/pmix_list.h" #include "src/mca/preg/preg.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_environ.h" #include "src/mca/pnet/base/base.h" /* NOTE: a tool (e.g., prun) may call this function to * harvest local envars for inclusion in a call to * PMIx_Spawn, or it might be called in response to * a call to PMIx_Allocate_resources */ pmix_status_t pmix_pnet_base_allocate(char *nspace, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist) { pmix_pnet_base_active_module_t *active; pmix_status_t rc; pmix_namespace_t *nptr, *ns; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:allocate called"); /* protect against bozo inputs */ if (NULL == nspace || NULL == ilist) { return PMIX_ERR_BAD_PARAM; } if (0 == pmix_list_get_size(&pmix_pnet_globals.actives)) { return PMIX_SUCCESS; } /* find this proc's nspace object */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(ns->nspace, nspace)) { nptr = ns; break; } } if (NULL == nptr) { /* add it */ nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { return PMIX_ERR_NOMEM; } nptr->nspace = strdup(nspace); pmix_list_append(&pmix_globals.nspaces, &nptr->super); } if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { /* process the allocation request */ PMIX_LIST_FOREACH (active, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { if (NULL != active->module->allocate) { rc = active->module->allocate(nptr, info, ninfo, ilist); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_AVAILABLE != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { /* true error */ return rc; } } } } return PMIX_SUCCESS; } /* can only be called by a server from within an event! */ pmix_status_t pmix_pnet_base_setup_local_network(char *nspace, pmix_info_t info[], size_t ninfo) { pmix_pnet_base_active_module_t *active; pmix_status_t rc; pmix_namespace_t *nsp, *nsp2; pmix_nspace_env_cache_t *ns, *ns2; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: setup_local_network called"); /* protect against bozo inputs */ if (NULL == nspace) { return PMIX_ERR_BAD_PARAM; } if (0 == pmix_list_get_size(&pmix_pnet_globals.actives)) { return PMIX_SUCCESS; } /* find this proc's nspace object */ ns = NULL; PMIX_LIST_FOREACH (ns2, &pmix_pnet_globals.nspaces, pmix_nspace_env_cache_t) { if (PMIX_CHECK_NSPACE(ns2->ns->nspace, nspace)) { ns = ns2; break; } } if (NULL == ns) { /* find the namespace object for this nspace */ nsp = NULL; PMIX_LIST_FOREACH (nsp2, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(nsp2->nspace, nspace)) { nsp = nsp2; break; } } if (NULL == nsp) { /* add it */ nsp = PMIX_NEW(pmix_namespace_t); if (NULL == nsp) { return PMIX_ERR_NOMEM; } nsp->nspace = strdup(nspace); pmix_list_append(&pmix_globals.nspaces, &nsp->super); } ns = PMIX_NEW(pmix_nspace_env_cache_t); PMIX_RETAIN(nsp); ns->ns = nsp; pmix_list_append(&pmix_pnet_globals.nspaces, &ns->super); } PMIX_LIST_FOREACH (active, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { if (NULL != active->module->setup_local_network) { rc = active->module->setup_local_network(ns, info, ninfo); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_AVAILABLE != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { return rc; } } } return PMIX_SUCCESS; } /* can only be called by a server from within an event! */ pmix_status_t pmix_pnet_base_setup_fork(const pmix_proc_t *proc, char ***env) { pmix_nspace_env_cache_t *ns, *ns2; pmix_envar_list_item_t *ev; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: setup_fork called"); /* protect against bozo inputs */ if (NULL == proc || NULL == env) { return PMIX_ERR_BAD_PARAM; } /* see if we have this nspace */ ns = NULL; PMIX_LIST_FOREACH (ns2, &pmix_pnet_globals.nspaces, pmix_nspace_env_cache_t) { if (PMIX_CHECK_NSPACE(ns2->ns->nspace, proc->nspace)) { ns = ns2; break; } } if (NULL != ns) { PMIX_LIST_FOREACH (ev, &ns->envars, pmix_envar_list_item_t) { PMIx_Setenv(ev->envar.envar, ev->envar.value, true, env); } } return PMIX_SUCCESS; } void pmix_pnet_base_child_finalized(pmix_proc_t *peer) { pmix_pnet_base_active_module_t *active; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: child_finalized called"); /* protect against bozo inputs */ if (NULL == peer) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return; } if (0 == pmix_list_get_size(&pmix_pnet_globals.actives)) { return; } PMIX_LIST_FOREACH (active, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { if (NULL != active->module->child_finalized) { active->module->child_finalized(peer); } } return; } void pmix_pnet_base_local_app_finalized(pmix_namespace_t *nptr) { pmix_pnet_base_active_module_t *active; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: local_app_finalized called"); /* protect against bozo inputs */ if (NULL == nptr) { return; } if (0 == pmix_list_get_size(&pmix_pnet_globals.actives)) { return; } PMIX_LIST_FOREACH (active, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { if (NULL != active->module->local_app_finalized) { active->module->local_app_finalized(nptr); } } return; } void pmix_pnet_base_deregister_nspace(char *nspace) { pmix_pnet_base_active_module_t *active; pmix_nspace_env_cache_t *ns, *ns2; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: deregister_nspace called"); /* protect against bozo inputs */ if (NULL == nspace) { return; } /* find this nspace object */ ns = NULL; PMIX_LIST_FOREACH (ns2, &pmix_pnet_globals.nspaces, pmix_nspace_env_cache_t) { if (PMIX_CHECK_NSPACE(ns2->ns->nspace, nspace)) { ns = ns2; pmix_list_remove_item(&pmix_pnet_globals.nspaces, &ns->super); break; } } if (NULL == ns) { return; } PMIX_LIST_FOREACH (active, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { if (NULL != active->module->deregister_nspace) { active->module->deregister_nspace(ns->ns); } } PMIX_RELEASE(ns); } pmix_status_t pmix_pnet_base_collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory) { pmix_pnet_base_active_module_t *active; pmix_status_t rc; PMIX_LIST_FOREACH (active, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { if (NULL != active->module->collect_inventory) { pmix_output_verbose(5, pmix_pnet_base_framework.framework_output, "COLLECTING %s", active->module->name); rc = active->module->collect_inventory(directives, ndirs, inventory); if (PMIX_SUCCESS != rc) { return rc; } } } return PMIX_SUCCESS; } pmix_status_t pmix_pnet_base_deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs) { pmix_pnet_base_active_module_t *active; pmix_status_t rc; PMIX_LIST_FOREACH (active, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { if (NULL != active->module->deliver_inventory) { pmix_output_verbose(5, pmix_pnet_base_framework.framework_output, "DELIVERING TO %s", active->module->name); rc = active->module->deliver_inventory(info, ninfo, directives, ndirs); if (PMIX_SUCCESS != rc) { return rc; } } } return PMIX_SUCCESS; } pmix_status_t pmix_pnet_base_register_fabric(pmix_fabric_t *fabric, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_pnet_base_active_module_t *active; pmix_status_t rc; pmix_pnet_fabric_t *ft; /* ensure our fields of the fabric object are initialized */ fabric->info = NULL; fabric->ninfo = 0; fabric->module = NULL; if (0 == pmix_list_get_size(&pmix_pnet_globals.actives)) { return PMIX_ERR_NOT_SUPPORTED; } /* scan across active modules until one returns success */ PMIX_LIST_FOREACH (active, &pmix_pnet_globals.actives, pmix_pnet_base_active_module_t) { if (NULL != active->module->register_fabric) { rc = active->module->register_fabric(fabric, directives, ndirs, cbfunc, cbdata); if (PMIX_OPERATION_SUCCEEDED == rc) { /* track this fabric so we can respond to remote requests */ ft = PMIX_NEW(pmix_pnet_fabric_t); ft->index = fabric->index; if (NULL != fabric->name) { ft->name = strdup(fabric->name); } ft->module = active->module; pmix_list_append(&pmix_pnet_globals.fabrics, &ft->super); return rc; } else if (PMIX_ERR_TAKE_NEXT_OPTION != rc) { /* just return the result */ return rc; } } } return PMIX_ERR_NOT_FOUND; } pmix_status_t pmix_pnet_base_update_fabric(pmix_fabric_t *fabric) { pmix_status_t rc = PMIX_SUCCESS; pmix_pnet_fabric_t *active; pmix_pnet_module_t *module = NULL; pmix_pnet_fabric_t *ft; /* protect against bozo input */ if (NULL == fabric) { return PMIX_ERR_BAD_PARAM; } else if (NULL == fabric->module) { /* this might be a remote request, so look at the * list of fabrics we have registered locally and * see if we have one with the matching index */ PMIX_LIST_FOREACH (ft, &pmix_pnet_globals.fabrics, pmix_pnet_fabric_t) { if (fabric->index == ft->index) { module = ft->module; } else if (NULL != fabric->name && NULL != ft->name && 0 == strcmp(ft->name, fabric->name)) { module = ft->module; } } } else { active = (pmix_pnet_fabric_t *) fabric->module; module = (pmix_pnet_module_t *) active->module; } if (NULL == module) { return PMIX_ERR_BAD_PARAM; } if (NULL != module->update_fabric) { rc = module->update_fabric(fabric); } return rc; } pmix_status_t pmix_pnet_base_deregister_fabric(pmix_fabric_t *fabric) { pmix_status_t rc = PMIX_SUCCESS; pmix_pnet_fabric_t *active; pmix_pnet_module_t *module = NULL; pmix_pnet_fabric_t *ft; /* protect against bozo input */ if (NULL == fabric) { return PMIX_ERR_BAD_PARAM; } else if (NULL == fabric->module) { /* this might be a remote request, so look at the * list of fabrics we have registered locally and * see if we have one with the matching index */ PMIX_LIST_FOREACH (ft, &pmix_pnet_globals.fabrics, pmix_pnet_fabric_t) { if (fabric->index == ft->index) { module = ft->module; } else if (NULL != fabric->name && NULL != ft->name && 0 == strcmp(ft->name, fabric->name)) { module = ft->module; } } } else { active = (pmix_pnet_fabric_t *) fabric->module; module = (pmix_pnet_module_t *) active->module; } if (NULL == module) { return PMIX_ERR_BAD_PARAM; } if (NULL != module->deregister_fabric) { rc = module->deregister_fabric(fabric); } return rc; } pmix-6.1.1~rc2/src/mca/pnet/tcp/0000775000175000017500000000000015203536752016560 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pnet/tcp/configure.m40000664000175000017500000000132315203536752021002 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_pmix_pnet_tcp_CONFIG([action-if-can-compile], # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pnet_tcp_CONFIG], [ AC_CONFIG_FILES([src/mca/pnet/tcp/Makefile]) AS_IF([test "yes" = "no"], [$1 pmix_pnet_tcp_happy=yes], [$2 pmix_pnet_tcp_happy=no]) PMIX_SUMMARY_ADD([Transports], [TCP], [], [$pmix_pnet_tcp_happy]) ])dnl pmix-6.1.1~rc2/src/mca/pnet/tcp/pnet_tcp_component.c0000664000175000017500000001021215203536752022616 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "pnet_tcp.h" #include "src/mca/pnet/pnet.h" #include "src/util/pmix_argv.h" static pmix_status_t component_register(void); static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_pnet_tcp_component_t pmix_mca_pnet_tcp_component = { .super = { PMIX_PNET_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "tcp", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_register_component_params = component_register, .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .static_ports = NULL, .default_request = NULL, .include = NULL, .exclude = NULL }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pnet, tcp) static pmix_status_t component_register(void) { pmix_mca_base_component_t *component = &pmix_mca_pnet_tcp_component.super; pmix_mca_pnet_tcp_component.static_ports = NULL; (void) pmix_mca_base_component_var_register( component, "static_ports", "Static ports for procs, expressed as a semi-colon delimited " "list of type:(optional)plane:Comma-delimited list of ranges (e.g., " "\"tcp:10.10.10.0/24:32000-32100,33000;udp:40000,40005\")", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pnet_tcp_component.static_ports); (void) pmix_mca_base_component_var_register( component, "default_network_allocation", "Semi-colon delimited list of (optional)type:(optional)plane:Comma-delimited list of " "ranges " "(e.g., \"udp:10.10.10.0/24:3\", or \"5\" if the choice of " "type and plane isn't critical)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pnet_tcp_component.default_request); pmix_mca_pnet_tcp_component.incparms = NULL; (void) pmix_mca_base_component_var_register( component, "include_envars", "Comma-delimited list of envars to harvest (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pnet_tcp_component.incparms); if (NULL != pmix_mca_pnet_tcp_component.incparms) { pmix_mca_pnet_tcp_component.include = PMIx_Argv_split(pmix_mca_pnet_tcp_component.incparms, ','); } pmix_mca_pnet_tcp_component.excparms = NULL; (void) pmix_mca_base_component_var_register( component, "exclude_envars", "Comma-delimited list of envars to exclude (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pnet_tcp_component.excparms); if (NULL != pmix_mca_pnet_tcp_component.excparms) { pmix_mca_pnet_tcp_component.exclude = PMIx_Argv_split(pmix_mca_pnet_tcp_component.excparms, ','); } return PMIX_SUCCESS; } static pmix_status_t component_open(void) { return PMIX_SUCCESS; } static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 5; *module = (pmix_mca_base_module_t *) &pmix_tcp_module; return PMIX_SUCCESS; } static pmix_status_t component_close(void) { return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pnet/tcp/Makefile.am0000664000175000017500000000411315203536752020613 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(pnet_tcp_CPPFLAGS) headers = pnet_tcp.h sources = \ pnet_tcp_component.c \ pnet_tcp.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pnet_tcp_DSO lib = lib_sources = component = pmix_mca_pnet_tcp.la component_sources = $(headers) $(sources) else lib = libpmix_mca_pnet_tcp.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_pnet_tcp_la_SOURCES = $(component_sources) pmix_mca_pnet_tcp_la_LIBADD = $(pnet_tcp_LIBS) pmix_mca_pnet_tcp_la_LDFLAGS = -module -avoid-version $(pnet_tcp_LDFLAGS) if NEED_LIBPMIX pmix_mca_pnet_tcp_la_LIBADD += $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_pnet_tcp_la_SOURCES = $(lib_sources) libpmix_mca_pnet_tcp_la_LIBADD = $(pnet_tcp_LIBS) libpmix_mca_pnet_tcp_la_LDFLAGS = -module -avoid-version $(pnet_tcp_LDFLAGS) pmix-6.1.1~rc2/src/mca/pnet/tcp/pnet_tcp.h0000664000175000017500000000144715203536752020553 0ustar alastairalastair/* * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PNET_OPA_H #define PMIX_PNET_OPA_H #include "src/include/pmix_config.h" #include "src/mca/pnet/pnet.h" BEGIN_C_DECLS typedef struct { pmix_pnet_base_component_t super; char *static_ports; char *default_request; char *incparms; char *excparms; char **include; char **exclude; int nverts; uint16_t **costmatrix; } pmix_pnet_tcp_component_t; /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_pnet_tcp_component_t pmix_mca_pnet_tcp_component; extern pmix_pnet_module_t pmix_tcp_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pnet/tcp/pnet_tcp.c0000664000175000017500000013160015203536752020541 0ustar alastairalastair/* * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/preg/preg.h" #include "src/util/apmix_lfg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_parse_options.h" #include "src/util/pmix_if.h" #include "src/util/pmix_environ.h" #include "pnet_tcp.h" #include "src/mca/pnet/base/base.h" #define PMIX_TCP_SETUP_APP_KEY "pmix.tcp.setup.app.key" #define PMIX_TCP_INVENTORY_KEY "pmix.tcp.inventory" static pmix_status_t tcp_init(void); static void tcp_finalize(void); static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); static pmix_status_t setup_local_network(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo); static pmix_status_t setup_fork(pmix_namespace_t *nptr, const pmix_proc_t *peer, char ***env); static void child_finalized(pmix_proc_t *peer); static void local_app_finalized(pmix_namespace_t *nptr); static void deregister_nspace(pmix_namespace_t *nptr); static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_inventory_cbfunc_t cbfunc, void *cbdata); static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata); pmix_pnet_module_t pmix_tcp_module = {.name = "tcp", .init = tcp_init, .finalize = tcp_finalize, .allocate = allocate, .setup_local_network = setup_local_network, .setup_fork = setup_fork, .child_finalized = child_finalized, .local_app_finalized = local_app_finalized, .deregister_nspace = deregister_nspace, .collect_inventory = collect_inventory, .deliver_inventory = deliver_inventory}; typedef struct { pmix_list_item_t super; char *device; char *address; } tcp_device_t; /* local tracker objects */ typedef struct { pmix_list_item_t super; pmix_list_t devices; char *type; char *plane; char **ports; size_t nports; } tcp_available_ports_t; typedef struct { pmix_list_item_t super; char *nspace; char **ports; tcp_available_ports_t *src; // source of the allocated ports } tcp_port_tracker_t; static pmix_list_t allocations, available; static pmix_status_t process_request(pmix_namespace_t *nptr, char *idkey, int ports_per_node, tcp_port_tracker_t *trk, pmix_list_t *ilist); static void dcon(tcp_device_t *p) { p->device = NULL; p->address = NULL; } static void ddes(tcp_device_t *p) { if (NULL != p->device) { free(p->device); } if (NULL != p->address) { free(p->address); } } static PMIX_CLASS_INSTANCE(tcp_device_t, pmix_list_item_t, dcon, ddes); static void tacon(tcp_available_ports_t *p) { PMIX_CONSTRUCT(&p->devices, pmix_list_t); p->type = NULL; p->plane = NULL; p->ports = NULL; p->nports = 0; } static void tades(tcp_available_ports_t *p) { PMIX_LIST_DESTRUCT(&p->devices); if (NULL != p->type) { free(p->type); } if (NULL != p->plane) { free(p->plane); } if (NULL != p->ports) { PMIx_Argv_free(p->ports); } } static PMIX_CLASS_INSTANCE(tcp_available_ports_t, pmix_list_item_t, tacon, tades); static void ttcon(tcp_port_tracker_t *p) { p->nspace = NULL; p->ports = NULL; p->src = NULL; } static void ttdes(tcp_port_tracker_t *p) { size_t n, m, mstart; if (NULL != p->nspace) { free(p->nspace); } if (NULL != p->src) { if (NULL != p->ports) { mstart = 0; for (n = 0; NULL != p->ports[n]; n++) { /* find an empty position */ for (m = mstart; m < p->src->nports; m++) { if (NULL == p->src->ports[m]) { p->src->ports[m] = strdup(p->ports[n]); mstart = m + 1; break; } } } PMIx_Argv_free(p->ports); } PMIX_RELEASE(p->src); // maintain accounting } else if (NULL != p->ports) { PMIx_Argv_free(p->ports); } } static PMIX_CLASS_INSTANCE(tcp_port_tracker_t, pmix_list_item_t, ttcon, ttdes); static pmix_status_t tcp_init(void) { tcp_available_ports_t *trk; char *p, **grps; size_t n; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: tcp init"); /* if we are not the "gateway", then there is nothing * for us to do */ if (!PMIX_PEER_IS_GATEWAY(pmix_globals.mypeer)) { return PMIX_SUCCESS; } PMIX_CONSTRUCT(&allocations, pmix_list_t); PMIX_CONSTRUCT(&available, pmix_list_t); /* if we have no static ports, then we don't have * anything to manage. However, we cannot just disqualify * ourselves as we may still need to provide inventory. * * NOTE: need to check inventory in addition to MCA param as * the inventory may have reported back static ports */ if (NULL == pmix_mca_pnet_tcp_component.static_ports) { return PMIX_SUCCESS; } /* split on semi-colons */ grps = PMIx_Argv_split(pmix_mca_pnet_tcp_component.static_ports, ';'); for (n = 0; NULL != grps[n]; n++) { trk = PMIX_NEW(tcp_available_ports_t); if (NULL == trk) { PMIx_Argv_free(grps); return PMIX_ERR_NOMEM; } /* there must be at least one colon */ if (NULL == (p = strrchr(grps[n], ':'))) { PMIx_Argv_free(grps); return PMIX_ERR_BAD_PARAM; } /* extract the ports */ *p = '\0'; ++p; pmix_util_parse_range_options(p, &trk->ports); trk->nports = PMIx_Argv_count(trk->ports); /* see if they provided a plane */ if (NULL != (p = strchr(grps[n], ':'))) { /* yep - save the plane */ *p = '\0'; ++p; trk->plane = strdup(p); } /* the type is just what is left at the front */ trk->type = strdup(grps[n]); pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "TYPE: %s PLANE %s", trk->type, (NULL == trk->plane) ? "NULL" : trk->plane); pmix_list_append(&available, &trk->super); } PMIx_Argv_free(grps); return PMIX_SUCCESS; } static void tcp_finalize(void) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: tcp finalize"); if (PMIX_PEER_IS_GATEWAY(pmix_globals.mypeer)) { PMIX_LIST_DESTRUCT(&allocations); PMIX_LIST_DESTRUCT(&available); } } /* some network users may want to encrypt their communications * as a means of securing them, or include a token in their * messaging headers for some minimal level of security. This * is far from perfect, but is provided to illustrate how it * can be done. The resulting info is placed into the * app_context's env array so it will automatically be pushed * into the environment of every MPI process when launched. * * In a more perfect world, there would be some privileged place * to store the crypto key and the encryption would occur * in a non-visible driver - but we don't have a mechanism * for doing so. */ static inline void generate_key(uint64_t *unique_key) { pmix_rng_buff_t rng; pmix_srand(&rng, (unsigned int) time(NULL)); unique_key[0] = pmix_rand(&rng); unique_key[1] = pmix_rand(&rng); } /* when allocate is called, we look at our table of available static addresses * and assign an address to each process on a node based on its node rank. * This will prevent collisions as the host RM is responsible for correctly * setting the node rank. Note that node ranks will "rollover" when they * hit whatever maximum value the host RM supports, and that they will * increase monotonically as new jobs are launched until hitting that * max value. So we need to take into account the number of static * ports we were given and check to ensure we have enough to hand out * * NOTE: this implementation is offered as an example that can * undoubtedly be vastly improved/optimized */ static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist) { uint64_t unique_key[2]; size_t n, nreqs = 0; int ports_per_node = 0; pmix_kval_t *kv; pmix_status_t rc; pmix_info_t *requests = NULL; char **reqs, *cptr; bool allocated = false, seckey = false, envars = false; tcp_port_tracker_t *trk; tcp_available_ports_t *avail, *aptr; pmix_list_t mylist; pmix_buffer_t buf; char *type = NULL, *plane = NULL, *idkey = NULL; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp:allocate for nspace %s", nptr->nspace); /* if I am not the gateway, then ignore this call - should never * happen, but check to be safe */ if (!PMIX_PEER_IS_GATEWAY(pmix_globals.mypeer)) { return PMIX_SUCCESS; } if (NULL == info) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* check directives to see if a crypto key and/or * network resource allocations requested */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ENVARS) || PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ALL)) { envars = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(info, PMIX_ALLOC_FABRIC)) { /* this info key includes an array of pmix_info_t, each providing * a key (that is to be used as the key for the allocated ports) and * a number of ports to allocate for that key */ if (PMIX_DATA_ARRAY != info->value.type || NULL == info->value.data.darray || PMIX_INFO != info->value.data.darray->type || NULL == info->value.data.darray->array) { /* they made an error */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } requests = (pmix_info_t *) info->value.data.darray->array; nreqs = info->value.data.darray->size; } } if (envars) { if (NULL != pmix_mca_pnet_tcp_component.include) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: tcp harvesting envars %s excluding %s", (NULL == pmix_mca_pnet_tcp_component.incparms) ? "NONE" : pmix_mca_pnet_tcp_component.incparms, (NULL == pmix_mca_pnet_tcp_component.excparms) ? "NONE" : pmix_mca_pnet_tcp_component.excparms); rc = pmix_util_harvest_envars(pmix_mca_pnet_tcp_component.include, pmix_mca_pnet_tcp_component.exclude, ilist); if (PMIX_SUCCESS != rc) { return rc; } } } if (NULL == requests) { return PMIX_ERR_TAKE_NEXT_OPTION; } pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp:allocate alloc_network for nspace %s", nptr->nspace); /* cycle thru the provided array and see if this refers to * tcp/udp-based resources - there is no required ordering * of the keys, so just have to do a search */ for (n = 0; n < nreqs; n++) { if (0 == strncasecmp(requests[n].key, PMIX_ALLOC_FABRIC_TYPE, PMIX_MAX_KEYLEN)) { /* check for bozo error */ if (PMIX_STRING != requests[n].value.type || NULL == requests[n].value.data.string) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } type = requests[n].value.data.string; } else if (0 == strncasecmp(requests[n].key, PMIX_ALLOC_FABRIC_PLANE, PMIX_MAX_KEYLEN)) { /* check for bozo error */ if (PMIX_STRING != requests[n].value.type || NULL == requests[n].value.data.string) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } plane = requests[n].value.data.string; } else if (0 == strncasecmp(requests[n].key, PMIX_ALLOC_FABRIC_ENDPTS, PMIX_MAX_KEYLEN)) { rc = PMIx_Value_get_number(&requests[n].value, &ports_per_node, PMIX_INT); if (PMIX_SUCCESS != rc) { return rc; } } else if (0 == strncmp(requests[n].key, PMIX_ALLOC_FABRIC_ID, PMIX_MAX_KEYLEN)) { /* check for bozo error */ if (PMIX_STRING != requests[n].value.type || NULL == requests[n].value.data.string) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } idkey = requests[n].value.data.string; } else if (0 == strncasecmp(requests[n].key, PMIX_ALLOC_FABRIC_SEC_KEY, PMIX_MAX_KEYLEN)) { seckey = PMIX_INFO_TRUE(&requests[n]); } } /* we at least require an attribute key for the response */ if (NULL == idkey) { return PMIX_ERR_BAD_PARAM; } PMIX_CONSTRUCT(&mylist, pmix_list_t); /* must include the idkey */ kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { return PMIX_ERR_NOMEM; } kv->key = strdup(PMIX_ALLOC_FABRIC_ID); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_STRING; kv->value->data.string = strdup(idkey); pmix_list_append(&mylist, &kv->super); /* note that they might not provide * the network type (letting it fall to a default component * based on priority), and they are not required to provide * a plane. In addition, they are allowed to simply request * a network security key without asking for endpts */ if (NULL != type) { /* if it is tcp or udp, then this is something we should process */ if (0 == strcasecmp(type, "tcp")) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp:allocate allocating TCP ports for nspace %s", nptr->nspace); /* do we have static tcp ports? */ avail = NULL; PMIX_LIST_FOREACH (aptr, &available, tcp_available_ports_t) { if (0 == strcmp(aptr->type, "tcp")) { /* if they specified a plane, then require it */ if (NULL != plane && (NULL == aptr->plane || 0 != strcmp(aptr->plane, plane))) { continue; } avail = aptr; break; } } /* nope - they asked for something that we cannot do */ if (NULL == avail) { PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_NOT_AVAILABLE; } /* setup to track the assignment */ trk = PMIX_NEW(tcp_port_tracker_t); if (NULL == trk) { PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_NOMEM; } trk->nspace = strdup(nptr->nspace); PMIX_RETAIN(avail); trk->src = avail; pmix_list_append(&allocations, &trk->super); rc = process_request(nptr, idkey, ports_per_node, trk, &mylist); if (PMIX_SUCCESS != rc) { /* return the allocated ports */ pmix_list_remove_item(&allocations, &trk->super); PMIX_RELEASE(trk); PMIX_LIST_DESTRUCT(&mylist); return rc; } allocated = true; } else if (0 == strcasecmp(requests[n].value.data.string, "udp")) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp:allocate allocating UDP ports for nspace %s", nptr->nspace); /* do we have static udp ports? */ avail = NULL; PMIX_LIST_FOREACH (aptr, &available, tcp_available_ports_t) { if (0 == strcmp(aptr->type, "udp")) { /* if they specified a plane, then require it */ if (NULL != plane && (NULL == aptr->plane || 0 != strcmp(aptr->plane, plane))) { continue; } avail = aptr; break; } } /* nope - they asked for something that we cannot do */ if (NULL == avail) { PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_NOT_AVAILABLE; } /* setup to track the assignment */ trk = PMIX_NEW(tcp_port_tracker_t); if (NULL == trk) { PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_NOMEM; } trk->nspace = strdup(nptr->nspace); PMIX_RETAIN(avail); trk->src = avail; pmix_list_append(&allocations, &trk->super); rc = process_request(nptr, idkey, ports_per_node, trk, &mylist); if (PMIX_SUCCESS != rc) { /* return the allocated ports */ pmix_list_remove_item(&allocations, &trk->super); PMIX_RELEASE(trk); PMIX_LIST_DESTRUCT(&mylist); return rc; } allocated = true; } else { /* unsupported type */ pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp:allocate unsupported type %s for nspace %s", type, nptr->nspace); PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_TAKE_NEXT_OPTION; } } else { if (NULL != plane) { /* if they didn't specify a type, but they did specify a plane, we can * see if that is a plane we recognize */ PMIX_LIST_FOREACH (aptr, &available, tcp_available_ports_t) { if (0 != strcmp(aptr->plane, plane)) { continue; } /* setup to track the assignment */ trk = PMIX_NEW(tcp_port_tracker_t); if (NULL == trk) { PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_NOMEM; } trk->nspace = strdup(nptr->nspace); PMIX_RETAIN(aptr); trk->src = aptr; pmix_list_append(&allocations, &trk->super); rc = process_request(nptr, idkey, ports_per_node, trk, &mylist); if (PMIX_SUCCESS != rc) { /* return the allocated ports */ pmix_list_remove_item(&allocations, &trk->super); PMIX_RELEASE(trk); PMIX_LIST_DESTRUCT(&mylist); return rc; } allocated = true; break; } } else { /* if they didn't specify either type or plane, then we got here because * nobody of a higher priority could act as a default transport - so try * to provide something here, starting by looking at any provided setting */ if (NULL != pmix_mca_pnet_tcp_component.default_request) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp:allocate allocating default ports %s for nspace %s", pmix_mca_pnet_tcp_component.default_request, nptr->nspace); reqs = PMIx_Argv_split(pmix_mca_pnet_tcp_component.default_request, ';'); for (n = 0; NULL != reqs[n]; n++) { /* if there is no colon, then it is just * a number of ports to use */ type = NULL; plane = NULL; if (NULL == (cptr = strrchr(reqs[n], ':'))) { avail = (tcp_available_ports_t *) pmix_list_get_first(&available); } else { *cptr = '\0'; ++cptr; ports_per_node = strtoul(cptr, NULL, 10); /* look for the plane */ cptr -= 2; if (NULL != (cptr = strrchr(cptr, ':'))) { *cptr = '\0'; ++cptr; plane = cptr; } type = reqs[n]; avail = NULL; PMIX_LIST_FOREACH (aptr, &available, tcp_available_ports_t) { if (0 == strcmp(aptr->type, type)) { /* if they specified a plane, then require it */ if (NULL != plane && (NULL == aptr->plane || 0 != strcmp(aptr->plane, plane))) { continue; } avail = aptr; break; } } /* if we didn't find it, that isn't an error - just ignore */ if (NULL == avail) { continue; } } /* setup to track the assignment */ trk = PMIX_NEW(tcp_port_tracker_t); if (NULL == trk) { PMIx_Argv_free(reqs); PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_NOMEM; } trk->nspace = strdup(nptr->nspace); PMIX_RETAIN(avail); trk->src = avail; pmix_list_append(&allocations, &trk->super); rc = process_request(nptr, idkey, ports_per_node, trk, &mylist); if (PMIX_SUCCESS != rc) { /* return the allocated ports */ pmix_list_remove_item(&allocations, &trk->super); PMIX_RELEASE(trk); PMIX_LIST_DESTRUCT(&mylist); return rc; } allocated = true; } } else { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp:allocate allocating %d ports/node for nspace %s", ports_per_node, nptr->nspace); if (0 == ports_per_node) { /* nothing to allocate */ PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_TAKE_NEXT_OPTION; } avail = (tcp_available_ports_t *) pmix_list_get_first(&available); if (NULL != avail) { /* setup to track the assignment */ trk = PMIX_NEW(tcp_port_tracker_t); if (NULL == trk) { PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_NOMEM; } trk->nspace = strdup(nptr->nspace); PMIX_RETAIN(avail); trk->src = avail; pmix_list_append(&allocations, &trk->super); rc = process_request(nptr, idkey, ports_per_node, trk, &mylist); if (PMIX_SUCCESS != rc) { /* return the allocated ports */ pmix_list_remove_item(&allocations, &trk->super); PMIX_RELEASE(trk); } else { allocated = true; } } } } if (!allocated) { /* nope - we cannot help */ PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_TAKE_NEXT_OPTION; } } if (seckey) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp: generate seckey"); generate_key(unique_key); kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_NOMEM; } kv->key = strdup(PMIX_ALLOC_FABRIC_SEC_KEY); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_BYTE_OBJECT; kv->value->data.bo.bytes = (char *) malloc(2 * sizeof(uint64_t)); if (NULL == kv->value->data.bo.bytes) { PMIX_RELEASE(kv); PMIX_LIST_DESTRUCT(&mylist); return PMIX_ERR_NOMEM; } memcpy(kv->value->data.bo.bytes, unique_key, 2 * sizeof(uint64_t)); kv->value->data.bo.size = 2 * sizeof(uint64_t); pmix_list_append(&mylist, &kv->super); } n = pmix_list_get_size(&mylist); if (0 < n) { PMIX_CONSTRUCT(&buf, pmix_buffer_t); /* pack the number of kvals for ease on the remote end */ PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &buf, &n, 1, PMIX_SIZE); /* cycle across the list and pack the kvals */ while (NULL != (kv = (pmix_kval_t *) pmix_list_remove_first(&mylist))) { PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &buf, kv, 1, PMIX_KVAL); PMIX_RELEASE(kv); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&buf); PMIX_LIST_DESTRUCT(&mylist); return rc; } } PMIX_LIST_DESTRUCT(&mylist); kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(PMIX_TCP_SETUP_APP_KEY); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); PMIX_DESTRUCT(&buf); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_BYTE_OBJECT; PMIX_UNLOAD_BUFFER(&buf, kv->value->data.bo.bytes, kv->value->data.bo.size); PMIX_DESTRUCT(&buf); pmix_list_append(ilist, &kv->super); } /* if we got here, then we processed this specific request, so * indicate that by returning success */ return PMIX_SUCCESS; } /* upon receipt of the launch message, each daemon adds the * static address assignments to the job-level info cache * for that job */ static pmix_status_t setup_local_network(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo) { size_t n, m, nkvals; pmix_buffer_t bkt; int32_t cnt; pmix_kval_t *kv; pmix_status_t rc; pmix_info_t *jinfo, stinfo; char *idkey = NULL; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp:setup_local_network"); if (NULL != info) { idkey = strdup("default"); for (n = 0; n < ninfo; n++) { /* look for my key */ if (0 == strncmp(info[n].key, PMIX_TCP_SETUP_APP_KEY, PMIX_MAX_KEYLEN)) { /* this macro NULLs and zero's the incoming bo */ PMIX_LOAD_BUFFER(pmix_globals.mypeer, &bkt, info[n].value.data.bo.bytes, info[n].value.data.bo.size); /* unpack the number of kvals */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &nkvals, &cnt, PMIX_SIZE); /* setup the info array */ PMIX_INFO_CONSTRUCT(&stinfo); pmix_strncpy(stinfo.key, idkey, PMIX_MAX_KEYLEN); stinfo.value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(stinfo.value.data.darray, nkvals, PMIX_INFO); jinfo = (pmix_info_t *) stinfo.value.data.darray->array; /* cycle thru the blob and extract the kvals */ kv = PMIX_NEW(pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, kv, &cnt, PMIX_KVAL); m = 0; while (PMIX_SUCCESS == rc) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "recvd KEY %s %s", kv->key, (PMIX_STRING == kv->value->type) ? kv->value->data.string : "NON-STRING"); /* xfer the value to the info */ pmix_strncpy(jinfo[m].key, kv->key, PMIX_MAX_KEYLEN); PMIX_BFROPS_VALUE_XFER(rc, pmix_globals.mypeer, &jinfo[m].value, kv->value); /* if this is the ID key, save it */ if (NULL == idkey && 0 == strncmp(kv->key, PMIX_ALLOC_FABRIC_ID, PMIX_MAX_KEYLEN)) { idkey = strdup(kv->value->data.string); } ++m; PMIX_RELEASE(kv); kv = PMIX_NEW(pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, kv, &cnt, PMIX_KVAL); } /* restore the incoming data */ info[n].value.data.bo.bytes = bkt.base_ptr; info[n].value.data.bo.size = bkt.bytes_used; bkt.base_ptr = NULL; bkt.bytes_used = 0; /* if they didn't include a network ID, then this is an error */ if (NULL == idkey) { PMIX_INFO_FREE(jinfo, nkvals); return PMIX_ERR_BAD_PARAM; } /* cache the info on the job */ PMIX_GDS_CACHE_JOB_INFO(rc, pmix_globals.mypeer, nptr, &stinfo, 1); PMIX_INFO_DESTRUCT(&stinfo); } } } if (NULL != idkey) { free(idkey); } return PMIX_SUCCESS; } static pmix_status_t setup_fork(pmix_namespace_t *nptr, const pmix_proc_t *peer, char ***env) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp:setup_fork"); return PMIX_SUCCESS; } /* when a local client finalizes, the server gives us a chance * to do any required local cleanup for that peer. We don't * have anything we need to do */ static void child_finalized(pmix_proc_t *peer) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp child finalized"); } /* when all local clients for a given job finalize, the server * provides an opportunity for the local network to cleanup * any resources consumed locally by the clients of that job. * We don't have anything we need to do */ static void local_app_finalized(pmix_namespace_t *nptr) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp app finalized"); } /* when the job completes, the scheduler calls the "deregister nspace" * PMix function, which in turn calls my TCP component to release the * assignments for that job. The addresses are marked as "available" * for reuse on the next job. */ static void deregister_nspace(pmix_namespace_t *nptr) { tcp_port_tracker_t *trk; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp deregister nspace %s", nptr->nspace); /* if we are not the "gateway", then there is nothing * for us to do */ if (!PMIX_PEER_IS_GATEWAY(pmix_globals.mypeer)) { return; } /* find this tracker */ PMIX_LIST_FOREACH (trk, &allocations, tcp_port_tracker_t) { if (0 == strcmp(nptr->nspace, trk->nspace)) { pmix_list_remove_item(&allocations, &trk->super); PMIX_RELEASE(trk); pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp released tracker for nspace %s", nptr->nspace); return; } } } static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_inventory_cbfunc_t cbfunc, void *cbdata) { pmix_inventory_rollup_t *cd = (pmix_inventory_rollup_t *) cbdata; char *prefix; char myconnhost[PMIX_MAXHOSTNAMELEN] = {0}; char name[32], uri[2048]; struct sockaddr_storage my_ss; char *foo; pmix_buffer_t bucket, pbkt; int i; pmix_status_t rc; bool found = false; pmix_byte_object_t pbo; pmix_kval_t *kv; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp:collect_inventory"); /* setup the bucket - we will pass the results as a blob */ PMIX_CONSTRUCT(&bucket, pmix_buffer_t); /* add our hostname */ PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &bucket, &pmix_globals.hostname, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&bucket); return rc; } /* look at all available interfaces */ for (i = pmix_ifbegin(); i >= 0; i = pmix_ifnext(i)) { if (PMIX_SUCCESS != pmix_ifindextoaddr(i, (struct sockaddr *) &my_ss, sizeof(my_ss))) { pmix_output(0, "ptl_tcp: problems getting address for index %i (kernel index %i)\n", i, pmix_ifindextokindex(i)); continue; } /* ignore non-ip4/6 interfaces */ if (AF_INET != my_ss.ss_family && AF_INET6 != my_ss.ss_family) { continue; } /* get the name for diagnostic purposes */ pmix_ifindextoname(i, name, sizeof(name)); /* ignore any virtual interfaces */ if (0 == strncmp(name, "vir", 3)) { continue; } /* ignore the loopback device */ if (pmix_ifisloopback(i)) { continue; } if (AF_INET == my_ss.ss_family) { prefix = "tcp4://"; inet_ntop(AF_INET, &((struct sockaddr_in *) &my_ss)->sin_addr, myconnhost, PMIX_MAXHOSTNAMELEN - 1); } else if (AF_INET6 == my_ss.ss_family) { prefix = "tcp6://"; inet_ntop(AF_INET6, &((struct sockaddr_in6 *) &my_ss)->sin6_addr, myconnhost, PMIX_MAXHOSTNAMELEN - 1); } else { continue; } (void) pmix_snprintf(uri, 2048, "%s%s", prefix, myconnhost); pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "TCP INVENTORY ADDING: %s %s", name, uri); found = true; /* pack the name of the device */ PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); foo = &name[0]; PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &pbkt, &foo, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&bucket); return rc; } /* pack the address */ foo = &uri[0]; PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &pbkt, &foo, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); PMIX_DESTRUCT(&bucket); return rc; } /* extract the resulting blob - this is a device unit */ PMIX_UNLOAD_BUFFER(&pbkt, pbo.bytes, pbo.size); /* now load that into the blob */ PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &bucket, &pbo, 1, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_BYTE_OBJECT_DESTRUCT(&pbo); PMIX_DESTRUCT(&bucket); return rc; } } /* if we have anything to report, then package it up for transfer */ if (!found) { PMIX_DESTRUCT(&bucket); return PMIX_ERR_TAKE_NEXT_OPTION; } /* extract the resulting blob */ PMIX_UNLOAD_BUFFER(&bucket, pbo.bytes, pbo.size); kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(PMIX_TCP_INVENTORY_KEY); PMIX_VALUE_CREATE(kv->value, 1); pmix_value_load(kv->value, &pbo, PMIX_BYTE_OBJECT); PMIX_BYTE_OBJECT_DESTRUCT(&pbo); pmix_list_append(&cd->payload, &kv->super); return PMIX_SUCCESS; } static pmix_status_t process_request(pmix_namespace_t *nptr, char *idkey, int ports_per_node, tcp_port_tracker_t *trk, pmix_list_t *ilist) { char **plist; pmix_kval_t *kv; size_t m; int p, ppn; tcp_available_ports_t *avail = trk->src; kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { return PMIX_ERR_NOMEM; } kv->key = strdup(idkey); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_STRING; kv->value->data.string = NULL; if (0 == ports_per_node) { /* find the maxprocs on the nodes in this nspace and * allocate that number of resources */ return PMIX_ERR_NOT_SUPPORTED; } else { ppn = ports_per_node; } /* assemble the list of ports */ p = 0; plist = NULL; for (m = 0; p < ppn && m < avail->nports; m++) { if (NULL != avail->ports[m]) { PMIx_Argv_append_nosize(&trk->ports, avail->ports[m]); PMIx_Argv_append_nosize(&plist, avail->ports[m]); free(avail->ports[m]); avail->ports[m] = NULL; ++p; } } /* if we couldn't find enough, then that's an error */ if (p < ppn) { PMIX_RELEASE(kv); /* the caller will release trk, and that will return * any allocated ports back to the available list */ return PMIX_ERR_OUT_OF_RESOURCE; } /* pass the value */ kv->value->data.string = PMIx_Argv_join(plist, ','); PMIx_Argv_free(plist); pmix_list_append(ilist, &kv->super); /* track where it came from */ kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { return PMIX_ERR_NOMEM; } kv->key = strdup(idkey); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_STRING; kv->value->data.string = strdup(trk->src->type); pmix_list_append(ilist, &kv->super); if (NULL != trk->src->plane) { kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { return PMIX_ERR_NOMEM; } kv->key = strdup(idkey); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_STRING; kv->value->data.string = strdup(trk->src->plane); pmix_list_append(ilist, &kv->super); } return PMIX_SUCCESS; } static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t bkt, pbkt; size_t n; int32_t cnt; char *hostname, *device, *address; pmix_byte_object_t pbo; pmix_pnet_node_t *nd, *ndptr; pmix_pnet_resource_t *lt, *lst; tcp_available_ports_t *prts; tcp_device_t *res; pmix_status_t rc; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:tcp deliver inventory"); for (n = 0; n < ninfo; n++) { if (0 == strncmp(info[n].key, PMIX_TCP_INVENTORY_KEY, PMIX_MAX_KEYLEN)) { /* this is our inventory in the form of a blob */ PMIX_LOAD_BUFFER(pmix_globals.mypeer, &bkt, info[n].value.data.bo.bytes, info[n].value.data.bo.size); /* first is the host this came from */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &hostname, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); /* must _not_ destruct bkt as we don't * own the bytes! */ return rc; } /* do we already have this node? */ nd = NULL; PMIX_LIST_FOREACH (ndptr, &pmix_pnet_globals.nodes, pmix_pnet_node_t) { if (0 == strcmp(hostname, ndptr->name)) { nd = ndptr; break; } } if (NULL == nd) { nd = PMIX_NEW(pmix_pnet_node_t); nd->name = strdup(hostname); pmix_list_append(&pmix_pnet_globals.nodes, &nd->super); } /* does this node already have a TCP entry? */ lst = NULL; PMIX_LIST_FOREACH (lt, &nd->resources, pmix_pnet_resource_t) { if (0 == strcmp(lt->name, "tcp")) { lst = lt; break; } } if (NULL == lst) { lst = PMIX_NEW(pmix_pnet_resource_t); lst->name = strdup("tcp"); pmix_list_append(&nd->resources, &lst->super); } /* this is a list of ports and devices */ prts = PMIX_NEW(tcp_available_ports_t); pmix_list_append(&lst->resources, &prts->super); /* cycle across any provided interfaces */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &pbo, &cnt, PMIX_BYTE_OBJECT); while (PMIX_SUCCESS == rc) { /* load the byte object for unpacking */ PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); PMIX_LOAD_BUFFER(pmix_globals.mypeer, &pbkt, pbo.bytes, pbo.size); /* unpack the name of the device */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &pbkt, &device, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); /* must _not_ destruct bkt as we don't * own the bytes! */ return rc; } /* unpack the address */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &pbkt, &address, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&pbkt); /* must _not_ destruct bkt as we don't * own the bytes! */ return rc; } /* store this on the node */ res = PMIX_NEW(tcp_device_t); res->device = device; res->address = address; pmix_list_append(&prts->devices, &res->super); PMIX_DESTRUCT(&pbkt); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &pbo, &cnt, PMIX_BYTE_OBJECT); } if (5 < pmix_output_get_verbosity(pmix_pnet_base_framework.framework_output)) { /* dump the resulting node resources */ pmix_output(0, "TCP resources for node: %s", nd->name); PMIX_LIST_FOREACH (lt, &nd->resources, pmix_pnet_resource_t) { if (0 == strcmp(lt->name, "tcp")) { PMIX_LIST_FOREACH (prts, <->resources, tcp_available_ports_t) { device = NULL; if (NULL != prts->ports) { device = PMIx_Argv_join(prts->ports, ','); } pmix_output(0, "\tPorts: %s", (NULL == device) ? "UNSPECIFIED" : device); if (NULL != device) { free(device); } PMIX_LIST_FOREACH (res, &prts->devices, tcp_device_t) { pmix_output(0, "\tDevice: %s", res->device); pmix_output(0, "\tAddress: %s", res->address); } } } } } } } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pnet/Makefile.am0000664000175000017500000000254615203536752020035 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2016 Intel, Inc. All rights reserved # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(LTDLINCL) # main library setup noinst_LTLIBRARIES = libmca_pnet.la libmca_pnet_la_SOURCES = # local files headers = pnet.h sources = # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.include libmca_pnet_la_SOURCES += $(headers) $(sources) distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/pnet/simptest/0000775000175000017500000000000015203536752017642 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pnet/simptest/pnet_simptest_component.c0000664000175000017500000001007715203536752024773 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "pnet_simptest.h" #include "src/mca/pnet/pnet.h" #include "src/util/pmix_argv.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_register(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_pnet_simptest_component_t pmix_mca_pnet_simptest_component = { .super = { PMIX_PNET_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "simptest", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, .pmix_mca_register_component_params = component_register }, .configfile = NULL }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pnet, simptest) static pmix_status_t component_register(void) { pmix_mca_base_component_t *component = &pmix_mca_pnet_simptest_component.super; (void) pmix_mca_base_component_var_register( component, "config_file", "Path of file containing network coordinate configuration", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pnet_simptest_component.configfile); return PMIX_SUCCESS; } static pmix_status_t component_open(void) { int index; const pmix_mca_base_var_storage_t *value = NULL; if (NULL == pmix_mca_pnet_simptest_component.configfile || !PMIX_PROC_IS_SERVER(&pmix_globals.mypeer->proc_type)) { /* nothing we can do without a description * of the fabric topology */ return PMIX_ERROR; } /* we only allow ourselves to be considered IF the user * specifically requested so */ if (0 > (index = pmix_mca_base_var_find("pmix", "pnet", NULL, NULL))) { return PMIX_ERROR; } pmix_mca_base_var_get_value(index, &value, NULL, NULL); if (NULL != value && NULL != value->stringval && '\0' != value->stringval[0]) { if (NULL != strcasestr(value->stringval, "simptest")) { return PMIX_SUCCESS; } } return PMIX_ERROR; } static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 0; *module = (pmix_mca_base_module_t *) &pmix_simptest_module; return PMIX_SUCCESS; } static pmix_status_t component_close(void) { return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pnet/simptest/help-pnet-simptest.txt0000664000175000017500000000067615203536752024156 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. # # Copyright (c) 2017 Intel, Inc. All rights reserved. # Copyright (c) 2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English general help file for the file sensor # [missing-file] The specified configuration file was not found: File: %s Please fix and try again. pmix-6.1.1~rc2/src/mca/pnet/simptest/configure.m40000664000175000017500000000163215203536752022067 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2020 Intel, Inc. All rights reserved. # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_pmix_pnet_simptest_CONFIG([action-if-can-compile], # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pnet_simptest_CONFIG], [ AC_CONFIG_FILES([src/mca/pnet/simptest/Makefile]) AC_ARG_WITH([simptest], [AS_HELP_STRING([--with-simptest], [Include simptest fabric support])], [pmix_want_simptest=yes], [pmix_want_simptest=no]) AS_IF([test "$pmix_want_simptest" = "yes"], [$1], [$2]) PMIX_SUMMARY_ADD([Transports], [Simptest], [], [$pmix_want_simptest]) ])dnl pmix-6.1.1~rc2/src/mca/pnet/simptest/Makefile.am0000664000175000017500000000377015203536752021705 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2022-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # EXTRA_DIST = help-pnet-simptest.txt headers = pnet_simptest.h sources = \ pnet_simptest_component.c \ pnet_simptest.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pnet_simptest_DSO lib = lib_sources = component = pmix_mca_pnet_simptest.la component_sources = $(headers) $(sources) else lib = libpmix_mca_pnet_simptest.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_pnet_simptest_la_SOURCES = $(component_sources) pmix_mca_pnet_simptest_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_pnet_simptest_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_pnet_simptest_la_SOURCES = $(lib_sources) libpmix_mca_pnet_simptest_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/pnet/simptest/pnet_simptest.c0000664000175000017500000003471315203536752022714 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/class/pmix_pointer_array.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/preg/preg.h" #include "src/util/pmix_alfg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_show_help.h" #include "pnet_simptest.h" #include "src/mca/pnet/base/base.h" #include "src/mca/pnet/pnet.h" static pmix_status_t simptest_init(void); static void simptest_finalize(void); static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); static pmix_status_t setup_local_network(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo); pmix_pnet_module_t pmix_simptest_module = { .name = "simptest", .init = simptest_init, .finalize = simptest_finalize, .allocate = allocate, .setup_local_network = setup_local_network}; /* internal tracking structures */ typedef struct { pmix_list_item_t super; char *name; pmix_geometry_t *devices; size_t ndevices; pmix_endpoint_t *endpts; size_t nendpts; pmix_device_distance_t *distances; size_t ndists; } pnet_node_t; static void ndcon(pnet_node_t *p) { p->name = NULL; p->devices = NULL; p->endpts = NULL; p->distances = NULL; } static void nddes(pnet_node_t *p) { if (NULL != p->name) { free(p->name); } if (NULL != p->devices) { PMIX_GEOMETRY_FREE(p->devices, p->ndevices); } if (NULL != p->endpts) { PMIX_ENDPOINT_FREE(p->endpts, p->nendpts); } if (NULL != p->distances) { PMIX_DEVICE_DIST_FREE(p->distances, p->ndists); } } static PMIX_CLASS_INSTANCE(pnet_node_t, pmix_list_item_t, ndcon, nddes); /* internal variables */ static pmix_list_t mynodes; #define PMIX_SIMPTEST_MAX_LINE_LENGTH 1024 static char *localgetline(FILE *fp) { char *ret, *buff; char input[PMIX_SIMPTEST_MAX_LINE_LENGTH]; int i = 0; ret = fgets(input, PMIX_SIMPTEST_MAX_LINE_LENGTH, fp); if (NULL != ret) { if ('\0' != input[0]) { input[strlen(input) - 1] = '\0'; /* remove newline */ /* strip any leading whitespace */ while (' ' == input[i] || '\t' == input[i]) { i++; } } buff = strdup(&input[i]); return buff; } return NULL; } static pmix_status_t simptest_init(void) { FILE *fp = NULL; char *line, **tmp; pnet_node_t *nd; int n, cache[1024]; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: simptest init"); PMIX_CONSTRUCT(&mynodes, pmix_list_t); /* if the configuration was given in a file, then build * the topology so we can respond to requests */ if (NULL == pmix_mca_pnet_simptest_component.configfile) { /* we cannot function */ return PMIX_ERR_INIT; } fp = fopen(pmix_mca_pnet_simptest_component.configfile, "r"); if (NULL == fp) { pmix_show_help("help-pnet-simptest.txt", "missing-file", true, pmix_mca_pnet_simptest_component.configfile); return PMIX_ERR_FATAL; } while (NULL != (line = localgetline(fp))) { /* if the line starts with a '#' or is blank, then * it is a comment and we ignore it */ if (0 == strlen(line) || '#' == line[0]) { free(line); continue; } tmp = PMIx_Argv_split(line, ' '); nd = PMIX_NEW(pnet_node_t); nd->name = strdup(tmp[0]); pmix_list_append(&mynodes, &nd->super); n = 0; while (n < 1024 && NULL != tmp[n + 1]) { cache[n] = strtol(tmp[n + 1], NULL, 10); ++n; } nd->coord.dims = n; nd->coord.coord = (int *) malloc(nd->coord.dims * sizeof(int)); memcpy(nd->coord.coord, cache, nd->coord.dims * sizeof(int)); free(line); PMIx_Argv_free(tmp); } if (NULL != fp) { fclose(fp); } return PMIX_SUCCESS; } static void simptest_finalize(void) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet: simptest finalize"); PMIX_LIST_DESTRUCT(&mynodes); } /* NOTE: if there is any binary data to be transferred, then * this function MUST pack it for transport as the host will * not know how to do so */ static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist) { size_t m, n, q; char **procs = NULL; char **nodes = NULL; pmix_status_t rc; pmix_list_t mylist; char **locals; pnet_node_t *nd, *nd2; pmix_kval_t *kv; pmix_info_t *iptr, *ip2; pmix_data_array_t *darray, *d2, *d3; pmix_rank_t rank; pmix_buffer_t buf; pmix_byte_object_t *bptr; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:simptest:allocate for nspace %s", nptr->nspace); /* if I am not the scheduler, then ignore this call - should never * happen, but check to be safe */ if (!PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { return PMIX_SUCCESS; } if (NULL == info) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* check directives to see if a crypto key and/or * fabric resource allocations requested */ for (n = 0; n < ninfo; n++) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:simptest:allocate processing key %s", info[n].key); if (PMIX_CHECK_KEY(&info[n], PMIX_PROC_MAP)) { rc = pmix_preg.parse_procs(info[n].value.data.string, &procs); if (PMIX_SUCCESS != rc) { return PMIX_ERR_BAD_PARAM; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_NODE_MAP)) { rc = pmix_preg.parse_nodes(info[n].value.data.string, &nodes); if (PMIX_SUCCESS != rc) { return PMIX_ERR_BAD_PARAM; } } } if (NULL == procs || NULL == nodes) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:simptest:allocate missing proc/node map for nspace %s", nptr->nspace); /* not an error - continue to next active component */ return PMIX_ERR_TAKE_NEXT_OPTION; } PMIX_CONSTRUCT(&mylist, pmix_list_t); pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:simptest:allocate assigning endpoints for nspace %s", nptr->nspace); /* cycle across the nodes and add the endpoints * for each proc on the node - we assume the same * list of static endpoints on each node */ for (n = 0; NULL != nodes[n]; n++) { /* split the procs for this node */ locals = PMIx_Argv_split(procs[n], ','); if (NULL == locals) { /* aren't any on this node */ continue; } /* find this node in our list */ nd = NULL; PMIX_LIST_FOREACH (nd2, &mynodes, pnet_node_t) { if (0 == strcmp(nd2->name, nodes[n])) { nd = nd2; break; } } if (NULL == nd) { /* should be impossible */ rc = PMIX_ERR_NOT_FOUND; PMIX_ERROR_LOG(rc); goto cleanup; } kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { rc = PMIX_ERR_NOMEM; goto cleanup; } kv->key = strdup(PMIX_ALLOC_FABRIC_ENDPTS); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); rc = PMIX_ERR_NOMEM; goto cleanup; } kv->value->type = PMIX_DATA_ARRAY; /* for each proc, we will assign an endpt * for each NIC on the node */ q = PMIx_Argv_count(locals); PMIX_DATA_ARRAY_CREATE(darray, q, PMIX_INFO); kv->value->data.darray = darray; iptr = (pmix_info_t *) darray->array; for (m = 0; NULL != locals[m]; m++) { /* each proc has one endpoint and one coord corresponding to the * node they upon which they are executing */ PMIX_LOAD_KEY(iptr[m].key, PMIX_PROC_DATA); PMIX_DATA_ARRAY_CREATE(d2, 3, PMIX_INFO); iptr[m].value.type = PMIX_DATA_ARRAY; iptr[m].value.data.darray = d2; ip2 = (pmix_info_t *) d2->array; /* start with the rank */ rank = strtoul(locals[m], NULL, 10); pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:simptest:allocate assigning %d endpoints for rank %u", (int) q, rank); PMIX_INFO_LOAD(&ip2[0], PMIX_RANK, &rank, PMIX_PROC_RANK); /* the second element in this array is the coord */ PMIX_INFO_LOAD(&ip2[1], PMIX_FABRIC_COORDINATE, &nd->coord, PMIX_COORD); /* third element is the endpt */ PMIX_DATA_ARRAY_CREATE(d3, 1, PMIX_BYTE_OBJECT); PMIX_LOAD_KEY(ip2[2].key, PMIX_FABRIC_ENDPT); ip2[2].value.type = PMIX_DATA_ARRAY; ip2[2].value.data.darray = d3; bptr = (pmix_byte_object_t *) d3->array; bptr[0].bytes = strdup(nd->endpt.bytes); bptr[0].size = nd->endpt.size; } PMIx_Argv_free(locals); locals = NULL; pmix_list_append(&mylist, &kv->super); } /* pack all our results into a buffer for xmission to the backend */ n = pmix_list_get_size(&mylist); if (0 < n) { PMIX_CONSTRUCT(&buf, pmix_buffer_t); /* cycle across the list and pack the kvals */ while (NULL != (kv = (pmix_kval_t *) pmix_list_remove_first(&mylist))) { PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &buf, kv, 1, PMIX_KVAL); PMIX_RELEASE(kv); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&buf); goto cleanup; } } kv = PMIX_NEW(pmix_kval_t); kv->key = strdup("pmix-pnet-simptest-blob"); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); PMIX_DESTRUCT(&buf); rc = PMIX_ERR_NOMEM; goto cleanup; } kv->value->type = PMIX_BYTE_OBJECT; PMIX_UNLOAD_BUFFER(&buf, kv->value->data.bo.bytes, kv->value->data.bo.size); PMIX_DESTRUCT(&buf); pmix_list_append(ilist, &kv->super); } cleanup: PMIX_LIST_DESTRUCT(&mylist); if (NULL != nodes) { PMIx_Argv_free(nodes); } if (NULL != procs) { PMIx_Argv_free(procs); } if (NULL != locals) { PMIx_Argv_free(locals); } return rc; } static pmix_status_t setup_local_network(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo) { size_t n, nvals; pmix_buffer_t bkt; int32_t cnt; pmix_kval_t *kv; pmix_status_t rc; pmix_info_t *iptr; pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:simptest:setup_local_network with %lu info", (unsigned long) ninfo); if (NULL != info) { for (n = 0; n < ninfo; n++) { /* look for my key */ if (PMIX_CHECK_KEY(&info[n], "pmix-pnet-simptest-blob")) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:simptest:setup_local_network found my blob"); /* this macro NULLs and zero's the incoming bo */ PMIX_LOAD_BUFFER(pmix_globals.mypeer, &bkt, info[n].value.data.bo.bytes, info[n].value.data.bo.size); /* cycle thru the blob and extract the kvals */ kv = PMIX_NEW(pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, kv, &cnt, PMIX_KVAL); while (PMIX_SUCCESS == rc) { pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "recvd KEY %s %s", kv->key, PMIx_Data_type_string(kv->value->type)); /* check for the fabric ID */ if (PMIX_CHECK_KEY(kv, PMIX_ALLOC_FABRIC_ENDPTS)) { iptr = (pmix_info_t *) kv->value->data.darray->array; nvals = kv->value->data.darray->size; /* each element in this array is itself an array containing * the rank and the endpts and coords assigned to that rank. This is * precisely the data we need to cache for the job, so * just do so) */ pmix_output_verbose(2, pmix_pnet_base_framework.framework_output, "pnet:simptest:setup_local_network caching %d endpts", (int) nvals); PMIX_GDS_CACHE_JOB_INFO(rc, pmix_globals.mypeer, nptr, iptr, nvals); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(kv); return rc; } } PMIX_RELEASE(kv); kv = PMIX_NEW(pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, kv, &cnt, PMIX_KVAL); } PMIX_RELEASE(kv); /* restore the incoming data */ info[n].value.data.bo.bytes = bkt.base_ptr; info[n].value.data.bo.size = bkt.bytes_used; bkt.base_ptr = NULL; bkt.bytes_used = 0; } } } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pnet/simptest/pnet_simptest.h0000664000175000017500000000145015203536752022711 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PNET_simptest_H #define PMIX_PNET_simptest_H #include "src/include/pmix_config.h" #include "src/mca/pnet/pnet.h" BEGIN_C_DECLS typedef struct { pmix_pnet_base_component_t super; char *configfile; } pmix_pnet_simptest_component_t; /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_pnet_simptest_component_t pmix_mca_pnet_simptest_component; extern pmix_pnet_module_t pmix_simptest_module; /* define a key for any blob we need to send in a launch msg */ #define PMIX_PNET_SIMPTEST_BLOB "pmix.pnet.simptest.blob" END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pnet/pnet.h0000664000175000017500000002262015203536752017113 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved. * * Copyright (c) 2015-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * This interface is for use by PMIx servers to obtain network-related info * such as security keys that need to be shared across applications, and to * setup network support for applications prior to launch * * Available plugins may be defined at runtime via the typical MCA parameter * syntax. */ #ifndef PMIX_PNET_H #define PMIX_PNET_H #include "src/include/pmix_config.h" #include "include/pmix.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/mca.h" #include "src/server/pmix_server_ops.h" BEGIN_C_DECLS /****** MODULE DEFINITION ******/ /** * Initialize the module. Returns an error if the module cannot * run, success if it can and wants to be used. */ typedef pmix_status_t (*pmix_pnet_base_module_init_fn_t)(void); /** * Finalize the module. Tear down any allocated storage, disconnect * from any system support (e.g., LDAP server) */ typedef void (*pmix_pnet_base_module_fini_fn_t)(void); /** * Allocate network resources. This can be called either as a result * of a call to PMIx_Allocate_resources, or by the scheduler to * provide an opportunity for the network to define values that * are to be passed to an application. This can include security * tokens required for application processes to communicate with * each other, environmental variables picked up at the login node * for forwarding to compute nodes, or allocation of static endpts */ typedef pmix_status_t (*pmix_pnet_base_module_allocate_fn_t)(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); /** * Give the local network library an opportunity to setup address information * for the application by passing in the layout type and a regex describing * the layout */ typedef pmix_status_t (*pmix_pnet_base_module_setup_local_net_fn_t)(pmix_nspace_env_cache_t *nptr, pmix_info_t info[], size_t ninfo); /** * Provide an opportunity for the local network library to cleanup when a * local application process terminates */ typedef void (*pmix_pnet_base_module_child_finalized_fn_t)(pmix_proc_t *peer); /** * Provide an opportunity for the local network library to cleanup after * all local clients for a given application have terminated */ typedef void (*pmix_pnet_base_module_local_app_finalized_fn_t)(pmix_namespace_t *nptr); /** * Provide an opportunity for the fabric components to cleanup any * resource allocations (e.g., static ports) they may have assigned */ typedef void (*pmix_pnet_base_module_dregister_nspace_fn_t)(pmix_namespace_t *nptr); /** * Request that the module report local inventory for its network type. * * If the operation can be performed immediately, then the module should just * add the inventory (as pmix_kval_t's) to the provided object's list and * return PMIX_SUCCESS. * * If the module needs to perform some non-atomic operation * (e.g., query a fabric manager), then it should shift to its own internal * thread, return PMIX_OPERATION_IN_PROGRESS, and execute the provided * callback function when the operation is completed. * * If there is no inventory to report, then just return PMIX_SUCCESS. * * If the module should be providing inventory but encounters an error, * then immediately return an error code if the error is immediately detected, * or execute the callback function with an error code if it is detected later. */ typedef pmix_status_t (*pmix_pnet_base_module_collect_inventory_fn_t)( pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory); /** * Deliver inventory for archiving by corresponding modules * * Modules are to search the provided inventory to identify * entries provided by their remote peers, and then store that * information in a manner that can be queried/retrieved by * the host RM and/or scheduler. If the operation can be * performed immediately (e.g., storing the information in * the local hash table), then the module should just perform * that operation and return the appropriate status. * * If the module needs to perform some non-atomic operation * (e.g., storing the information in a non-local DHT), then * it should shift to its own internal thread, return * PMIX_OPERATION_IN_PROGRESS, and execute the provided * callback function when the operation is completed. * * If there is no relevant inventory to archive, then the module * should just return PMIX_SUCCESS; */ typedef pmix_status_t (*pmix_pnet_base_module_deliver_inventory_fn_t)( pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs); /* Register to provide cost information * * Scan the provided directives to identify if the module * should service this request - directives could include * ordered specification of fabric type or a direct request * for a specific component */ typedef pmix_status_t (*pmix_pnet_base_module_register_fabric_fn_t)(pmix_fabric_t *fabric, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata); /* Update the fabric information */ typedef pmix_status_t (*pmix_pnet_base_module_update_fabric_fn_t)(pmix_fabric_t *fabric); /* Deregister the fabric, giving the associated module a chance to cleanup */ typedef pmix_status_t (*pmix_pnet_base_module_deregister_fabric_fn_t)(pmix_fabric_t *fabric); /** * Base structure for a PNET module. Each component should malloc a * copy of the module structure for each fabric plane they support. */ typedef struct { char *name; /* provide a pointer to plane-specific metadata */ void *plane; /* init/finalize */ pmix_pnet_base_module_init_fn_t init; pmix_pnet_base_module_fini_fn_t finalize; pmix_pnet_base_module_allocate_fn_t allocate; pmix_pnet_base_module_setup_local_net_fn_t setup_local_network; pmix_pnet_base_module_child_finalized_fn_t child_finalized; pmix_pnet_base_module_local_app_finalized_fn_t local_app_finalized; pmix_pnet_base_module_dregister_nspace_fn_t deregister_nspace; pmix_pnet_base_module_collect_inventory_fn_t collect_inventory; pmix_pnet_base_module_deliver_inventory_fn_t deliver_inventory; pmix_pnet_base_module_register_fabric_fn_t register_fabric; pmix_pnet_base_module_update_fabric_fn_t update_fabric; pmix_pnet_base_module_deregister_fabric_fn_t deregister_fabric; } pmix_pnet_module_t; /* define a few API versions of the functions - main difference is the * string nspace parameter instead of a pointer to pmix_namespace_t. This * is done as an optimization to avoid having every component look for * that pointer */ typedef pmix_status_t (*pmix_pnet_base_API_allocate_fn_t)(char *nspace, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); typedef pmix_status_t (*pmix_pnet_base_API_setup_local_net_fn_t)(char *nspace, pmix_info_t info[], size_t ninfo); /** * Give the network framework an opportunity to add any envars to the * environment of a local application process prior to fork/exec */ typedef pmix_status_t (*pmix_pnet_base_API_setup_fork_fn_t)(const pmix_proc_t *peer, char ***env); typedef void (*pmix_pnet_base_API_deregister_nspace_fn_t)(char *nspace); /** * Base structure for a PNET API */ typedef struct { char *name; /* init/finalize */ pmix_pnet_base_module_init_fn_t init; pmix_pnet_base_module_fini_fn_t finalize; pmix_pnet_base_API_allocate_fn_t allocate; pmix_pnet_base_API_setup_local_net_fn_t setup_local_network; pmix_pnet_base_API_setup_fork_fn_t setup_fork; pmix_pnet_base_module_child_finalized_fn_t child_finalized; pmix_pnet_base_module_local_app_finalized_fn_t local_app_finalized; pmix_pnet_base_API_deregister_nspace_fn_t deregister_nspace; pmix_pnet_base_module_collect_inventory_fn_t collect_inventory; pmix_pnet_base_module_deliver_inventory_fn_t deliver_inventory; pmix_pnet_base_module_register_fabric_fn_t register_fabric; pmix_pnet_base_module_update_fabric_fn_t update_fabric; pmix_pnet_base_module_deregister_fabric_fn_t deregister_fabric; } pmix_pnet_API_module_t; /* declare the global APIs */ PMIX_EXPORT extern pmix_pnet_API_module_t pmix_pnet; /* * the standard component data structure */ typedef pmix_mca_base_component_t pmix_pnet_base_component_t; /* * Macro for use in components that are of type pnet */ #define PMIX_PNET_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("pnet", 1, 0, 0) END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/base/0000775000175000017500000000000015203536752015736 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/base/pmix_mca_base_components_open.c0000664000175000017500000003346615203536752024173 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2013 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2022 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2015 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2014 Hochschule Esslingen. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_show_help.h" /* * Local functions */ static int open_components(pmix_mca_base_framework_t *framework); struct pmix_mca_base_dummy_framework_list_item_t { pmix_list_item_t super; pmix_mca_base_framework_t framework; }; typedef struct fc_pair { pmix_list_item_t li; char *framework_name; char *component_name; } fc_pair_t; PMIX_CLASS_DECLARATION(fc_pair_t); typedef enum { SHOW_LOAD_ERRORS_ALL, SHOW_LOAD_ERRORS_INCLUDE, SHOW_LOAD_ERRORS_EXCLUDE, SHOW_LOAD_ERRORS_NONE, } show_load_type_t; static show_load_type_t show_load_errors = SHOW_LOAD_ERRORS_ALL; static pmix_list_t show_load_errors_include = PMIX_LIST_STATIC_INIT; static pmix_list_t show_load_errors_exclude = PMIX_LIST_STATIC_INIT; static void fc_pair_constructor(struct fc_pair *obj) { obj->framework_name = NULL; obj->component_name = NULL; } static void fc_pair_destructor(struct fc_pair *obj) { free(obj->framework_name); obj->framework_name = NULL; free(obj->component_name); obj->component_name = NULL; } PMIX_CLASS_INSTANCE(fc_pair_t, pmix_list_item_t, fc_pair_constructor, fc_pair_destructor); /* * Parse the content of the show_load_errors value * * Valid values: * - "all" * - "none" * - comma-delimited list of items, each of which is * "framework[/component]" * * The comma-delimited list may be prefixed with a "^". */ int pmix_mca_base_show_load_errors_init(void) { PMIX_CONSTRUCT(&show_load_errors_include, pmix_list_t); PMIX_CONSTRUCT(&show_load_errors_exclude, pmix_list_t); // Check to see if mca_base_component_show_load_errors is a // boolean value pmix_value_t value; PMIX_VALUE_LOAD(&value, pmix_mca_base_component_show_load_errors, PMIX_STRING); pmix_boolean_t ret = PMIx_Value_true(&value); PMIx_Value_destruct(&value); // Treat true values as a synonym for "all", and false values // as a synonym for "none". if (PMIX_BOOL_TRUE == ret) { show_load_errors = SHOW_LOAD_ERRORS_ALL; } else if (PMIX_BOOL_FALSE == ret) { show_load_errors = SHOW_LOAD_ERRORS_NONE; } else { // must not be a bool, so treat as a string if (0 == strcasecmp(pmix_mca_base_component_show_load_errors, "all")) { show_load_errors = SHOW_LOAD_ERRORS_ALL; } else if (0 == strcasecmp(pmix_mca_base_component_show_load_errors, "none")) { show_load_errors = SHOW_LOAD_ERRORS_NONE; } else { // We have a comma-delimited list of values. Is it // "include"-style, or "exclude" style? size_t pos = 0; pmix_list_t *list = &show_load_errors_include; show_load_errors = SHOW_LOAD_ERRORS_INCLUDE; if ('^' == pmix_mca_base_component_show_load_errors[0]) { pos = 1; list = &show_load_errors_exclude; show_load_errors = SHOW_LOAD_ERRORS_EXCLUDE; } // Examine each of the values in the comma-delimited list. // Each value can be of the form "framework" or // "framework/component". char **values = PMIx_Argv_split(pmix_mca_base_component_show_load_errors + pos, ','); if (values == NULL) { ret = PMIX_ERROR; pmix_show_help("help-pmix-mca-base.txt", "internal error during init", true, __func__, __FILE__, __LINE__, ret, "Failed to argv split pmix_mca_base_component_show_load_errors"); return ret; } char **split; int argc; fc_pair_t *fcp; for (int i = 0; values[i] != NULL; ++i) { split = PMIx_Argv_split(values[i], '/'); if (NULL == split) { ret = PMIX_ERROR; pmix_show_help("help-pmix-mca-base.txt", "internal error during init", true, __func__, __FILE__, __LINE__, ret, "Failed to argv split pmix_mca_base_component_show_load_errors value"); return ret; } argc = PMIx_Argv_count(split); if (0 == argc) { // This should never happen ret = PMIX_ERROR; pmix_show_help("help-pmix-mca-base.txt", "internal error during init", true, __func__, __FILE__, __LINE__, ret, "Argv split resulted in 0 tokens"); return ret; } if (0 == strlen(split[0])) { // Empty entry (e.g., consecutive commas); silently // skip it continue; } if (argc > 2) { ret = PMIX_ERR_BAD_PARAM; pmix_show_help("help-pmix-mca-base.txt", "show_load_errors: too many /", true, values[i]); return ret; } fcp = PMIX_NEW(fc_pair_t); if (NULL == fcp) { ret = PMIX_ERR_OUT_OF_RESOURCE; pmix_show_help("help-pmix-mca-base.txt", "internal error during init", true, __func__, __FILE__, __LINE__, ret, "Failed to alloc new fc_pair_t"); return ret; } fcp->framework_name = split[0]; if (2 == argc) { fcp->component_name = split[1]; } pmix_list_append(list, &fcp->li); } PMIx_Argv_free(values); } } return PMIX_SUCCESS; } bool pmix_mca_base_show_load_errors(const char *framework_name, const char *component_name) { if (SHOW_LOAD_ERRORS_ALL == show_load_errors) { return true; } else if (SHOW_LOAD_ERRORS_NONE == show_load_errors) { return false; } if (NULL == framework_name) { return false; } // If we get here, it means we have an include or exclude list. // Setup for what to do based on whether it's an include or // exclude list. pmix_list_t *list; bool value_if_match_found; if (SHOW_LOAD_ERRORS_INCLUDE == show_load_errors) { list = &show_load_errors_include; value_if_match_found = true; } else { list = &show_load_errors_exclude; value_if_match_found = false; } // See if the framework_name/component_name pair is found in the // active list. fc_pair_t *item; PMIX_LIST_FOREACH(item, list, fc_pair_t) { if (0 == strcmp(framework_name, item->framework_name)) { if (NULL == component_name) { // If there's no component name, then we're matching // all components in this framework. return value_if_match_found; } else if (0 == strcmp(component_name, item->component_name)) { // We matched both the framework *and* component name. return value_if_match_found; } } } // We didn't find a match. return !value_if_match_found; } int pmix_mca_base_show_load_errors_finalize(void) { PMIX_DESTRUCT(&show_load_errors_include); PMIX_DESTRUCT(&show_load_errors_exclude); return PMIX_SUCCESS; } /** * Function for finding and opening either all MCA components, or the * one that was specifically requested via a MCA parameter. */ int pmix_mca_base_framework_components_open(pmix_mca_base_framework_t *framework, pmix_mca_base_open_flag_t flags) { /* Open flags are not used at this time. Suppress compiler warning. */ if (flags & PMIX_MCA_BASE_OPEN_FIND_COMPONENTS) { bool open_dso_components = !(flags & PMIX_MCA_BASE_OPEN_STATIC_ONLY); /* Find and load requested components */ int ret = pmix_mca_base_component_find(NULL, framework, false, open_dso_components); if (PMIX_SUCCESS != ret) { return ret; } } /* Open all registered components */ return open_components(framework); } /* * Traverse the entire list of found components (a list of * pmix_mca_base_component_t instances). If the requested_component_names * array is empty, or the name of each component in the list of found * components is in the requested_components_array, try to open it. * If it opens, add it to the components_available list. */ static int open_components(pmix_mca_base_framework_t *framework) { pmix_list_t *components = &framework->framework_components; int output_id = framework->framework_output; pmix_mca_base_component_list_item_t *cli, *next; int ret; /* If pmix_mca_base_framework_register_components was called with the MCA_BASE_COMPONENTS_ALL flag we need to trim down and close any extra components we do not want open */ ret = pmix_mca_base_components_filter(framework); if (PMIX_SUCCESS != ret) { return ret; } /* Announce */ pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca: base: components_open: opening %s components", framework->framework_name); /* Traverse the list of components */ PMIX_LIST_FOREACH_SAFE (cli, next, components, pmix_mca_base_component_list_item_t) { const pmix_mca_base_component_t *component = cli->cli_component; pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca: base: components_open: found loaded component %s", component->pmix_mca_component_name); if (NULL != component->pmix_mca_open_component) { /* Call open if register didn't call it already */ ret = component->pmix_mca_open_component(); if (PMIX_SUCCESS == ret) { pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca: base: components_open: " "component %s open function successful", component->pmix_mca_component_name); } else { if (PMIX_ERR_NOT_AVAILABLE != ret) { /* If the component returns PMIX_ERR_NOT_AVAILABLE, it's a cue to "silently ignore me" -- it's not a failure, it's just a way for the component to say "nope!". Otherwise, however, display an error. We may end up displaying this twice, but it may go to separate streams. So better to be redundant than to not display the error in the stream where it was expected. */ if (pmix_mca_base_show_load_errors(component->pmix_mca_type_name, component->pmix_mca_component_name)) { pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_ERROR, output_id, "mca: base: components_open: component %s " "/ %s open function failed", component->pmix_mca_type_name, component->pmix_mca_component_name); } pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca: base: components_open: " "component %s open function failed", component->pmix_mca_component_name); } pmix_mca_base_component_close(component, output_id); pmix_list_remove_item(components, &cli->super); PMIX_RELEASE(cli); } } } /* All done */ return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_var_enum.h0000664000175000017500000002316315203536752022577 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2016 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #if !defined(PMIX_MCA_BASE_VAR_ENUM_H) # define PMIX_MCA_BASE_VAR_ENUM_H # include "src/include/pmix_config.h" # include "pmix_common.h" # include "src/class/pmix_object.h" /* Output mode for dumping var enumerators. * Caution: Not 1:1 with pmix_mca_base_var_dump_type_t, appropriate * conversion is required, see PMIX_MCA_BASE_VAR_DUMP_TYPE_TO_ENUM_DUMP_TYPE() */ typedef enum { /* Dump human-readable strings */ PMIX_MCA_BASE_VAR_ENUM_DUMP_READABLE = 0, /* Dump human-readable strings, with color where supported */ PMIX_MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR = 1 } pmix_mca_base_var_enum_dump_type_t; #define PMIX_MCA_BASE_VAR_DUMP_TYPE_TO_ENUM_DUMP_TYPE(var_dump_type) \ (PMIX_MCA_BASE_VAR_DUMP_READABLE_COLOR == (var_dump_type) ? \ PMIX_MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR : PMIX_MCA_BASE_VAR_ENUM_DUMP_READABLE) typedef struct pmix_mca_base_var_enum_t pmix_mca_base_var_enum_t; /** * Get the number of values in the enumerator * * @param[in] self the enumerator * @param[out] count the number of values in the enumerator */ typedef int (*pmix_mca_base_var_enum_get_count_fn_t)(pmix_mca_base_var_enum_t *self, int *count); /** * Get the value and its string representation for an index 0..get_count() * * @param[in] self the enumerator * @param[in] index the index to get the value of * @param[out] value integer value * @param[out] string_value string value */ typedef int (*pmix_mca_base_var_enum_get_value_fn_t)(pmix_mca_base_var_enum_t *self, int index, int *value, const char **string_value); /** * Look up the integer value of a string * * @param[in] self the enumerator * @param[in] string_value string to lookup * @param[out] value integer value for the string * * @retval PMIX_SUCCESS if found * @retval PMIX_ERR_VALUE_OUT_OF_BOUNDS if not */ typedef int (*pmix_mca_base_var_enum_vfs_fn_t)(pmix_mca_base_var_enum_t *self, const char *string_value, int *value); /** * Dump a textual representation of all the values in an enumerator * * @param[in] self the enumerator * @param[out] out the string representation * * @retval PMIX_SUCCESS on success * @retval pmix error on error */ typedef int (*pmix_mca_base_var_enum_dump_fn_t)(pmix_mca_base_var_enum_t *self, char **out, pmix_mca_base_var_enum_dump_type_t output_type); /** * Get the string representation for an enumerator value * * @param[in] self the enumerator * @param[in] value integer value * @param[out] string_value string value for value * * @retval PMIX_SUCCESS on success * @retval PMIX_ERR_VALUE_OUT_OF_BOUNDS if not found * * @long This function returns the string value for a given integer value in the * {string_value} parameter. The {string_value} parameter may be NULL in which case * no string is returned. If a string is returned in {string_value} the caller * must free the string with free(). */ typedef int (*pmix_mca_base_var_enum_sfv_fn_t)(pmix_mca_base_var_enum_t *self, const int value, char **string_value); /** * The default enumerator class takes in a list of integer-string pairs. If a * string is read from an environment variable or a file value the matching * integer value is used for the MCA variable. */ struct pmix_mca_base_var_enum_value_t { int value; const char *string; }; typedef struct pmix_mca_base_var_enum_value_t pmix_mca_base_var_enum_value_t; /** * enumerator base class */ struct pmix_mca_base_var_enum_t { pmix_object_t super; /** Is the enumerator statically allocated */ bool enum_is_static; /** Name of this enumerator. This value is duplicated from the argument provided to pmix_mca_base_var_enum_create() */ char *enum_name; /** Get the number of values this enumerator represents. Subclasses should override the default function. */ pmix_mca_base_var_enum_get_count_fn_t get_count; /** Get the value and string representation for a particular index. Subclasses should override the default function */ pmix_mca_base_var_enum_get_value_fn_t get_value; /** Given a string return corresponding integer value. If the string does not match a valid value return PMIX_ERR_VALUE_OUT_OF_BOUNDS */ pmix_mca_base_var_enum_vfs_fn_t value_from_string; /** Given an integer return the corresponding string value. If the integer does not match a valid value return PMIX_ERR_VALUE_OUT_OF_BOUNDS */ pmix_mca_base_var_enum_sfv_fn_t string_from_value; /** Dump a textual representation of the enumerator. The caller is responsible for freeing the string */ pmix_mca_base_var_enum_dump_fn_t dump; int enum_value_count; /** Copy of the enumerators values (used by the default functions). This array and and the strings it contains are freed by the destructor if not NULL. */ pmix_mca_base_var_enum_value_t *enum_values; }; /** * The default flag enumerator class takes in a list of integer-string pairs. If a * string is read from an environment variable or a file value the matching * flag value is used for the MCA variable. The conflicting_flag is used to * indicate any flags that should conflict. */ struct pmix_mca_base_var_enum_value_flag_t { /** flag value (must be power-of-two) */ int flag; /** corresponding string name */ const char *string; /** conflicting flag(s) if any */ int conflicting_flag; }; typedef struct pmix_mca_base_var_enum_value_flag_t pmix_mca_base_var_enum_value_flag_t; /** * flag enumerator base class */ struct pmix_mca_base_var_enum_flag_t { /** use the existing enumerator interface */ pmix_mca_base_var_enum_t super; /** flag value(s) */ pmix_mca_base_var_enum_value_flag_t *enum_flags; }; typedef struct pmix_mca_base_var_enum_flag_t pmix_mca_base_var_enum_flag_t; /** * Object declaration for pmix_mca_base_var_enum_t */ PMIX_CLASS_DECLARATION(pmix_mca_base_var_enum_t); /** * Create a new default enumerator * * @param[in] name Name for this enumerator * @param[in] values List of values terminated with a NULL .string * member. * @param[out] enumerator Newly created enumerator. * * @retval PMIX_SUCCESS On success * @retval pmix error code On error * * This function creates a value enumerator for integer variables. The * OUT enumerator value will be a newly OBJ_NEW'ed object that should * be released by the caller via OBJ_RELEASE. * * Note that the output enumerator can be OBJ_RELEASE'd after it has * been used in a cvar or pvar registration, because the variable * registration functions will OBJ_RETAIN the enumberator. * * Note that all the strings in the values[] array are strdup'ed into * internal storage, meaning that the caller can free all of the * strings passed in values[] after pmix_mca_base_var_enum_create() * returns. */ int pmix_mca_base_var_enum_create(const char *name, const pmix_mca_base_var_enum_value_t values[], pmix_mca_base_var_enum_t **enumerator); /** * Create a new default flag enumerator * * @param[in] name Name for this enumerator * @param[in] flags List of flags terminated with a NULL .string * member. * @param[out] enumerator Newly created enumerator. * * @retval PMIX_SUCCESS On success * @retval pmix error code On error * * This function creates a flag enumerator for integer variables. The * OUT enumerator value will be a newly OBJ_NEW'ed object that should * be released by the caller via OBJ_RELEASE. * * Note that the output enumerator can be OBJ_RELEASE'd after it has * been used in a cvar or pvar registration, because the variable * registration functions will OBJ_RETAIN the enumberator. * * Note that all the strings in the values[] array are strdup'ed into * internal storage, meaning that the caller can free all of the * strings passed in values[] after pmix_mca_base_var_enum_create() * returns. */ int pmix_mca_base_var_enum_create_flag(const char *name, const pmix_mca_base_var_enum_value_flag_t flags[], pmix_mca_base_var_enum_flag_t **enumerator); /* standard enumerators. it is invalid to call OBJ_RELEASE on any of these enumerators */ /** * Boolean enumerator * * This enumerator maps: * positive integer, true, yes, enabled, t -> 1 * 0, false, no, disabled, f -> 0 */ extern pmix_mca_base_var_enum_t pmix_mca_base_var_enum_bool; /** * Verbosity level enumerator */ extern pmix_mca_base_var_enum_t pmix_mca_base_var_enum_verbose; #endif /* !defined(MCA_BASE_VAR_ENUM_H) */ pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_framework.c0000664000175000017500000001757315203536752022763 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2012-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/util/pmix_output.h" #include "pmix_mca_base_framework.h" #include "pmix_mca_base_var.h" #include "src/mca/base/pmix_base.h" bool pmix_mca_base_framework_is_registered(struct pmix_mca_base_framework_t *framework) { return !!(framework->framework_flags & PMIX_MCA_BASE_FRAMEWORK_FLAG_REGISTERED); } bool pmix_mca_base_framework_is_open(struct pmix_mca_base_framework_t *framework) { return !!(framework->framework_flags & PMIX_MCA_BASE_FRAMEWORK_FLAG_OPEN); } static void framework_open_output(struct pmix_mca_base_framework_t *framework) { if (0 < framework->framework_verbose) { if (-1 == framework->framework_output) { framework->framework_output = pmix_output_open(NULL); } pmix_output_set_verbosity(framework->framework_output, framework->framework_verbose); } else if (-1 != framework->framework_output) { pmix_output_close(framework->framework_output); framework->framework_output = -1; } } static void framework_close_output(struct pmix_mca_base_framework_t *framework) { if (-1 != framework->framework_output) { pmix_output_close(framework->framework_output); framework->framework_output = -1; } } int pmix_mca_base_framework_register(struct pmix_mca_base_framework_t *framework, pmix_mca_base_register_flag_t flags) { char *desc; int ret; assert(NULL != framework); framework->framework_refcnt++; if (pmix_mca_base_framework_is_registered(framework)) { return PMIX_SUCCESS; } PMIX_CONSTRUCT(&framework->framework_components, pmix_list_t); PMIX_CONSTRUCT(&framework->framework_failed_components, pmix_list_t); if (framework->framework_flags & PMIX_MCA_BASE_FRAMEWORK_FLAG_NO_DSO) { flags |= PMIX_MCA_BASE_REGISTER_STATIC_ONLY; } if (!(PMIX_MCA_BASE_FRAMEWORK_FLAG_NOREGISTER & framework->framework_flags)) { /* register this framework with the MCA variable system */ ret = pmix_mca_base_var_group_register(framework->framework_project, framework->framework_name, NULL, framework->framework_description); if (0 > ret) { return ret; } ret = asprintf(&desc, "Default selection set of components for the %s framework (" " means use all components that can be found)", framework->framework_name); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } ret = pmix_mca_base_var_register(framework->framework_project, framework->framework_name, NULL, NULL, desc, PMIX_MCA_BASE_VAR_TYPE_STRING, &framework->framework_selection); free(desc); if (0 > ret) { return ret; } /* register a verbosity variable for this framework */ ret = asprintf(&desc, "Verbosity level for the %s framework (default: 0)", framework->framework_name); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } framework->framework_verbose = PMIX_MCA_BASE_VERBOSE_ERROR; ret = pmix_mca_base_framework_var_register(framework, "verbose", desc, PMIX_MCA_BASE_VAR_TYPE_INT, &framework->framework_verbose); free(desc); if (0 > ret) { return ret; } /* check the initial verbosity and open the output if necessary. we will recheck this on open */ framework_open_output(framework); /* register framework variables */ if (NULL != framework->framework_register) { ret = framework->framework_register(flags); if (PMIX_SUCCESS != ret) { return ret; } } /* register components variables */ ret = pmix_mca_base_framework_components_register(framework, flags); if (PMIX_SUCCESS != ret) { return ret; } } framework->framework_flags |= PMIX_MCA_BASE_FRAMEWORK_FLAG_REGISTERED; /* framework did not provide a register function */ return PMIX_SUCCESS; } int pmix_mca_base_framework_open(struct pmix_mca_base_framework_t *framework, pmix_mca_base_open_flag_t flags) { int ret; assert(NULL != framework); /* register this framework before opening it */ ret = pmix_mca_base_framework_register(framework, PMIX_MCA_BASE_REGISTER_DEFAULT); if (PMIX_SUCCESS != ret) { return ret; } /* check if this framework is already open */ if (pmix_mca_base_framework_is_open(framework)) { return PMIX_SUCCESS; } if (PMIX_MCA_BASE_FRAMEWORK_FLAG_NOREGISTER & framework->framework_flags) { flags |= PMIX_MCA_BASE_OPEN_FIND_COMPONENTS; if (PMIX_MCA_BASE_FRAMEWORK_FLAG_NO_DSO & framework->framework_flags) { flags |= PMIX_MCA_BASE_OPEN_STATIC_ONLY; } } /* check the verbosity level and open (or close) the output */ framework_open_output(framework); if (NULL != framework->framework_open) { ret = framework->framework_open(flags); } else { ret = pmix_mca_base_framework_components_open(framework, flags); } if (PMIX_SUCCESS != ret) { framework->framework_refcnt--; } else { framework->framework_flags |= PMIX_MCA_BASE_FRAMEWORK_FLAG_OPEN; } return ret; } int pmix_mca_base_framework_close(struct pmix_mca_base_framework_t *framework) { bool is_open = pmix_mca_base_framework_is_open(framework); bool is_registered = pmix_mca_base_framework_is_registered(framework); int ret, group_id; assert(NULL != framework); if (!(is_open || is_registered)) { return PMIX_SUCCESS; } assert(framework->framework_refcnt); if (--framework->framework_refcnt) { return PMIX_SUCCESS; } /* find and deregister all component groups and variables */ group_id = pmix_mca_base_var_group_find(framework->framework_project, framework->framework_name, NULL); if (0 <= group_id) { (void) pmix_mca_base_var_group_deregister(group_id); } /* close the framework and all of its components */ if (is_open) { if (NULL != framework->framework_close) { ret = framework->framework_close(); } else { ret = pmix_mca_base_framework_components_close(framework, NULL); } if (PMIX_SUCCESS != ret) { return ret; } } else { pmix_list_item_t *item; while (NULL != (item = pmix_list_remove_first(&framework->framework_components))) { pmix_mca_base_component_list_item_t *cli; cli = (pmix_mca_base_component_list_item_t *) item; pmix_mca_base_component_unload(cli->cli_component, framework->framework_output); PMIX_RELEASE(item); } ret = PMIX_SUCCESS; } framework->framework_flags &= ~(PMIX_MCA_BASE_FRAMEWORK_FLAG_REGISTERED | PMIX_MCA_BASE_FRAMEWORK_FLAG_OPEN); PMIX_DESTRUCT(&framework->framework_components); PMIX_LIST_DESTRUCT(&framework->framework_failed_components); framework_close_output(framework); return ret; } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_var_group.h0000664000175000017500000001211315203536752022760 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2017 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_MCA_BASE_VAR_GROUP_H #define PMIX_MCA_BASE_VAR_GROUP_H #include "src/mca/mca.h" struct pmix_mca_base_var_group_t { pmix_list_item_t super; /** Index of group */ int group_index; /** Group is valid (registered) */ bool group_isvalid; /** Group name */ char *group_full_name; char *group_project; char *group_framework; char *group_component; /** Group help message (description) */ char *group_description; /** Integer value array of subgroup indices */ pmix_value_array_t group_subgroups; /** Integer array of group variables */ pmix_value_array_t group_vars; }; typedef struct pmix_mca_base_var_group_t pmix_mca_base_var_group_t; /** * Object declaration for pmix_mca_base_var_group_t */ PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_mca_base_var_group_t); /** * Register an MCA variable group * * @param[in] project_name Project name for this group. * @param[in] framework_name Framework name for this group. * @param[in] component_name Component name for this group. * @param[in] description Description of this group. * * @retval index Unique group index * @return pmix error code on Error * * Create an MCA variable group. If the group already exists * this call is equivalent to pmix_mca_base_ver_find_group(). */ PMIX_EXPORT int pmix_mca_base_var_group_register(const char *project_name, const char *framework_name, const char *component_name, const char *description); /** * Register an MCA variable group for a component * * @param[in] component [in] Pointer to the component for which the * group is being registered. * @param[in] description Description of this group. * * @retval index Unique group index * @return pmix error code on Error */ PMIX_EXPORT int pmix_mca_base_var_group_component_register(const pmix_mca_base_component_t *component, const char *description); /** * Deregister an MCA param group * * @param group_index [in] Group index from pmix_mca_base_var_group_register (), * pmix_mca_base_var_group_find(). * * This call deregisters all associated variables and subgroups. */ PMIX_EXPORT int pmix_mca_base_var_group_deregister(int group_index); /** * Find an MCA group * * @param[in] project_name Project name * @param[in] framework_name Framework name * @param[in] component_name Component name * * @returns PMIX_SUCCESS if found * @returns PMIX_ERR_NOT_FOUND if not found */ PMIX_EXPORT int pmix_mca_base_var_group_find(const char *project_name, const char *framework_name, const char *component_name); /** * Find an MCA group by its full name * * @param[in] full_name Full name of MCA variable group. Ex: shmem_mmap * @param[out] index Index of group if found * * @returns PMIX_SUCCESS if found * @returns PMIX_ERR_NOT_FOUND if not found */ PMIX_EXPORT int pmix_mca_base_var_group_find_by_name(const char *full_name, int *index); /** * Get the group at a specified index * * @param[in] group_index Group index * @param[out] group Storage for the group object pointer. * * @retval PMIX_ERR_NOT_FOUND If the group specified by group_index does not exist. * @retval PMIX_SUCCESS If the group is found * * The returned pointer belongs to the MCA variable system. Do not modify/release/retain * the pointer. */ PMIX_EXPORT int pmix_mca_base_var_group_get(const int group_index, const pmix_mca_base_var_group_t **group); /** * Get the number of registered MCA groups * * @retval count Number of registered MCA groups */ PMIX_EXPORT int pmix_mca_base_var_group_get_count(void); /** * Get a relative timestamp for the MCA group system * * @retval stamp * * This value will change if groups or variables are either added or removed. */ PMIX_EXPORT int pmix_mca_base_var_group_get_stamp(void); #endif /* PMIX_MCA_BASE_VAR_GROUP_H */ pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_var_group.c0000664000175000017500000003400015203536752022752 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2012 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2013 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #include #include "pmix_common.h" #include "src/include/pmix_stdint.h" #include "src/mca/base/pmix_mca_base_vari.h" #include "src/mca/mca.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_show_help.h" static pmix_pointer_array_t pmix_mca_base_var_groups; static pmix_hash_table_t pmix_mca_base_var_group_index_hash; static int pmix_mca_base_var_group_count = 0; static int pmix_mca_base_var_groups_timestamp = 0; static bool pmix_mca_base_var_group_initialized = false; static void pmix_mca_base_var_group_constructor(pmix_mca_base_var_group_t *group); static void pmix_mca_base_var_group_destructor(pmix_mca_base_var_group_t *group); PMIX_CLASS_INSTANCE(pmix_mca_base_var_group_t, pmix_object_t, pmix_mca_base_var_group_constructor, pmix_mca_base_var_group_destructor); int pmix_mca_base_var_group_init(void) { int ret; if (!pmix_mca_base_var_group_initialized) { PMIX_CONSTRUCT(&pmix_mca_base_var_groups, pmix_pointer_array_t); /* These values are arbitrary */ ret = pmix_pointer_array_init(&pmix_mca_base_var_groups, 128, 16384, 128); if (PMIX_SUCCESS != ret) { return ret; } PMIX_CONSTRUCT(&pmix_mca_base_var_group_index_hash, pmix_hash_table_t); ret = pmix_hash_table_init(&pmix_mca_base_var_group_index_hash, 256); if (PMIX_SUCCESS != ret) { return ret; } pmix_mca_base_var_group_initialized = true; pmix_mca_base_var_group_count = 0; } return PMIX_SUCCESS; } int pmix_mca_base_var_group_finalize(void) { pmix_object_t *object; int size, i; if (pmix_mca_base_var_group_initialized) { size = pmix_pointer_array_get_size(&pmix_mca_base_var_groups); for (i = 0; i < size; ++i) { object = pmix_pointer_array_get_item(&pmix_mca_base_var_groups, i); if (NULL != object) { PMIX_RELEASE(object); } } PMIX_DESTRUCT(&pmix_mca_base_var_groups); PMIX_DESTRUCT(&pmix_mca_base_var_group_index_hash); pmix_mca_base_var_group_count = 0; pmix_mca_base_var_group_initialized = false; } return PMIX_SUCCESS; } int pmix_mca_base_var_group_get_internal(const int group_index, pmix_mca_base_var_group_t **group, bool invalidok) { if (group_index < 0) { return PMIX_ERR_NOT_FOUND; } *group = (pmix_mca_base_var_group_t *) pmix_pointer_array_get_item(&pmix_mca_base_var_groups, group_index); if (NULL == *group || (!invalidok && !(*group)->group_isvalid)) { *group = NULL; return PMIX_ERR_NOT_FOUND; } return PMIX_SUCCESS; } static int group_find_by_name(const char *full_name, int *index, bool invalidok) { pmix_mca_base_var_group_t *group; void *tmp; int rc; rc = pmix_hash_table_get_value_ptr(&pmix_mca_base_var_group_index_hash, full_name, strlen(full_name), &tmp); if (PMIX_SUCCESS != rc) { return rc; } rc = pmix_mca_base_var_group_get_internal((int) (uintptr_t) tmp, &group, invalidok); if (PMIX_SUCCESS != rc) { return rc; } if (invalidok || group->group_isvalid) { *index = (int) (uintptr_t) tmp; return PMIX_SUCCESS; } return PMIX_ERR_NOT_FOUND; } static bool compare_strings(const char *str1, const char *str2) { if ((NULL != str1 && 0 == strcmp(str1, "*")) || (NULL == str1 && NULL == str2)) { return true; } if (NULL != str1 && NULL != str2) { return 0 == strcmp(str1, str2); } return false; } static int group_find_linear(const char *project_name, const char *framework_name, const char *component_name, bool invalidok) { for (int i = 0; i < pmix_mca_base_var_group_count; ++i) { pmix_mca_base_var_group_t *group; int rc = pmix_mca_base_var_group_get_internal(i, &group, invalidok); if (PMIX_SUCCESS != rc) { continue; } if (compare_strings(project_name, group->group_project) && compare_strings(framework_name, group->group_framework) && compare_strings(component_name, group->group_component)) { return i; } } return PMIX_ERR_NOT_FOUND; } static int group_find(const char *project_name, const char *framework_name, const char *component_name, bool invalidok) { char *full_name; int ret, index = 0; if (!pmix_mca_base_var_initialized) { return PMIX_ERR_NOT_FOUND; } /* check for wildcards */ if ((project_name && '*' == project_name[0]) || (framework_name && '*' == framework_name[0]) || (component_name && '*' == component_name[0])) { return group_find_linear(project_name, framework_name, component_name, invalidok); } ret = pmix_mca_base_var_generate_full_name4(project_name, framework_name, component_name, NULL, &full_name); if (PMIX_SUCCESS != ret) { return PMIX_ERROR; } ret = group_find_by_name(full_name, &index, invalidok); free(full_name); return (0 > ret) ? ret : index; } static int group_register(const char *project_name, const char *framework_name, const char *component_name, const char *description) { pmix_mca_base_var_group_t *group; int group_id, parent_id = -1; int ret; if (NULL == project_name && NULL == framework_name && NULL == component_name) { /* don't create a group with no name (maybe we should create a generic group?) */ return -1; } /* avoid groups of the form pmix_pmix, etc */ if (NULL != project_name && NULL != framework_name && (0 == strcmp(project_name, framework_name))) { project_name = NULL; } group_id = group_find(project_name, framework_name, component_name, true); if (0 <= group_id) { ret = pmix_mca_base_var_group_get_internal(group_id, &group, true); if (PMIX_SUCCESS != ret) { /* something went horribly wrong */ assert(NULL != group); return ret; } group->group_isvalid = true; pmix_mca_base_var_groups_timestamp++; /* group already exists. return it's index */ return group_id; } group = PMIX_NEW(pmix_mca_base_var_group_t); group->group_isvalid = true; if (NULL != project_name) { group->group_project = strdup(project_name); if (NULL == group->group_project) { PMIX_RELEASE(group); return PMIX_ERR_OUT_OF_RESOURCE; } } if (NULL != framework_name) { group->group_framework = strdup(framework_name); if (NULL == group->group_framework) { PMIX_RELEASE(group); return PMIX_ERR_OUT_OF_RESOURCE; } } if (NULL != component_name) { group->group_component = strdup(component_name); if (NULL == group->group_component) { PMIX_RELEASE(group); return PMIX_ERR_OUT_OF_RESOURCE; } } if (NULL != description) { group->group_description = strdup(description); if (NULL == group->group_description) { PMIX_RELEASE(group); return PMIX_ERR_OUT_OF_RESOURCE; } } if (NULL != framework_name && NULL != component_name) { parent_id = group_register(project_name, framework_name, NULL, NULL); } /* build the group name */ ret = pmix_mca_base_var_generate_full_name4(NULL, project_name, framework_name, component_name, &group->group_full_name); if (PMIX_SUCCESS != ret) { PMIX_RELEASE(group); return ret; } group_id = pmix_pointer_array_add(&pmix_mca_base_var_groups, group); if (0 > group_id) { PMIX_RELEASE(group); return PMIX_ERROR; } pmix_hash_table_set_value_ptr(&pmix_mca_base_var_group_index_hash, group->group_full_name, strlen(group->group_full_name), (void *) (uintptr_t) group_id); pmix_mca_base_var_group_count++; pmix_mca_base_var_groups_timestamp++; if (0 <= parent_id) { pmix_mca_base_var_group_t *parent_group; (void) pmix_mca_base_var_group_get_internal(parent_id, &parent_group, false); pmix_value_array_append_item(&parent_group->group_subgroups, &group_id); } return group_id; } int pmix_mca_base_var_group_register(const char *project_name, const char *framework_name, const char *component_name, const char *description) { return group_register(project_name, framework_name, component_name, description); } int pmix_mca_base_var_group_component_register(const pmix_mca_base_component_t *component, const char *description) { /* 1.7 components do not store the project */ return group_register(component->pmix_mca_project_name, component->pmix_mca_type_name, component->pmix_mca_component_name, description); } int pmix_mca_base_var_group_deregister(int group_index) { pmix_mca_base_var_group_t *group; int size, ret; int *params, *subgroups; ret = pmix_mca_base_var_group_get_internal(group_index, &group, false); if (PMIX_SUCCESS != ret) { return ret; } group->group_isvalid = false; /* deregister all associated mca parameters */ size = pmix_value_array_get_size(&group->group_vars); params = PMIX_VALUE_ARRAY_GET_BASE(&group->group_vars, int); for (int i = 0; i < size; ++i) { const pmix_mca_base_var_t *var; ret = pmix_mca_base_var_get(params[i], &var); if (PMIX_SUCCESS != ret) { continue; } (void) pmix_mca_base_var_deregister(params[i]); } size = pmix_value_array_get_size(&group->group_subgroups); subgroups = PMIX_VALUE_ARRAY_GET_BASE(&group->group_subgroups, int); for (int i = 0; i < size; ++i) { (void) pmix_mca_base_var_group_deregister(subgroups[i]); } /* ordering of variables and subgroups must be the same if the * group is re-registered */ pmix_mca_base_var_groups_timestamp++; return PMIX_SUCCESS; } int pmix_mca_base_var_group_find(const char *project_name, const char *framework_name, const char *component_name) { return group_find(project_name, framework_name, component_name, false); } int pmix_mca_base_var_group_find_by_name(const char *full_name, int *index) { return group_find_by_name(full_name, index, false); } int pmix_mca_base_var_group_add_var(const int group_index, const int param_index) { pmix_mca_base_var_group_t *group; int size, i, ret; int *params; ret = pmix_mca_base_var_group_get_internal(group_index, &group, false); if (PMIX_SUCCESS != ret) { return ret; } size = pmix_value_array_get_size(&group->group_vars); params = PMIX_VALUE_ARRAY_GET_BASE(&group->group_vars, int); for (i = 0; i < size; ++i) { if (params[i] == param_index) { return i; } } if (PMIX_SUCCESS != (ret = pmix_value_array_append_item(&group->group_vars, ¶m_index))) { return ret; } pmix_mca_base_var_groups_timestamp++; /* return the group index */ return (int) pmix_value_array_get_size(&group->group_vars) - 1; } int pmix_mca_base_var_group_get(const int group_index, const pmix_mca_base_var_group_t **group) { return pmix_mca_base_var_group_get_internal(group_index, (pmix_mca_base_var_group_t **) group, false); } static void pmix_mca_base_var_group_constructor(pmix_mca_base_var_group_t *group) { memset((char *) group + sizeof(group->super), 0, sizeof(*group) - sizeof(group->super)); PMIX_CONSTRUCT(&group->group_subgroups, pmix_value_array_t); pmix_value_array_init(&group->group_subgroups, sizeof(int)); PMIX_CONSTRUCT(&group->group_vars, pmix_value_array_t); pmix_value_array_init(&group->group_vars, sizeof(int)); } static void pmix_mca_base_var_group_destructor(pmix_mca_base_var_group_t *group) { free(group->group_full_name); group->group_full_name = NULL; free(group->group_description); group->group_description = NULL; free(group->group_project); group->group_project = NULL; free(group->group_framework); group->group_framework = NULL; free(group->group_component); group->group_component = NULL; PMIX_DESTRUCT(&group->group_subgroups); PMIX_DESTRUCT(&group->group_vars); } int pmix_mca_base_var_group_get_count(void) { return pmix_mca_base_var_group_count; } int pmix_mca_base_var_group_get_stamp(void) { return pmix_mca_base_var_groups_timestamp; } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_framework.h0000664000175000017500000002204515203536752022756 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2012-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #if !defined(PMIX_MCA_BASE_FRAMEWORK_H) # define PMIX_MCA_BASE_FRAMEWORK_H # include "src/include/pmix_config.h" # include "src/class/pmix_list.h" # include "src/mca/mca.h" /* * Register and open flags */ enum pmix_mca_base_register_flag_t { PMIX_MCA_BASE_REGISTER_DEFAULT = 0, /** Register all components (ignore selection MCA variables) */ PMIX_MCA_BASE_REGISTER_ALL = 1, /** Do not register DSO components */ PMIX_MCA_BASE_REGISTER_STATIC_ONLY = 2 }; typedef enum pmix_mca_base_register_flag_t pmix_mca_base_register_flag_t; enum pmix_mca_base_open_flag_t { PMIX_MCA_BASE_OPEN_DEFAULT = 0, /** Find components in pmix_mca_base_components_find. Used by pmix_mca_base_framework_open() when NOREGISTER is specified by the framework */ PMIX_MCA_BASE_OPEN_FIND_COMPONENTS = 1, /** Do not open DSO components */ PMIX_MCA_BASE_OPEN_STATIC_ONLY = 2, }; typedef enum pmix_mca_base_open_flag_t pmix_mca_base_open_flag_t; /** * Register the MCA framework parameters * * @param[in] flags Registration flags (see mca/base/pmix_base.h) * * @retval PMIX_SUCCESS on success * @retval pmix error code on failure * * This function registers all framework MCA parameters. This * function should not call pmix_mca_base_framework_components_register(). * * Frameworks are NOT required to provide this function. It * may be NULL. */ typedef int (*pmix_mca_base_framework_register_params_fn_t)(pmix_mca_base_register_flag_t flags); /** * Initialize the MCA framework * * @retval PMIX_SUCCESS Upon success * @retval PMIX_ERROR Upon failure * * This must be the first function invoked in the MCA framework. * It initializes the MCA framework, finds and opens components, * populates the components list, etc. * * This function is invoked during pmix_init() and during the * initialization of the special case of the ompi_info command. * * This function fills in the components framework value, which * is a list of all components that were successfully opened. * This variable should \em only be used by other framework base * functions or by ompi_info -- it is not considered a public * interface member -- and is only mentioned here for completeness. * * Any resources allocated by this function must be freed * in the framework close function. * * Frameworks are NOT required to provide this function. It may * be NULL. If a framework does not provide an open function the * default behavior of pmix_mca_base_framework_open() is to call * pmix_mca_base_framework_components_open(). If a framework provides * an open function it will need to call pmix_mca_base_framework_components_open() * if it needs to open any components. */ typedef int (*pmix_mca_base_framework_open_fn_t)(pmix_mca_base_open_flag_t flags); /** * Shut down the MCA framework. * * @retval PMIX_SUCCESS Always * * This function should shut downs everything in the MCA * framework, and is called during pmix_finalize() and the * special case of the ompi_info command. * * It must be the last function invoked on the MCA framework. * * Frameworks are NOT required to provide this function. It may * be NULL. If a framework does not provide a close function the * default behavior of pmix_mca_base_framework_close() is to call * pmix_mca_base_framework_components_close(). If a framework provide * a close function it will need to call pmix_mca_base_framework_components_close() * if any components were opened. */ typedef int (*pmix_mca_base_framework_close_fn_t)(void); typedef enum { PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT = 0, /** Don't register any variables for this framework */ PMIX_MCA_BASE_FRAMEWORK_FLAG_NOREGISTER = 1, /** Internal. Don't set outside pmix_mca_base_framework.h */ PMIX_MCA_BASE_FRAMEWORK_FLAG_REGISTERED = 2, /** Framework does not have any DSO components */ PMIX_MCA_BASE_FRAMEWORK_FLAG_NO_DSO = 4, /** Internal. Don't set outside pmix_mca_base_framework.h */ PMIX_MCA_BASE_FRAMEWORK_FLAG_OPEN = 8, /** * The upper 16 bits are reserved for project specific flags. */ } pmix_mca_base_framework_flags_t; typedef struct pmix_mca_base_framework_t { /** Project name for this component (ex "pmix") */ char *framework_project; /** Framework name */ char *framework_name; /** Description of this framework or NULL */ const char *framework_description; /** Framework register function or NULL if the framework and all its components have nothing to register */ pmix_mca_base_framework_register_params_fn_t framework_register; /** Framework open function or NULL */ pmix_mca_base_framework_open_fn_t framework_open; /** Framework close function or NULL */ pmix_mca_base_framework_close_fn_t framework_close; /** Framework flags (future use) set to 0 */ pmix_mca_base_framework_flags_t framework_flags; /** Framework open count */ int framework_refcnt; /** List of static components */ const pmix_mca_base_component_t ***framework_static_components; /** Component selection. This will be registered with the MCA variable system and should be either NULL (all components) or a heap allocated, comma-delimited list of components. */ char *framework_selection; /** Verbosity level (0-100) */ int framework_verbose; /** Pmix output for this framework (or -1) */ int framework_output; /** List of selected components (filled in by pmix_mca_base_framework_register() or pmix_mca_base_framework_open() */ pmix_list_t framework_components; /** List of components that failed to load */ pmix_list_t framework_failed_components; } pmix_mca_base_framework_t; /** * Register a framework with MCA. * * @param[in] framework framework to register * * @retval PMIX_SUCCESS Upon success * @retval PMIX_ERROR Upon failure * * Call a framework's register function. */ PMIX_EXPORT int pmix_mca_base_framework_register(pmix_mca_base_framework_t *framework, pmix_mca_base_register_flag_t flags); /** * Open a framework * * @param[in] framework framework to open * * @retval PMIX_SUCCESS Upon success * @retval PMIX_ERROR Upon failure * * Call a framework's open function. */ PMIX_EXPORT int pmix_mca_base_framework_open(pmix_mca_base_framework_t *framework, pmix_mca_base_open_flag_t flags); /** * Close a framework * * @param[in] framework framework to close * * @retval PMIX_SUCCESS Upon success * @retval PMIX_ERROR Upon failure * * Call a framework's close function. */ PMIX_EXPORT int pmix_mca_base_framework_close(pmix_mca_base_framework_t *framework); /** * Check if a framework is already registered * * @param[in] framework framework to query * * @retval true if the framework's mca variables are registered * @retval false if not */ PMIX_EXPORT bool pmix_mca_base_framework_is_registered(struct pmix_mca_base_framework_t *framework); /** * Check if a framework is already open * * @param[in] framework framework to query * * @retval true if the framework is open * @retval false if not */ PMIX_EXPORT bool pmix_mca_base_framework_is_open(struct pmix_mca_base_framework_t *framework); /** * Macro to declare an MCA framework * * Example: * PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, foo, NULL, pmix_foo_open, pmix_foo_close, * MCA_BASE_FRAMEWORK_FLAG_LAZY) */ # define PMIX_MCA_BASE_FRAMEWORK_DECLARE(project, name, description, registerfn, openfn, \ closefn, static_components, flags) \ pmix_mca_base_framework_t project##_##name##_base_framework \ = {.framework_project = #project, \ .framework_name = #name, \ .framework_description = description, \ .framework_register = registerfn, \ .framework_open = openfn, \ .framework_close = closefn, \ .framework_flags = flags, \ .framework_refcnt = 0, \ .framework_static_components = static_components, \ .framework_selection = NULL, \ .framework_verbose = 0, \ .framework_output = -1} #endif /* PMIX_MCA_BASE_FRAMEWORK_H */ pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_components_register.c0000664000175000017500000001450515203536752025047 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2012 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2015 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_component_repository.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/mca.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_show_help.h" /* * Local functions */ static int register_components(pmix_mca_base_framework_t *framework); /** * Function for finding and opening either all MCA components, or the * one that was specifically requested via a MCA parameter. */ int pmix_mca_base_framework_components_register(pmix_mca_base_framework_t *framework, pmix_mca_base_register_flag_t flags) { bool open_dso_components = !(flags & PMIX_MCA_BASE_REGISTER_STATIC_ONLY); bool ignore_requested = !!(flags & PMIX_MCA_BASE_REGISTER_ALL); int ret; /* Find and load requested components */ ret = pmix_mca_base_component_find(NULL, framework, ignore_requested, open_dso_components); if (PMIX_SUCCESS != ret) { return ret; } /* Register all remaining components */ return register_components(framework); } /* * Traverse the entire list of found components (a list of * pmix_mca_base_component_t instances). If the requested_component_names * array is empty, or the name of each component in the list of found * components is in the requested_components_array, try to open it. * If it opens, add it to the components_available list. */ static int register_components(pmix_mca_base_framework_t *framework) { int ret; pmix_mca_base_component_t *component; pmix_mca_base_component_list_item_t *cli, *next; int output_id = framework->framework_output; /* Announce */ pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "pmix:mca: base: components_register: registering framework %s components", framework->framework_name); /* Traverse the list of found components */ PMIX_LIST_FOREACH_SAFE (cli, next, &framework->framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_mca_base_component_t *) cli->cli_component; pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "pmix:mca: base: components_register: found loaded component %s", component->pmix_mca_component_name); /* Call the component's MCA parameter registration function (or open if register doesn't * exist) */ if (NULL == component->pmix_mca_register_component_params) { pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "pmix:mca: base: components_register: " "component %s has no register or open function", component->pmix_mca_component_name); ret = PMIX_SUCCESS; } else { ret = component->pmix_mca_register_component_params(); } if (PMIX_SUCCESS != ret) { if (PMIX_ERR_NOT_AVAILABLE != ret) { /* If the component returns PMIX_ERR_NOT_AVAILABLE, it's a cue to "silently ignore me" -- it's not a failure, it's just a way for the component to say "nope!". Otherwise, however, display an error. We may end up displaying this twice, but it may go to separate streams. So better to be redundant than to not display the error in the stream where it was expected. */ if (pmix_mca_base_show_load_errors(component->pmix_mca_type_name, component->pmix_mca_component_name)) { pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_ERROR, output_id, "pmix:mca: base: components_register: component %s " "/ %s register function failed", component->pmix_mca_type_name, component->pmix_mca_component_name); } pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "pmix:mca: base: components_register: " "component %s register function failed", component->pmix_mca_component_name); } pmix_list_remove_item(&framework->framework_components, &cli->super); /* Release this list item */ PMIX_RELEASE(cli); continue; } if (NULL != component->pmix_mca_register_component_params) { pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "pmix:mca: base: components_register: " "component %s register function successful", component->pmix_mca_component_name); } } /* All done */ return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_parse_paramfile.c0000664000175000017500000000554615203536752024115 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_vari.h" #include "src/mca/mca.h" #include "src/util/pmix_keyval_parse.h" static void save_value(const char *file, int lineno, const char *name, const char *value); static char *file_being_read; static pmix_list_t *_param_list; int pmix_mca_base_parse_paramfile(const char *paramfile, pmix_list_t *list) { file_being_read = (char *) paramfile; _param_list = list; return pmix_util_keyval_parse(paramfile, save_value); } int pmix_mca_base_internal_env_store(void) { return pmix_util_keyval_save_internal_envars(save_value); } static void save_value(const char *file, int lineno, const char *name, const char *value) { pmix_mca_base_var_file_value_t *fv; bool found = false; PMIX_HIDE_UNUSED_PARAMS(file, lineno); /* First traverse through the list and ensure that we don't already have a param of this name. If we do, just replace the value. */ PMIX_LIST_FOREACH (fv, _param_list, pmix_mca_base_var_file_value_t) { if (0 == strcmp(name, fv->mbvfv_var)) { if (NULL != fv->mbvfv_value) { free(fv->mbvfv_value); } found = true; break; } } if (!found) { /* We didn't already have the param, so append it to the list */ fv = PMIX_NEW(pmix_mca_base_var_file_value_t); if (NULL == fv) { return; } fv->mbvfv_var = strdup(name); pmix_list_append(_param_list, &fv->super); } fv->mbvfv_value = value ? strdup(value) : NULL; fv->mbvfv_file = file_being_read; fv->mbvfv_lineno = pmix_util_keyval_parse_lineno; } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_var_enum.c0000664000175000017500000005260515203536752022575 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2012 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2013 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_var_enum.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_printf.h" #include "src/include/pmix_globals.h" static void pmix_mca_base_var_enum_constructor(pmix_mca_base_var_enum_t *enumerator); static void pmix_mca_base_var_enum_destructor(pmix_mca_base_var_enum_t *enumerator); PMIX_CLASS_INSTANCE(pmix_mca_base_var_enum_t, pmix_object_t, pmix_mca_base_var_enum_constructor, pmix_mca_base_var_enum_destructor); static void pmix_mca_base_var_enum_flag_constructor(pmix_mca_base_var_enum_flag_t *enumerator); static void pmix_mca_base_var_enum_flag_destructor(pmix_mca_base_var_enum_flag_t *enumerator); PMIX_CLASS_INSTANCE(pmix_mca_base_var_enum_flag_t, pmix_object_t, pmix_mca_base_var_enum_flag_constructor, pmix_mca_base_var_enum_flag_destructor); static int enum_dump(pmix_mca_base_var_enum_t *self, char **out, pmix_mca_base_var_enum_dump_type_t output_type); static int enum_get_count(pmix_mca_base_var_enum_t *self, int *count); static int enum_get_value(pmix_mca_base_var_enum_t *self, int index, int *value, const char **string_value); static int pmix_mca_base_var_enum_bool_get_count(pmix_mca_base_var_enum_t *enumerator, int *count) { (void) enumerator; *count = 2; return PMIX_SUCCESS; } static int pmix_mca_base_var_enum_bool_get_value(pmix_mca_base_var_enum_t *self, int index, int *value, const char **string_value) { (void) self; if (1 < index) { return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } *value = index ? 1 : 0; *string_value = index ? "true" : "false"; return PMIX_SUCCESS; } static int pmix_mca_base_var_enum_bool_vfs(pmix_mca_base_var_enum_t *self, const char *string_value, int *value) { PMIX_HIDE_UNUSED_PARAMS(self); char *tmp; int v; /* skip whitespace */ string_value += strspn(string_value, " \t\n\v\f\r"); v = strtol(string_value, &tmp, 10); if (*tmp != '\0') { if (0 == strcmp(string_value, "true") || 0 == strcmp(string_value, "t") || 0 == strcmp(string_value, "enabled") || 0 == strcmp(string_value, "yes")) { v = 1; } else if (0 == strcmp(string_value, "false") || 0 == strcmp(string_value, "f") || 0 == strcmp(string_value, "disabled") || 0 == strcmp(string_value, "no")) { v = 0; } else { return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } } *value = !!v; return PMIX_SUCCESS; } static int pmix_mca_base_var_enum_bool_sfv(pmix_mca_base_var_enum_t *self, const int value, char **string_value) { PMIX_HIDE_UNUSED_PARAMS(self); if (string_value) { *string_value = strdup(value ? "true" : "false"); } return PMIX_SUCCESS; } static int pmix_mca_base_var_enum_bool_dump(pmix_mca_base_var_enum_t *self, char **out, pmix_mca_base_var_enum_dump_type_t output_type) { PMIX_HIDE_UNUSED_PARAMS(self); int ret; char *color_vv = "", *color_reset = ""; if (PMIX_MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR == output_type) { color_vv = pmix_var_dump_color[PMIX_VAR_DUMP_COLOR_VALID_VALUES]; color_reset = "\033[0m"; } ret = pmix_asprintf(out, "%s0%s|%sf%s|%sfalse%s|%sdisabled%s|%sno%s|%sn%s, " "%s1%s|%st%s|%strue%s|%senabled%s|%syes%s|%sy%s", color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset); if (ret < 0) { *out = NULL; return PMIX_ERR_OUT_OF_RESOURCE; } return PMIX_SUCCESS; } pmix_mca_base_var_enum_t pmix_mca_base_var_enum_bool = {.super = PMIX_OBJ_STATIC_INIT(pmix_object_t), .enum_is_static = true, .enum_name = "boolean", .get_count = pmix_mca_base_var_enum_bool_get_count, .get_value = pmix_mca_base_var_enum_bool_get_value, .value_from_string = pmix_mca_base_var_enum_bool_vfs, .string_from_value = pmix_mca_base_var_enum_bool_sfv, .dump = pmix_mca_base_var_enum_bool_dump}; /* verbosity enumerator */ static pmix_mca_base_var_enum_value_t verbose_values[] = {{PMIX_MCA_BASE_VERBOSE_NONE, "none"}, {PMIX_MCA_BASE_VERBOSE_ERROR, "error"}, {PMIX_MCA_BASE_VERBOSE_COMPONENT, "component"}, {PMIX_MCA_BASE_VERBOSE_WARN, "warn"}, {PMIX_MCA_BASE_VERBOSE_INFO, "info"}, {PMIX_MCA_BASE_VERBOSE_TRACE, "trace"}, {PMIX_MCA_BASE_VERBOSE_DEBUG, "debug"}, {PMIX_MCA_BASE_VERBOSE_MAX, "max"}, {-1, NULL}}; static int pmix_mca_base_var_enum_verbose_vfs(pmix_mca_base_var_enum_t *self, const char *string_value, int *value) { (void) self; char *tmp; int v; /* skip whitespace */ string_value += strspn(string_value, " \t\n\v\f\r"); v = strtol(string_value, &tmp, 10); if (*tmp != '\0') { for (int i = 0; verbose_values[i].string; ++i) { if (0 == strcmp(verbose_values[i].string, string_value)) { *value = verbose_values[i].value; return PMIX_SUCCESS; } } return PMIX_ERR_NOT_FOUND; } else if (v < PMIX_MCA_BASE_VERBOSE_NONE) { v = PMIX_MCA_BASE_VERBOSE_NONE; } else if (v > PMIX_MCA_BASE_VERBOSE_MAX) { v = PMIX_MCA_BASE_VERBOSE_MAX; } *value = v; return PMIX_SUCCESS; } static int pmix_mca_base_var_enum_verbose_sfv(pmix_mca_base_var_enum_t *self, const int value, char **string_value) { (void) self; int ret; if (value < 0 || value > 100) { return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } for (int i = 0; verbose_values[i].string; ++i) { if (verbose_values[i].value == value) { *string_value = strdup(verbose_values[i].string); return PMIX_SUCCESS; } } if (string_value) { ret = asprintf(string_value, "%d", value); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } } return PMIX_SUCCESS; } static int pmix_mca_base_var_enum_verbose_dump(pmix_mca_base_var_enum_t *self, char **out, pmix_mca_base_var_enum_dump_type_t output_type) { char *tmp; int ret; char *color_vv = "", *color_reset = ""; ret = enum_dump(self, out, output_type); if (PMIX_SUCCESS != ret) { return ret; } if (PMIX_MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR == output_type) { color_vv = pmix_var_dump_color[PMIX_VAR_DUMP_COLOR_VALID_VALUES]; color_reset = "\033[0m"; } ret = pmix_asprintf(&tmp, "%s, %s0%s-%s100%s", *out, color_vv, color_reset, color_vv, color_reset); free(*out); if (0 > ret) { *out = NULL; return PMIX_ERR_OUT_OF_RESOURCE; } *out = tmp; return PMIX_SUCCESS; } pmix_mca_base_var_enum_t pmix_mca_base_var_enum_verbose = { .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), .enum_is_static = true, .enum_name = "verbosity", .get_count = enum_get_count, .get_value = enum_get_value, .value_from_string = pmix_mca_base_var_enum_verbose_vfs, .string_from_value = pmix_mca_base_var_enum_verbose_sfv, .dump = pmix_mca_base_var_enum_verbose_dump, .enum_value_count = 8, .enum_values = verbose_values, }; int pmix_mca_base_var_enum_create(const char *name, const pmix_mca_base_var_enum_value_t *values, pmix_mca_base_var_enum_t **enumerator) { pmix_mca_base_var_enum_t *new_enum; int i; *enumerator = NULL; new_enum = PMIX_NEW(pmix_mca_base_var_enum_t); if (NULL == new_enum) { return PMIX_ERR_OUT_OF_RESOURCE; } new_enum->enum_name = strdup(name); if (NULL == new_enum->enum_name) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; values[i].string; ++i) ; new_enum->enum_value_count = i; /* make a copy of the values */ new_enum->enum_values = calloc(new_enum->enum_value_count + 1, sizeof(*new_enum->enum_values)); if (NULL == new_enum->enum_values) { PMIX_RELEASE(new_enum); return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; i < new_enum->enum_value_count; ++i) { new_enum->enum_values[i].value = values[i].value; new_enum->enum_values[i].string = strdup(values[i].string); } *enumerator = new_enum; return PMIX_SUCCESS; } int pmix_mca_base_var_enum_create_flag(const char *name, const pmix_mca_base_var_enum_value_flag_t *flags, pmix_mca_base_var_enum_flag_t **enumerator) { pmix_mca_base_var_enum_flag_t *new_enum; int i; *enumerator = NULL; new_enum = PMIX_NEW(pmix_mca_base_var_enum_flag_t); if (NULL == new_enum) { return PMIX_ERR_OUT_OF_RESOURCE; } new_enum->super.enum_name = strdup(name); if (NULL == new_enum->super.enum_name) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0; flags[i].string; ++i) ; new_enum->super.enum_value_count = i; /* make a copy of the values */ new_enum->enum_flags = calloc(new_enum->super.enum_value_count + 1, sizeof(*new_enum->enum_flags)); if (NULL == new_enum->enum_flags) { PMIX_RELEASE(new_enum); return PMIX_ERR_OUT_OF_RESOURCE; } #if PMIX_ENABLE_DEBUG int all_flags = 0; #endif for (i = 0; i < new_enum->super.enum_value_count; ++i) { new_enum->enum_flags[i].flag = flags[i].flag; new_enum->enum_flags[i].string = strdup(flags[i].string); new_enum->enum_flags[i].conflicting_flag = flags[i].conflicting_flag; /* ensure flags are only set a single bit, doesn't conflict with itself, and * hasn't already been specified. */ assert(!(flags[i].flag & (flags[i].flag - 1))); assert(!(flags[i].flag & flags[i].conflicting_flag)); #if PMIX_ENABLE_DEBUG assert(!(all_flags & flags[i].flag)); #endif assert(flags[i].flag); #if PMIX_ENABLE_DEBUG all_flags |= flags[i].flag; #endif } *enumerator = new_enum; return PMIX_SUCCESS; } static int enum_dump(pmix_mca_base_var_enum_t *self, char **out, pmix_mca_base_var_enum_dump_type_t output_type) { int i; char *tmp; int ret; char *color_vv = "", *color_reset = ""; *out = NULL; if (NULL == self) { return PMIX_ERROR; } if (PMIX_MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR == output_type) { color_vv = pmix_var_dump_color[PMIX_VAR_DUMP_COLOR_VALID_VALUES]; color_reset = "\033[0m"; } tmp = NULL; for (i = 0; i < self->enum_value_count && self->enum_values[i].string; ++i) { ret = pmix_asprintf(out, "%s%s%s%d%s|%s%s%s", tmp ? tmp : "", tmp ? ", " : "", color_vv, self->enum_values[i].value, color_reset, color_vv, self->enum_values[i].string, color_reset); if (tmp) { free(tmp); } if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } tmp = *out; } return PMIX_SUCCESS; } static int enum_get_count(pmix_mca_base_var_enum_t *self, int *count) { *count = self->enum_value_count; return PMIX_SUCCESS; } static int enum_get_value(pmix_mca_base_var_enum_t *self, int index, int *value, const char **string_value) { int count, ret; ret = self->get_count(self, &count); if (PMIX_SUCCESS != ret) { return ret; } if (index >= count) { return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } if (value) { *value = self->enum_values[index].value; } if (string_value) { *string_value = strdup(self->enum_values[index].string); } return PMIX_SUCCESS; } static int enum_value_from_string(pmix_mca_base_var_enum_t *self, const char *string_value, int *value_out) { int value, count, ret, i; bool is_int; char *tmp; ret = self->get_count(self, &count); if (PMIX_SUCCESS != ret) { return ret; } value = strtol(string_value, &tmp, 0); /* Check if the string is an integer */ is_int = tmp[0] == '\0'; for (i = 0; i < count; ++i) { if ((is_int && value == self->enum_values[i].value) || 0 == strcasecmp(string_value, self->enum_values[i].string)) { break; } } if (i == count) { return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } *value_out = self->enum_values[i].value; return PMIX_SUCCESS; } static int enum_string_from_value(pmix_mca_base_var_enum_t *self, const int value, char **string_value) { int count, ret, i; ret = self->get_count(self, &count); if (PMIX_SUCCESS != ret) { return ret; } for (i = 0; i < count; ++i) { if (value == self->enum_values[i].value) { break; } } if (i == count) { return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } if (string_value) { *string_value = strdup(self->enum_values[i].string); } return PMIX_SUCCESS; } static void pmix_mca_base_var_enum_constructor(pmix_mca_base_var_enum_t *enumerator) { memset((char *) enumerator + sizeof(enumerator->super), 0, sizeof(*enumerator) - sizeof(enumerator->super)); enumerator->get_value = enum_get_value; enumerator->get_count = enum_get_count; enumerator->value_from_string = enum_value_from_string; enumerator->string_from_value = enum_string_from_value; enumerator->dump = enum_dump; enumerator->enum_is_static = false; } static void pmix_mca_base_var_enum_destructor(pmix_mca_base_var_enum_t *enumerator) { if (enumerator->enum_name) { free(enumerator->enum_name); } /* release the copy of the values */ if (enumerator->enum_values) { for (int i = 0; i < enumerator->enum_value_count; ++i) { free((void *) enumerator->enum_values[i].string); } free(enumerator->enum_values); } } static int enum_get_value_flag(pmix_mca_base_var_enum_t *self, int index, int *value, const char **string_value) { pmix_mca_base_var_enum_flag_t *flag_enum = (pmix_mca_base_var_enum_flag_t *) self; int count, ret; ret = self->get_count(self, &count); if (PMIX_SUCCESS != ret) { return ret; } if (index >= count) { return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } if (value) { *value = flag_enum->enum_flags[index].flag; } if (string_value) { *string_value = strdup(flag_enum->enum_flags[index].string); } return PMIX_SUCCESS; } static int enum_value_from_string_flag(pmix_mca_base_var_enum_t *self, const char *string_value, int *value_out) { pmix_mca_base_var_enum_flag_t *flag_enum = (pmix_mca_base_var_enum_flag_t *) self; int value, count, ret, flag; char **flags; bool is_int; char *tmp; ret = self->get_count(self, &count); if (PMIX_SUCCESS != ret) { return ret; } flags = PMIx_Argv_split(string_value, ','); if (NULL == flags) { return PMIX_ERR_BAD_PARAM; } flag = 0; for (int i = 0; flags[i]; ++i) { value = strtol(flags[i], &tmp, 0); is_int = tmp[0] == '\0'; bool found = false, conflict = false; for (int j = 0; j < count; ++j) { if ((is_int && (value == flag_enum->enum_flags[i].flag)) || 0 == strcasecmp(flags[i], flag_enum->enum_flags[i].string)) { found = true; if (flag & flag_enum->enum_flags[i].conflicting_flag) { conflict = true; } else { flag |= flag_enum->enum_flags[i].flag; } break; } } if (!found || conflict) { PMIx_Argv_free(flags); return !found ? PMIX_ERR_VALUE_OUT_OF_BOUNDS : PMIX_ERR_BAD_PARAM; } } PMIx_Argv_free(flags); *value_out = flag; return PMIX_SUCCESS; } static int enum_string_from_value_flag(pmix_mca_base_var_enum_t *self, const int value, char **string_value) { pmix_mca_base_var_enum_flag_t *flag_enum = (pmix_mca_base_var_enum_flag_t *) self; int count, ret, current; char *out = NULL, *tmp; ret = self->get_count(self, &count); if (PMIX_SUCCESS != ret) { return ret; } current = value; for (int i = 0; i < count; ++i) { if (!(flag_enum->enum_flags[i].flag & current)) { continue; } tmp = out; ret = asprintf(&out, "%s%s%s", tmp ? tmp : "", tmp ? "," : "", flag_enum->enum_flags[i].string); free(tmp); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } if (value & flag_enum->enum_flags[i].conflicting_flag) { free(out); return PMIX_ERR_BAD_PARAM; } current &= ~flag_enum->enum_flags[i].flag; } if (current) { free(out); return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } if (string_value) { *string_value = out ? out : strdup(""); } else { free(out); } return PMIX_SUCCESS; } static int enum_dump_flag(pmix_mca_base_var_enum_t *self, char **out, pmix_mca_base_var_enum_dump_type_t output_type) { pmix_mca_base_var_enum_flag_t *flag_enum = (pmix_mca_base_var_enum_flag_t *) self; char *tmp; int ret; char *color_vv = "", *color_reset = ""; *out = NULL; if (NULL == self) { return PMIX_ERROR; } if (PMIX_MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR == output_type) { color_vv = pmix_var_dump_color[PMIX_VAR_DUMP_COLOR_VALID_VALUES]; color_reset = "\033[0m"; } *out = strdup("Comma-delimited list of: "); if (NULL == *out) { return PMIX_ERR_OUT_OF_RESOURCE; } for (int i = 0; i < self->enum_value_count; ++i) { tmp = *out; ret = pmix_asprintf(out, "%s%s%s0x%x%s|%s%s%s", tmp, i ? ", " : " ", color_vv, flag_enum->enum_flags[i].flag, color_reset, color_vv, flag_enum->enum_flags[i].string, color_reset); free(tmp); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } } return PMIX_SUCCESS; } static void pmix_mca_base_var_enum_flag_constructor(pmix_mca_base_var_enum_flag_t *enumerator) { enumerator->enum_flags = NULL; enumerator->super.get_value = enum_get_value_flag; enumerator->super.get_count = enum_get_count; enumerator->super.value_from_string = enum_value_from_string_flag; enumerator->super.string_from_value = enum_string_from_value_flag; enumerator->super.dump = enum_dump_flag; enumerator->super.enum_is_static = false; } static void pmix_mca_base_var_enum_flag_destructor(pmix_mca_base_var_enum_flag_t *enumerator) { /* release the copy of the values */ if (enumerator->enum_flags) { for (int i = 0; i < enumerator->super.enum_value_count; ++i) { free((void *) enumerator->enum_flags[i].string); } free(enumerator->enum_flags); } } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_components_close.c0000664000175000017500000000704115203536752024325 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2006 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2006 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2006 The Regents of the University of California. * All rights reserved. * Copyright (c) 2013-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_component_repository.h" #include "src/mca/mca.h" #include "src/util/pmix_output.h" void pmix_mca_base_component_unload(const pmix_mca_base_component_t *component, int output_id) { int ret; /* Unload */ pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca: base: close: unloading component %s", component->pmix_mca_component_name); ret = pmix_mca_base_var_group_find(component->pmix_mca_project_name, component->pmix_mca_type_name, component->pmix_mca_component_name); if (0 <= ret) { pmix_mca_base_var_group_deregister(ret); } pmix_mca_base_component_repository_release(component); } void pmix_mca_base_component_close(const pmix_mca_base_component_t *component, int output_id) { /* Close */ if (NULL != component->pmix_mca_close_component) { component->pmix_mca_close_component(); pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca: base: close: component %s closed", component->pmix_mca_component_name); } pmix_mca_base_component_unload(component, output_id); } int pmix_mca_base_framework_components_close(pmix_mca_base_framework_t *framework, const pmix_mca_base_component_t *skip) { return pmix_mca_base_components_close(framework->framework_output, &framework->framework_components, skip); } int pmix_mca_base_components_close(int output_id, pmix_list_t *components, const pmix_mca_base_component_t *skip) { pmix_mca_base_component_list_item_t *cli, *next; /* Close and unload all components in the available list, except the "skip" item. This is handy to close out all non-selected components. It's easier to simply remove the entire list and then simply re-add the skip entry when done. */ PMIX_LIST_FOREACH_SAFE (cli, next, components, pmix_mca_base_component_list_item_t) { if (skip == cli->cli_component) { continue; } pmix_mca_base_component_close(cli->cli_component, output_id); pmix_list_remove_item(components, &cli->super); PMIX_RELEASE(cli); } /* All done */ return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_var.c0000664000175000017500000017457415203536752021563 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2012 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2021 FUJITSU LIMITED. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #include #include "pmix_common.h" #include "src/include/pmix_stdint.h" #include "src/mca/base/pmix_mca_base_vari.h" #include "src/mca/mca.h" #include "src/mca/pinstalldirs/pinstalldirs.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_output.h" #include "src/util/pmix_path.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #ifndef MAXPATHLEN /* Hurd */ #define MAXPATHLEN 1024 #endif /* * global variables */ bool pmix_mca_base_var_initialized = false; pmix_list_t pmix_mca_base_var_file_values = PMIX_LIST_STATIC_INIT; pmix_list_t pmix_mca_base_var_override_values = PMIX_LIST_STATIC_INIT; /* * local variables */ static pmix_pointer_array_t pmix_mca_base_vars; static char *home = NULL; static char *cwd = NULL; static char *force_agg_path = NULL; static char *pmix_mca_base_var_files = NULL; static char **pmix_mca_base_var_file_list = NULL; static char *pmix_mca_base_var_override_file = NULL; static char *pmix_mca_base_var_file_prefix = NULL; static char *pmix_mca_base_param_file_path = NULL; static bool pmix_mca_base_var_suppress_override_warning = false; static int pmix_mca_base_var_count = 0; static pmix_hash_table_t pmix_mca_base_var_index_hash = PMIX_HASH_TABLE_STATIC_INIT; #define PMIX_MCA_VAR_MBV_ENUMERATOR_FREE(mbv_enumerator) \ { \ if (mbv_enumerator && !mbv_enumerator->enum_is_static) { \ PMIX_RELEASE(mbv_enumerator); \ } \ } const char *pmix_var_type_names[] = {"int", "unsigned_int", "unsigned_long", "unsigned_long_long", "size_t", "string", "version_string", "bool", "double"}; const size_t pmix_var_type_sizes[] = {sizeof(int), sizeof(unsigned), sizeof(unsigned long), sizeof(unsigned long long), sizeof(size_t), sizeof(char), sizeof(char), sizeof(bool), sizeof(double)}; const char *pmix_var_source_names[] = {"default", "command line", "environment", "file", "set", "override"}; /* * local functions */ static int fixup_files(char **file_list, char *path, bool rel_path_search, char sep); static int read_files(char *file_list, pmix_list_t *file_values, char sep); static int var_set_initial(pmix_mca_base_var_t *var, pmix_mca_base_var_t *original); static int var_get(int vari, pmix_mca_base_var_t **var_out, bool original); static int var_value_string(pmix_mca_base_var_t *var, char **value_string); /* * classes */ static void var_constructor(pmix_mca_base_var_t *p); static void var_destructor(pmix_mca_base_var_t *p); PMIX_CLASS_INSTANCE(pmix_mca_base_var_t, pmix_object_t, var_constructor, var_destructor); static void fv_constructor(pmix_mca_base_var_file_value_t *p); static void fv_destructor(pmix_mca_base_var_file_value_t *p); PMIX_CLASS_INSTANCE(pmix_mca_base_var_file_value_t, pmix_list_item_t, fv_constructor, fv_destructor); static const char *pmix_mca_base_var_source_file(const pmix_mca_base_var_t *var) { pmix_mca_base_var_file_value_t *fv = (pmix_mca_base_var_file_value_t *) var->mbv_file_value; if (NULL != var->mbv_source_file) { return var->mbv_source_file; } if (fv) { return fv->mbvfv_file; } return NULL; } /* * Generate a full name from three names */ int pmix_mca_base_var_generate_full_name4(const char *project, const char *framework, const char *component, const char *variable, char **full_name) { const char *const names[] = {project, framework, component, variable}; char *name, *tmp; size_t i, len; *full_name = NULL; for (i = 0, len = 0; i < 4; ++i) { if (NULL != names[i]) { /* Add space for the string + _ or \0 */ len += strlen(names[i]) + 1; } } name = calloc(1, len); if (NULL == name) { return PMIX_ERR_OUT_OF_RESOURCE; } for (i = 0, tmp = name; i < 4; ++i) { if (NULL != names[i]) { if (name != tmp) { *tmp++ = '_'; } strncat(name, names[i], len - (size_t)(uintptr_t)(tmp - name)); tmp += strlen(names[i]); } } *full_name = name; return PMIX_SUCCESS; } static int compare_strings(const char *str1, const char *str2) { if ((NULL != str1 && 0 == strcmp(str1, "*")) || (NULL == str1 && NULL == str2)) { return 0; } if (NULL != str1 && NULL != str2) { return strcmp(str1, str2); } return 1; } /* * Append a filename to the file list if it does not exist and return a * pointer to the filename in the list. */ static char *append_filename_to_list(const char *filename) { int i, count; (void) PMIx_Argv_append_unique_nosize(&pmix_mca_base_var_file_list, filename); count = PMIx_Argv_count(pmix_mca_base_var_file_list); for (i = count - 1; i >= 0; --i) { if (0 == strcmp(pmix_mca_base_var_file_list[i], filename)) { return pmix_mca_base_var_file_list[i]; } } /* *#@*? */ return NULL; } /* * Set it up */ int pmix_mca_base_var_init(void) { int ret; if (!pmix_mca_base_var_initialized) { /* Init the value array for the param storage */ PMIX_CONSTRUCT(&pmix_mca_base_vars, pmix_pointer_array_t); /* These values are arbitrary */ ret = pmix_pointer_array_init(&pmix_mca_base_vars, 128, 16384, 128); if (PMIX_SUCCESS != ret) { return ret; } pmix_mca_base_var_count = 0; /* Init the file param value list */ PMIX_CONSTRUCT(&pmix_mca_base_var_file_values, pmix_list_t); PMIX_CONSTRUCT(&pmix_mca_base_var_override_values, pmix_list_t); PMIX_CONSTRUCT(&pmix_mca_base_var_index_hash, pmix_hash_table_t); ret = pmix_hash_table_init(&pmix_mca_base_var_index_hash, 1024); if (PMIX_SUCCESS != ret) { return ret; } ret = pmix_mca_base_var_group_init(); if (PMIX_SUCCESS != ret) { return ret; } /* Set this before we register the parameter, below */ pmix_mca_base_var_initialized = true; pmix_mca_base_var_cache_files(false); } return PMIX_SUCCESS; } static void resolve_relative_paths(char **file_prefix, char *file_path, bool rel_path_search, char **files, char sep) { char *tmp_str; /* * Resolve all relative paths. * the file list returned will contain only absolute paths */ if (PMIX_SUCCESS != fixup_files(file_prefix, file_path, rel_path_search, sep)) { #if 0 /* JJH We need to die! */ abort(); #else ; #endif } else { /* Prepend the files to the search list */ if (0 > asprintf(&tmp_str, "%s%c%s", *file_prefix, sep, *files)) { pmix_output(0, "OUT OF MEM"); free(*files); free(tmp_str); *files = NULL; return; } free(*files); *files = tmp_str; } } int pmix_mca_base_var_cache_files(bool rel_path_search) { char *tmp; int ret = 0; /* We may need this later */ home = (char *) pmix_home_directory(geteuid()); if (NULL == cwd) { cwd = (char *) malloc(sizeof(char) * MAXPATHLEN); if (NULL == (cwd = getcwd(cwd, MAXPATHLEN))) { pmix_output(0, "Error: Unable to get the current working directory\n"); cwd = strdup("."); } } /* if we were passed our PMIx param file contents, then no need * to obtain them here */ if (NULL != getenv("PMIX_PARAM_FILE_PASSED")) { return PMIX_SUCCESS; } #if PMIX_WANT_HOME_CONFIG_FILES ret = asprintf(&pmix_mca_base_var_files, "%s" PMIX_PATH_SEP ".pmix" PMIX_PATH_SEP "mca-params.conf%c%s" PMIX_PATH_SEP "pmix-mca-params.conf", home, ',', pmix_pinstall_dirs.sysconfdir); #else ret = asprintf(&pmix_mca_base_var_files, "%s" PMIX_PATH_SEP "pmix-mca-params.conf", pmix_pinstall_dirs.sysconfdir); #endif if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } /* Initialize a parameter that says where MCA param files can be found */ tmp = pmix_mca_base_var_files; ret = pmix_mca_base_var_register("pmix", "mca", "base", "param_files", "Path for MCA " "configuration files containing variable values", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_base_var_files); free(tmp); if (PMIX_SUCCESS != ret) { return ret; } (void) pmix_mca_base_var_register_synonym(ret, "pmix", "mca", NULL, "param_files", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); ret = asprintf(&pmix_mca_base_var_override_file, "%s" PMIX_PATH_SEP "pmix-mca-params-override.conf", pmix_pinstall_dirs.sysconfdir); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } tmp = pmix_mca_base_var_override_file; ret = pmix_mca_base_var_register("pmix", "mca", "base", "override_param_file", "Variables set in this file will override any value set in" "the environment or another configuration file", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_base_var_override_file); free(tmp); if (0 > ret) { return ret; } /* Disable reading MCA parameter files. */ if (NULL == pmix_mca_base_var_files || 0 == strcmp(pmix_mca_base_var_files, "none")) { return PMIX_SUCCESS; } pmix_mca_base_var_suppress_override_warning = false; ret = pmix_mca_base_var_register( "pmix", "mca", "base", "suppress_override_warning", "Suppress warnings when attempting to set an overridden value (default: false)", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_mca_base_var_suppress_override_warning); if (0 > ret) { return ret; } /* Aggregate MCA parameter files * A prefix search path to look up aggregate MCA parameter file * requests that do not specify an absolute path */ pmix_mca_base_var_file_prefix = NULL; ret = pmix_mca_base_var_register("pmix", "mca", "base", "param_file_prefix", "Aggregate MCA parameter file sets", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_base_var_file_prefix); if (0 > ret) { return ret; } ret = asprintf(&pmix_mca_base_param_file_path, "%s" PMIX_PATH_SEP "amca-param-sets%c%s", pmix_pinstall_dirs.pmixdatadir, PMIX_ENV_SEP, cwd); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } tmp = pmix_mca_base_param_file_path; ret = pmix_mca_base_var_register("pmix", "mca", "base", "param_file_path", "Aggregate MCA parameter Search path", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_base_param_file_path); free(tmp); if (0 > ret) { return ret; } force_agg_path = NULL; ret = pmix_mca_base_var_register("pmix", "mca", "base", "param_file_path_force", "Forced Aggregate MCA parameter Search path", PMIX_MCA_BASE_VAR_TYPE_STRING, &force_agg_path); if (0 > ret) { return ret; } if (NULL != force_agg_path) { if (NULL != pmix_mca_base_param_file_path) { char *tmp_str = pmix_mca_base_param_file_path; ret = asprintf(&pmix_mca_base_param_file_path, "%s%c%s", force_agg_path, PMIX_ENV_SEP, tmp_str); free(tmp_str); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } } else { pmix_mca_base_param_file_path = strdup(force_agg_path); } } if (NULL != pmix_mca_base_var_file_prefix) { resolve_relative_paths(&pmix_mca_base_var_file_prefix, pmix_mca_base_param_file_path, rel_path_search, &pmix_mca_base_var_files, PMIX_ENV_SEP); } ret = read_files(pmix_mca_base_var_files, &pmix_mca_base_var_file_values, ','); if (PMIX_SUCCESS != ret && PMIX_ERR_NOT_FOUND != ret) { // it is okay if a file isn't found return ret; } ret = read_files(pmix_mca_base_var_override_file, &pmix_mca_base_var_override_values, PMIX_ENV_SEP); if (PMIX_SUCCESS != ret && PMIX_ERR_NOT_FOUND != ret) { // it is okay if the file isn't found return ret; } return PMIX_SUCCESS; } /* * Look up an integer MCA parameter. */ int pmix_mca_base_var_get_value(int vari, void *value, pmix_mca_base_var_source_t *source, const char **source_file) { pmix_mca_base_var_t *var; void **tmp = (void **) value; int ret; ret = var_get(vari, &var, true); if (PMIX_SUCCESS != ret) { return ret; } if (!PMIX_VAR_IS_VALID(var[0])) { return PMIX_ERR_NOT_FOUND; } if (NULL != value) { /* Return a pointer to our backing store (either a char **, int *, or bool *) */ *tmp = var->mbv_storage; } if (NULL != source) { *source = var->mbv_source; } if (NULL != source_file) { *source_file = pmix_mca_base_var_source_file(var); } return PMIX_SUCCESS; } static int var_set_string(pmix_mca_base_var_t *var, char *value) { char *tmp; int ret; if (NULL != var->mbv_storage->stringval) { free(var->mbv_storage->stringval); } var->mbv_storage->stringval = NULL; if (NULL == value || 0 == strlen(value)) { return PMIX_SUCCESS; } /* Replace all instances of ~/ in a path-style string with the user's home directory. This may be handled by the enumerator in the future. */ if (0 == strncmp(value, "~/", 2)) { if (NULL != home) { ret = asprintf(&value, "%s/%s", home, value + 2); if (0 > ret) { return PMIX_ERROR; } } else { value = strdup(value + 2); } } else { value = strdup(value); } if (NULL == value) { return PMIX_ERR_OUT_OF_RESOURCE; } while (NULL != (tmp = strstr(value, ":~/"))) { tmp[0] = '\0'; tmp += 3; ret = asprintf(&tmp, "%s:%s%s%s", value, home ? home : "", home ? "/" : "", tmp); free(value); if (0 > ret) { return PMIX_ERR_OUT_OF_RESOURCE; } value = tmp; } var->mbv_storage->stringval = value; return PMIX_SUCCESS; } static int int_from_string(const char *src, pmix_mca_base_var_enum_t *enumerator, uint64_t *value_out) { uint64_t value; bool is_int; char *tmp; if (NULL == src || 0 == strlen(src)) { if (NULL == enumerator) { *value_out = 0; } return PMIX_SUCCESS; } if (enumerator) { int int_val, ret; ret = enumerator->value_from_string(enumerator, src, &int_val); if (PMIX_SUCCESS != ret) { return ret; } *value_out = (uint64_t) int_val; return PMIX_SUCCESS; } /* Check for an integer value */ value = strtoull(src, &tmp, 0); if (tmp[0] == '\0') { is_int = true; } else { is_int = false; } if (!is_int && tmp != src) { switch (tmp[0]) { case 'G': case 'g': value <<= 30; break; case 'M': case 'm': value <<= 20; break; case 'K': case 'k': value <<= 10; break; default: break; } } *value_out = value; return PMIX_SUCCESS; } static int var_set_from_string(pmix_mca_base_var_t *var, char *src) { pmix_mca_base_var_storage_t *dst = var->mbv_storage; uint64_t int_value = 0; int ret; bool *boolcastme; char *tmp; switch (var->mbv_type) { case PMIX_MCA_BASE_VAR_TYPE_INT: case PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_INT: case PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_LONG: case PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_LONG_LONG: case PMIX_MCA_BASE_VAR_TYPE_SIZE_T: ret = int_from_string(src, var->mbv_enumerator, &int_value); if (PMIX_ERR_VALUE_OUT_OF_BOUNDS == ret || (PMIX_MCA_BASE_VAR_TYPE_INT == var->mbv_type && ((int) int_value != (int64_t) int_value)) || (PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_INT == var->mbv_type && ((unsigned int) int_value != int_value))) { if (var->mbv_enumerator) { char *valid_values; (void) var->mbv_enumerator->dump(var->mbv_enumerator, &valid_values, PMIX_MCA_BASE_VAR_ENUM_DUMP_READABLE); pmix_show_help("help-pmix-mca-var.txt", "invalid-value-enum", true, var->mbv_full_name, src, valid_values); free(valid_values); } else { pmix_show_help("help-pmix-mca-var.txt", "invalid-value", true, var->mbv_full_name, src); } return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } if (PMIX_MCA_BASE_VAR_TYPE_INT == var->mbv_type || PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_INT == var->mbv_type) { int *castme = (int *) var->mbv_storage; *castme = int_value; } else if (PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_LONG == var->mbv_type) { unsigned long *castme = (unsigned long *) var->mbv_storage; *castme = (unsigned long) int_value; } else if (PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_LONG_LONG == var->mbv_type) { unsigned long long *castme = (unsigned long long *) var->mbv_storage; *castme = (unsigned long long) int_value; } else if (PMIX_MCA_BASE_VAR_TYPE_SIZE_T == var->mbv_type) { size_t *castme = (size_t *) var->mbv_storage; *castme = (size_t) int_value; } return ret; case PMIX_MCA_BASE_VAR_TYPE_BOOL: boolcastme = (bool *) var->mbv_storage; int_value = strtoull(src, &tmp, 0); if (tmp[0] == '\0') { *boolcastme = !!int_value; } else { if (0 == strncasecmp(src, "true", strlen(src))) { *boolcastme = true; } else if (0 == strncasecmp(src, "false", strlen(src))) { *boolcastme = false; } else { return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } } return PMIX_SUCCESS; case PMIX_MCA_BASE_VAR_TYPE_DOUBLE: dst->lfval = strtod(src, NULL); break; case PMIX_MCA_BASE_VAR_TYPE_STRING: case PMIX_MCA_BASE_VAR_TYPE_VERSION_STRING: var_set_string(var, src); break; case PMIX_MCA_BASE_VAR_TYPE_MAX: return PMIX_ERROR; } return PMIX_SUCCESS; } /* * Deregister a parameter */ int pmix_mca_base_var_deregister(int vari) { pmix_mca_base_var_t *var; int ret; ret = var_get(vari, &var, false); if (PMIX_SUCCESS != ret) { return ret; } if (!PMIX_VAR_IS_VALID(var[0])) { return PMIX_ERR_BAD_PARAM; } /* Mark this parameter as invalid but keep its info in case this parameter is reregistered later */ var->mbv_flags &= ~PMIX_MCA_BASE_VAR_FLAG_VALID; /* Done deregistering synonym */ if (PMIX_MCA_BASE_VAR_FLAG_SYNONYM & var->mbv_flags) { return PMIX_SUCCESS; } /* Release the current value if it is a string. */ if ((PMIX_MCA_BASE_VAR_TYPE_STRING == var->mbv_type || PMIX_MCA_BASE_VAR_TYPE_VERSION_STRING == var->mbv_type) && var->mbv_storage->stringval) { free(var->mbv_storage->stringval); var->mbv_storage->stringval = NULL; } else { PMIX_MCA_VAR_MBV_ENUMERATOR_FREE(var->mbv_enumerator); } var->mbv_enumerator = NULL; var->mbv_storage = NULL; return PMIX_SUCCESS; } static int var_get(int vari, pmix_mca_base_var_t **var_out, bool original) { pmix_mca_base_var_t *var; if (var_out) { *var_out = NULL; } /* Check for bozo cases */ if (!pmix_mca_base_var_initialized) { return PMIX_ERROR; } if (vari < 0) { return PMIX_ERR_BAD_PARAM; } var = pmix_pointer_array_get_item(&pmix_mca_base_vars, vari); if (NULL == var) { return PMIX_ERR_BAD_PARAM; } if (PMIX_VAR_IS_SYNONYM(var[0]) && original) { return var_get(var->mbv_synonym_for, var_out, false); } if (var_out) { *var_out = var; } return PMIX_SUCCESS; } /* * Find the index for an MCA parameter based on its names. */ static int var_find_by_name(const char *full_name, int *vari, bool invalidok) { pmix_mca_base_var_t *var = NULL; void *tmp; int rc; rc = pmix_hash_table_get_value_ptr(&pmix_mca_base_var_index_hash, full_name, strlen(full_name), &tmp); if (PMIX_SUCCESS != rc) { return rc; } (void) var_get((int) (uintptr_t) tmp, &var, false); if (invalidok || (var && PMIX_VAR_IS_VALID(var[0]))) { *vari = (int) (uintptr_t) tmp; return PMIX_SUCCESS; } return PMIX_ERR_NOT_FOUND; } static int var_find(const char *project_name, const char *framework_name, const char *component_name, const char *variable_name, bool invalidok) { (void) project_name; char *full_name; int ret, vari; ret = pmix_mca_base_var_generate_full_name4(NULL, framework_name, component_name, variable_name, &full_name); if (PMIX_SUCCESS != ret) { return PMIX_ERROR; } ret = var_find_by_name(full_name, &vari, invalidok); /* NTH: should we verify the name components match? */ free(full_name); if (PMIX_SUCCESS != ret) { return ret; } return vari; } /* * Find the index for an MCA parameter based on its name components. */ int pmix_mca_base_var_find(const char *project_name, const char *framework_name, const char *component_name, const char *variable_name) { return var_find(project_name, framework_name, component_name, variable_name, false); } /* * Find the index for an MCA parameter based on full name. */ int pmix_mca_base_var_find_by_name(const char *full_name, int *vari) { return var_find_by_name(full_name, vari, false); } /* * Return info on a parameter at an index */ int pmix_mca_base_var_get(int vari, const pmix_mca_base_var_t **var) { int ret; ret = var_get(vari, (pmix_mca_base_var_t **) var, false); if (PMIX_SUCCESS != ret) { return ret; } if (!PMIX_VAR_IS_VALID(*(var[0]))) { return PMIX_ERR_NOT_FOUND; } return PMIX_SUCCESS; } /* * Make an argv-style list of strings suitable for an environment */ int pmix_mca_base_var_build_env(char ***env, int *num_env) { pmix_mca_base_var_t *var; size_t i, len; int ret = 0; /* Check for bozo cases */ if (!pmix_mca_base_var_initialized) { return PMIX_ERROR; } /* Iterate through all the registered parameters */ len = pmix_pointer_array_get_size(&pmix_mca_base_vars); for (i = 0; i < len; ++i) { char *value_string; char *str = NULL; var = pmix_pointer_array_get_item(&pmix_mca_base_vars, i); if (NULL == var) { continue; } /* Don't output default values */ if (PMIX_MCA_BASE_VAR_SOURCE_DEFAULT == var->mbv_source) { continue; } if ((PMIX_MCA_BASE_VAR_TYPE_STRING == var->mbv_type || PMIX_MCA_BASE_VAR_TYPE_VERSION_STRING == var->mbv_type) && NULL == var->mbv_storage->stringval) { continue; } ret = var_value_string(var, &value_string); if (PMIX_SUCCESS != ret) { goto cleanup; } ret = asprintf(&str, "%s%s=%s", var->mbv_prefix, var->mbv_full_name, value_string); free(value_string); if (0 > ret) { goto cleanup; } pmix_argv_append(num_env, env, str); free(str); str = NULL; ret = PMIX_SUCCESS; switch (var->mbv_source) { case PMIX_MCA_BASE_VAR_SOURCE_FILE: case PMIX_MCA_BASE_VAR_SOURCE_OVERRIDE: ret = asprintf(&str, "%sSOURCE_%s=FILE:%s", var->mbv_prefix, var->mbv_full_name, pmix_mca_base_var_source_file(var)); break; case PMIX_MCA_BASE_VAR_SOURCE_COMMAND_LINE: ret = asprintf(&str, "%sSOURCE_%s=COMMAND_LINE", var->mbv_prefix, var->mbv_full_name); break; case PMIX_MCA_BASE_VAR_SOURCE_ENV: case PMIX_MCA_BASE_VAR_SOURCE_SET: case PMIX_MCA_BASE_VAR_SOURCE_DEFAULT: str = NULL; break; case PMIX_MCA_BASE_VAR_SOURCE_MAX: goto cleanup; } if (NULL != str) { pmix_argv_append(num_env, env, str); free(str); } } if (ret < 0) { ret = PMIX_ERR_OUT_OF_RESOURCE; } /* All done */ return ret; /* Error condition */ cleanup: if (*num_env > 0) { PMIx_Argv_free(*env); *num_env = 0; *env = NULL; } return PMIX_ERR_NOT_FOUND; } /* * Shut down the MCA parameter system (normally only invoked by the * MCA framework itself). */ int pmix_mca_base_var_finalize(void) { pmix_object_t *pmixect; int size, i; if (pmix_mca_base_var_initialized) { size = pmix_pointer_array_get_size(&pmix_mca_base_vars); for (i = 0; i < size; ++i) { pmixect = pmix_pointer_array_get_item(&pmix_mca_base_vars, i); if (NULL != pmixect) { PMIX_RELEASE(pmixect); } } PMIX_DESTRUCT(&pmix_mca_base_vars); PMIX_LIST_DESTRUCT(&pmix_mca_base_var_file_values); PMIX_LIST_DESTRUCT(&pmix_mca_base_var_override_values); if (NULL != cwd) { free(cwd); cwd = NULL; } pmix_mca_base_var_initialized = false; pmix_mca_base_var_count = 0; if (NULL != pmix_mca_base_var_file_list) { PMIx_Argv_free(pmix_mca_base_var_file_list); } pmix_mca_base_var_file_list = NULL; (void) pmix_mca_base_var_group_finalize(); PMIX_DESTRUCT(&pmix_mca_base_var_index_hash); } /* All done */ return PMIX_SUCCESS; } /*************************************************************************/ static int fixup_files(char **file_list, char *path, bool rel_path_search, char sep) { int exit_status = PMIX_SUCCESS; char **files = NULL; char **search_path = NULL; char *tmp_file = NULL; char **argv = NULL; char *rel_path; int mode = R_OK; /* The file exists, and we can read it */ int count, i, argc = 0; search_path = PMIx_Argv_split(path, PMIX_ENV_SEP); files = PMIx_Argv_split(*file_list, sep); count = PMIx_Argv_count(files); rel_path = force_agg_path ? force_agg_path : cwd; /* Read in reverse order, so we can preserve the original ordering */ for (i = 0; i < count; ++i) { char *msg_path = path; if (pmix_path_is_absolute(files[i])) { /* Absolute paths preserved */ tmp_file = pmix_os_path(false, files[i], NULL); } else if (!rel_path_search && NULL != strchr(files[i], PMIX_PATH_SEP[0])) { /* Resolve all relative paths: * - If filename contains a "/" (e.g., "./foo" or "foo/bar") * - look for it relative to cwd * - if exists, use it * - ow warn/error */ msg_path = rel_path; tmp_file = pmix_os_path(false, files[i], rel_path, NULL); } else { /* Resolve all relative paths: * - Use path resolution * - if found and readable, use it * - otherwise, warn/error */ tmp_file = pmix_path_find(files[i], search_path, mode, NULL); } if (NULL == tmp_file) { pmix_show_help("help-pmix-mca-var.txt", "missing-param-file", true, getpid(), files[i], msg_path); exit_status = PMIX_ERROR; break; } pmix_argv_append(&argc, &argv, tmp_file); free(tmp_file); } if (PMIX_SUCCESS == exit_status) { free(*file_list); *file_list = PMIx_Argv_join(argv, sep); } if (NULL != files) { PMIx_Argv_free(files); files = NULL; } if (NULL != argv) { PMIx_Argv_free(argv); argv = NULL; } if (NULL != search_path) { PMIx_Argv_free(search_path); search_path = NULL; } return exit_status; } static int read_files(char *file_list, pmix_list_t *file_values, char sep) { char **tmp; int i, count, rc; if (NULL == file_list) { return PMIX_SUCCESS; } tmp = PMIx_Argv_split(file_list, sep); if (!tmp) { return PMIX_ERR_OUT_OF_RESOURCE; } count = PMIx_Argv_count(tmp); /* Iterate through all the files passed in -- read them in reverse order so that we preserve unix/shell path-like semantics (i.e., the entries farthest to the left get precedence) */ for (i = count - 1; i >= 0; --i) { char *file_name = append_filename_to_list(tmp[i]); rc = pmix_mca_base_parse_paramfile(file_name, file_values); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_FOUND != rc) { // it is okay if the file isn't found PMIx_Argv_free(tmp); return rc; } } PMIx_Argv_free(tmp); pmix_mca_base_internal_env_store(); return PMIX_SUCCESS; } /******************************************************************************/ static int register_variable(const char *project_name, const char *framework_name, const char *component_name, const char *variable_name, const char *description, pmix_mca_base_var_type_t type, pmix_mca_base_var_flag_internal_t flags, int synonym_for, void *storage) { int ret, var_index, group_index, tmp; pmix_mca_base_var_group_t *group; pmix_mca_base_var_t *var, *original = NULL; char *ntmp; int n; /* Developer error. Storage can not be NULL and type must exist */ assert(((flags & PMIX_MCA_BASE_VAR_FLAG_SYNONYM) || NULL != storage) && type < PMIX_MCA_BASE_VAR_TYPE_MAX); #if PMIX_ENABLE_DEBUG /* Developer error: check for alignments */ uintptr_t align = 0; switch (type) { case PMIX_MCA_BASE_VAR_TYPE_INT: align = ALIGNOF_INT; break; case PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_INT: align = ALIGNOF_INT; break; case PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_LONG: align = ALIGNOF_LONG; break; case PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_LONG_LONG: align = ALIGNOF_LONG_LONG; break; case PMIX_MCA_BASE_VAR_TYPE_SIZE_T: align = ALIGNOF_SIZE_T; break; case PMIX_MCA_BASE_VAR_TYPE_BOOL: align = ALIGNOF_BOOL; break; case PMIX_MCA_BASE_VAR_TYPE_DOUBLE: align = ALIGNOF_DOUBLE; break; case PMIX_MCA_BASE_VAR_TYPE_VERSION_STRING: case PMIX_MCA_BASE_VAR_TYPE_STRING: default: align = 0; break; } if (0 != align) { assert(((uintptr_t) storage) % align == 0); } /* Also check to ensure that synonym_for>=0 when MCA_BCASE_VAR_FLAG_SYNONYM is specified */ if (flags & PMIX_MCA_BASE_VAR_FLAG_SYNONYM && synonym_for < 0) { assert((flags & PMIX_MCA_BASE_VAR_FLAG_SYNONYM) && synonym_for >= 0); } #endif if (flags & PMIX_MCA_BASE_VAR_FLAG_SYNONYM) { if (synonym_for < 0) { return PMIX_ERR_BAD_PARAM; } original = pmix_pointer_array_get_item(&pmix_mca_base_vars, synonym_for); if (NULL == original) { /* Attempting to create a synonym for a non-existent variable. probably a * developer error. */ assert(NULL != original); return PMIX_ERR_NOT_FOUND; } } /* Initialize the array if it has never been initialized */ if (!pmix_mca_base_var_initialized) { ret = pmix_mca_base_var_init(); if (PMIX_SUCCESS != ret) { return ret; } } /* See if this entry is already in the array */ var_index = var_find(project_name, framework_name, component_name, variable_name, true); if (0 > var_index) { /* Create a new parameter entry */ group_index = pmix_mca_base_var_group_register(project_name, framework_name, component_name, NULL); if (-1 > group_index) { return group_index; } var = PMIX_NEW(pmix_mca_base_var_t); ntmp = (char*)malloc(strlen(project_name)+1); for (n=0; '\0' != project_name[n]; n++) { ntmp[n] = toupper(project_name[n]); } ntmp[n] = '\0'; pmix_asprintf(&var->mbv_prefix, "%s_MCA_", ntmp); free(ntmp); var->mbv_type = type; var->mbv_flags = flags; var->mbv_group_index = group_index; var->mbv_synonym_for = synonym_for; if (NULL != description) { var->mbv_description = strdup(description); } if (NULL != variable_name) { var->mbv_variable_name = strdup(variable_name); if (NULL == var->mbv_variable_name) { PMIX_RELEASE(var); return PMIX_ERR_OUT_OF_RESOURCE; } } ret = pmix_mca_base_var_generate_full_name4(NULL, framework_name, component_name, variable_name, &var->mbv_full_name); if (PMIX_SUCCESS != ret) { PMIX_RELEASE(var); return PMIX_ERROR; } ret = pmix_mca_base_var_generate_full_name4(project_name, framework_name, component_name, variable_name, &var->mbv_long_name); if (PMIX_SUCCESS != ret) { PMIX_RELEASE(var); return PMIX_ERROR; } /* Add it to the array. Note that we copy the mca_var_t by value, so the entire contents of the struct is copied. The synonym list will always be empty at this point, so there's no need for an extra RETAIN or RELEASE. */ var_index = pmix_pointer_array_add(&pmix_mca_base_vars, var); if (0 > var_index) { PMIX_RELEASE(var); return PMIX_ERROR; } var->mbv_index = var_index; if (0 <= group_index) { pmix_mca_base_var_group_add_var(group_index, var_index); } pmix_mca_base_var_count++; if (0 <= var_find_by_name(var->mbv_full_name, &tmp, 0)) { /* XXX --- FIXME: variable overshadows an existing variable. this is difficult to * support */ assert(0); } pmix_hash_table_set_value_ptr(&pmix_mca_base_var_index_hash, var->mbv_full_name, strlen(var->mbv_full_name), (void *) (uintptr_t) var_index); } else { ret = var_get(var_index, &var, false); if (PMIX_SUCCESS != ret) { /* Shouldn't ever happen */ return PMIX_ERROR; } ret = pmix_mca_base_var_group_get_internal(var->mbv_group_index, &group, true); if (PMIX_SUCCESS != ret) { /* Shouldn't ever happen */ return PMIX_ERROR; } if (!group->group_isvalid) { group->group_isvalid = true; } /* Verify the name components match */ if (0 != compare_strings(framework_name, group->group_framework) || 0 != compare_strings(component_name, group->group_component) || 0 != compare_strings(variable_name, var->mbv_variable_name)) { pmix_show_help("help-pmix-mca-var.txt", "var-name-conflict", true, var->mbv_full_name, framework_name, component_name, variable_name, group->group_framework, group->group_component, var->mbv_variable_name); /* This is developer error. abort! */ assert(0); return PMIX_ERROR; } if (var->mbv_type != type) { #if PMIX_ENABLE_DEBUG pmix_show_help("help-pmix-mca-var.txt", "re-register-with-different-type", true, var->mbv_full_name); #endif return PMIX_ERR_VALUE_OUT_OF_BOUNDS; } } if (!original) { var->mbv_storage = storage; /* make a copy of the default string value */ if ((PMIX_MCA_BASE_VAR_TYPE_STRING == type || PMIX_MCA_BASE_VAR_TYPE_VERSION_STRING == type) && NULL != ((char **) storage)[0]) { ((char **) storage)[0] = strdup(((char **) storage)[0]); } } else { /* synonym variable */ pmix_value_array_append_item(&original->mbv_synonyms, &var_index); } /* go ahead and mark this variable as valid */ var->mbv_flags |= PMIX_MCA_BASE_VAR_FLAG_VALID; ret = var_set_initial(var, original); if (PMIX_SUCCESS != ret) { return ret; } /* All done */ return var_index; } int pmix_mca_base_var_register(const char *project_name, const char *framework_name, const char *component_name, const char *variable_name, const char *description, pmix_mca_base_var_type_t type, void *storage) { return register_variable(project_name, framework_name, component_name, variable_name, description, type, PMIX_MCA_BASE_VAR_FLAG_NONE, 0, storage); } int pmix_mca_base_component_var_register(const pmix_mca_base_component_t *component, const char *variable_name, const char *description, pmix_mca_base_var_type_t type, void *storage) { return pmix_mca_base_var_register(component->pmix_mca_project_name, component->pmix_mca_type_name, component->pmix_mca_component_name, variable_name, description, type, storage); } int pmix_mca_base_framework_var_register(const pmix_mca_base_framework_t *framework, const char *variable_name, const char *help_msg, pmix_mca_base_var_type_t type, void *storage) { return pmix_mca_base_var_register(framework->framework_project, framework->framework_name, "base", variable_name, help_msg, type, storage); } int pmix_mca_base_var_register_synonym(int synonym_for, const char *project_name, const char *framework_name, const char *component_name, const char *synonym_name, pmix_mca_base_var_syn_flag_t flags) { pmix_mca_base_var_flag_internal_t var_flags = PMIX_MCA_BASE_VAR_FLAG_SYNONYM; pmix_mca_base_var_t *var; int ret; ret = var_get(synonym_for, &var, false); if (PMIX_SUCCESS != ret || PMIX_VAR_IS_SYNONYM(var[0])) { return PMIX_ERR_BAD_PARAM; } if (flags & PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED) { var_flags |= PMIX_MCA_BASE_VAR_FLAG_DEPRECATED; } return register_variable(project_name, framework_name, component_name, synonym_name, var->mbv_description, var->mbv_type, var_flags, synonym_for, NULL); } static int var_get_env(pmix_mca_base_var_t *var, const char *name, char **source, char **value) { (void) var; char *source_env, *value_env; int ret; ret = asprintf(&source_env, "%sSOURCE_%s", var->mbv_prefix, name); if (0 > ret) { return PMIX_ERROR; } ret = asprintf(&value_env, "%s%s", var->mbv_prefix, name); if (0 > ret) { free(source_env); return PMIX_ERROR; } *source = getenv(source_env); *value = getenv(value_env); free(source_env); free(value_env); if (NULL == *value) { *source = NULL; return PMIX_ERR_NOT_FOUND; } return PMIX_SUCCESS; } /* * Lookup a param in the environment */ static int var_set_from_env(pmix_mca_base_var_t *var, pmix_mca_base_var_t *original) { const char *var_full_name = var->mbv_full_name; const char *var_long_name = var->mbv_long_name; bool deprecated = PMIX_VAR_IS_DEPRECATED(var[0]); bool is_synonym = PMIX_VAR_IS_SYNONYM(var[0]); char *source_env, *value_env; int ret; ret = var_get_env(var, var_long_name, &source_env, &value_env); if (PMIX_SUCCESS != ret) { ret = var_get_env(var, var_full_name, &source_env, &value_env); } if (PMIX_SUCCESS != ret) { return ret; } if (PMIX_MCA_BASE_VAR_SOURCE_OVERRIDE == original->mbv_source) { if (!pmix_mca_base_var_suppress_override_warning) { pmix_show_help("help-pmix-mca-var.txt", "overridden-param-set", true, var_full_name); } return PMIX_ERR_NOT_FOUND; } original->mbv_source = PMIX_MCA_BASE_VAR_SOURCE_ENV; if (NULL != source_env) { if (0 == strncasecmp(source_env, "file:", 5)) { original->mbv_source_file = append_filename_to_list(source_env + 5); if (0 == strcmp(var->mbv_source_file, pmix_mca_base_var_override_file)) { original->mbv_source = PMIX_MCA_BASE_VAR_SOURCE_OVERRIDE; } else { original->mbv_source = PMIX_MCA_BASE_VAR_SOURCE_FILE; } } else if (0 == strcasecmp(source_env, "command")) { var->mbv_source = PMIX_MCA_BASE_VAR_SOURCE_COMMAND_LINE; } } if (deprecated) { const char *new_variable = "None (going away)"; if (is_synonym) { new_variable = var->mbv_full_name; } switch (var->mbv_source) { case PMIX_MCA_BASE_VAR_SOURCE_ENV: pmix_show_help("help-pmix-mca-var.txt", "deprecated-mca-env", true, var_full_name, new_variable); break; case PMIX_MCA_BASE_VAR_SOURCE_COMMAND_LINE: pmix_show_help("help-pmix-mca-var.txt", "deprecated-mca-cli", true, var_full_name, new_variable); break; case PMIX_MCA_BASE_VAR_SOURCE_FILE: case PMIX_MCA_BASE_VAR_SOURCE_OVERRIDE: pmix_show_help("help-pmix-mca-var.txt", "deprecated-mca-file", true, var_full_name, pmix_mca_base_var_source_file(var), new_variable); break; case PMIX_MCA_BASE_VAR_SOURCE_DEFAULT: case PMIX_MCA_BASE_VAR_SOURCE_MAX: case PMIX_MCA_BASE_VAR_SOURCE_SET: /* silence compiler warnings about unhandled enumerations */ break; } } return var_set_from_string(original, value_env); } /* * Lookup a param in the files */ static int var_set_from_file(pmix_mca_base_var_t *var, pmix_mca_base_var_t *original, pmix_list_t *file_values) { const char *var_full_name = var->mbv_full_name; const char *var_long_name = var->mbv_long_name; bool deprecated = PMIX_VAR_IS_DEPRECATED(var[0]); bool is_synonym = PMIX_VAR_IS_SYNONYM(var[0]); pmix_mca_base_var_file_value_t *fv; /* Scan through the list of values read in from files and try to find a match. If we do, cache it on the param (for future lookups) and save it in the storage. */ PMIX_LIST_FOREACH (fv, file_values, pmix_mca_base_var_file_value_t) { if (0 != strcmp(fv->mbvfv_var, var_full_name) && 0 != strcmp(fv->mbvfv_var, var_long_name)) { continue; } if (PMIX_MCA_BASE_VAR_SOURCE_OVERRIDE == original->mbv_source) { if (!pmix_mca_base_var_suppress_override_warning) { pmix_show_help("help-pmix-mca-var.txt", "overridden-param-set", true, var_full_name); } return PMIX_ERR_NOT_FOUND; } if (deprecated) { const char *new_variable = "None (going away)"; if (is_synonym) { new_variable = original->mbv_full_name; } pmix_show_help("help-pmix-mca-var.txt", "deprecated-mca-file", true, var_full_name, fv->mbvfv_file, new_variable); } original->mbv_file_value = (void *) fv; original->mbv_source = PMIX_MCA_BASE_VAR_SOURCE_FILE; if (is_synonym) { var->mbv_file_value = (void *) fv; var->mbv_source = PMIX_MCA_BASE_VAR_SOURCE_FILE; } return var_set_from_string(original, fv->mbvfv_value); } return PMIX_ERR_NOT_FOUND; } /* * Lookup the initial value for a parameter */ static int var_set_initial(pmix_mca_base_var_t *var, pmix_mca_base_var_t *original) { int ret; if (original) { /* synonym */ var->mbv_source = original->mbv_source; var->mbv_file_value = original->mbv_file_value; var->mbv_source_file = original->mbv_source_file; } else { var->mbv_source = PMIX_MCA_BASE_VAR_SOURCE_DEFAULT; original = var; } /* Check all the places that the param may be hiding, in priority order. If the default only flag is set the user will get a warning if they try to set a value from the environment or a file. */ ret = var_set_from_file(var, original, &pmix_mca_base_var_override_values); if (PMIX_SUCCESS == ret) { var->mbv_source = PMIX_MCA_BASE_VAR_SOURCE_OVERRIDE; } ret = var_set_from_env(var, original); if (PMIX_ERR_NOT_FOUND != ret) { return ret; } ret = var_set_from_file(var, original, &pmix_mca_base_var_file_values); if (PMIX_ERR_NOT_FOUND != ret) { return ret; } return PMIX_SUCCESS; } /* * Create an empty param container */ static void var_constructor(pmix_mca_base_var_t *var) { memset((char *) var + sizeof(var->super), 0, sizeof(*var) - sizeof(var->super)); var->mbv_type = PMIX_MCA_BASE_VAR_TYPE_MAX; PMIX_CONSTRUCT(&var->mbv_synonyms, pmix_value_array_t); pmix_value_array_init(&var->mbv_synonyms, sizeof(int)); } /* * Free all the contents of a param container */ static void var_destructor(pmix_mca_base_var_t *var) { if ((PMIX_MCA_BASE_VAR_TYPE_STRING == var->mbv_type || PMIX_MCA_BASE_VAR_TYPE_VERSION_STRING == var->mbv_type) && NULL != var->mbv_storage && NULL != var->mbv_storage->stringval) { free(var->mbv_storage->stringval); var->mbv_storage->stringval = NULL; } /* don't release the boolean enumerator */ PMIX_MCA_VAR_MBV_ENUMERATOR_FREE(var->mbv_enumerator); if (NULL != var->mbv_variable_name) { free(var->mbv_variable_name); } if (NULL != var->mbv_full_name) { free(var->mbv_full_name); } if (NULL != var->mbv_long_name) { free(var->mbv_long_name); } if (NULL != var->mbv_prefix) { free(var->mbv_prefix); } if (NULL != var->mbv_description) { free(var->mbv_description); } /* Destroy the synonym array */ PMIX_DESTRUCT(&var->mbv_synonyms); /* mark this parameter as invalid */ var->mbv_type = PMIX_MCA_BASE_VAR_TYPE_MAX; #if PMIX_ENABLE_DEBUG /* Cheap trick to reset everything to NULL */ memset((char *) var + sizeof(var->super), 0, sizeof(*var) - sizeof(var->super)); #endif } static void fv_constructor(pmix_mca_base_var_file_value_t *f) { memset((char *) f + sizeof(f->super), 0, sizeof(*f) - sizeof(f->super)); } static void fv_destructor(pmix_mca_base_var_file_value_t *f) { if (NULL != f->mbvfv_var) { free(f->mbvfv_var); } if (NULL != f->mbvfv_value) { free(f->mbvfv_value); } /* the file name is stored in mca_*/ fv_constructor(f); } static char *source_name(pmix_mca_base_var_t *var) { char *ret; if (PMIX_MCA_BASE_VAR_SOURCE_FILE == var->mbv_source || PMIX_MCA_BASE_VAR_SOURCE_OVERRIDE == var->mbv_source) { struct pmix_mca_base_var_file_value_t *fv = var->mbv_file_value; int rc; if (fv) { rc = asprintf(&ret, "file (%s:%d)", fv->mbvfv_file, fv->mbvfv_lineno); } else { rc = asprintf(&ret, "file (%s)", var->mbv_source_file); } /* some compilers will warn if the return code of asprintf is not checked (even if it is * cast to void) */ if (0 > rc) { return NULL; } return ret; } else if (PMIX_MCA_BASE_VAR_SOURCE_MAX <= var->mbv_source) { return strdup("unknown(!!)"); } return strdup(pmix_var_source_names[var->mbv_source]); } static int var_value_string(pmix_mca_base_var_t *var, char **value_string) { pmix_mca_base_var_storage_t *value = NULL; int ret; assert(PMIX_MCA_BASE_VAR_TYPE_MAX > var->mbv_type); ret = pmix_mca_base_var_get_value(var->mbv_index, &value, NULL, NULL); if (PMIX_SUCCESS != ret || NULL == value) { return ret; } if (NULL == var->mbv_enumerator) { switch (var->mbv_type) { case PMIX_MCA_BASE_VAR_TYPE_INT: ret = asprintf(value_string, "%d", value->intval); break; case PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_INT: ret = asprintf(value_string, "%u", value->uintval); break; case PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_LONG: ret = asprintf(value_string, "%lu", value->ulval); break; case PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_LONG_LONG: ret = asprintf(value_string, "%llu", value->ullval); break; case PMIX_MCA_BASE_VAR_TYPE_SIZE_T: ret = asprintf(value_string, "%" PRIsize_t, value->sizetval); break; case PMIX_MCA_BASE_VAR_TYPE_STRING: case PMIX_MCA_BASE_VAR_TYPE_VERSION_STRING: ret = asprintf(value_string, "%s", value->stringval ? value->stringval : ""); break; case PMIX_MCA_BASE_VAR_TYPE_BOOL: ret = asprintf(value_string, "%d", value->boolval); break; case PMIX_MCA_BASE_VAR_TYPE_DOUBLE: ret = asprintf(value_string, "%lf", value->lfval); break; default: ret = -1; break; } ret = (0 > ret) ? PMIX_ERR_OUT_OF_RESOURCE : PMIX_SUCCESS; } else { /* we use an enumerator to handle string->bool and bool->string conversion */ if (PMIX_MCA_BASE_VAR_TYPE_BOOL == var->mbv_type) { ret = var->mbv_enumerator->string_from_value(var->mbv_enumerator, value->boolval, value_string); } else { ret = var->mbv_enumerator->string_from_value(var->mbv_enumerator, value->intval, value_string); } if (PMIX_SUCCESS != ret) { return ret; } } return ret; } int pmix_mca_base_var_check_exclusive(const char *project, const char *type_a, const char *component_a, const char *param_a, const char *type_b, const char *component_b, const char *param_b) { pmix_mca_base_var_t *var_a = NULL, *var_b = NULL; int var_ai, var_bi; /* XXX -- Remove me once the project name is in the componennt */ project = NULL; var_ai = pmix_mca_base_var_find(project, type_a, component_a, param_a); var_bi = pmix_mca_base_var_find(project, type_b, component_b, param_b); if (var_bi < 0 || var_ai < 0) { return PMIX_ERR_NOT_FOUND; } (void) var_get(var_ai, &var_a, true); (void) var_get(var_bi, &var_b, true); if (NULL == var_a || NULL == var_b) { return PMIX_ERR_NOT_FOUND; } if (PMIX_MCA_BASE_VAR_SOURCE_DEFAULT != var_a->mbv_source && PMIX_MCA_BASE_VAR_SOURCE_DEFAULT != var_b->mbv_source) { char *str_a, *str_b; /* Form cosmetic string names for A */ str_a = source_name(var_a); /* Form cosmetic string names for B */ str_b = source_name(var_b); /* Print it all out */ pmix_show_help("help-pmix-mca-var.txt", "mutually-exclusive-vars", true, var_a->mbv_full_name, str_a, var_b->mbv_full_name, str_b); /* Free the temp strings */ free(str_a); free(str_b); return PMIX_ERR_BAD_PARAM; } return PMIX_SUCCESS; } int pmix_mca_base_var_get_count(void) { return pmix_mca_base_var_count; } int pmix_mca_base_var_dump(int vari, char ***out, pmix_mca_base_var_dump_type_t output_type) { const char *framework, *component, *full_name; int i, line_count, line = 0, enum_count = 0; char *value_string, *source_string, *tmp; int synonym_count, ret, *synonyms = NULL; pmix_mca_base_var_t *var, *original = NULL; pmix_mca_base_var_group_t *group; ret = var_get(vari, &var, false); if (PMIX_SUCCESS != ret) { return ret; } ret = pmix_mca_base_var_group_get_internal(var->mbv_group_index, &group, false); if (PMIX_SUCCESS != ret) { return ret; } if (PMIX_VAR_IS_SYNONYM(var[0])) { ret = var_get(var->mbv_synonym_for, &original, false); if (PMIX_SUCCESS != ret) { return ret; } /* just for protection... */ if (NULL == original) { return PMIX_ERR_NOT_FOUND; } } framework = group->group_framework; component = group->group_component ? group->group_component : "base"; full_name = var->mbv_full_name; synonym_count = pmix_value_array_get_size(&var->mbv_synonyms); if (synonym_count) { synonyms = PMIX_VALUE_ARRAY_GET_BASE(&var->mbv_synonyms, int); } ret = var_value_string(var, &value_string); if (PMIX_SUCCESS != ret) { return ret; } source_string = source_name(var); if (NULL == source_string) { free(value_string); return PMIX_ERR_OUT_OF_RESOURCE; } if (PMIX_MCA_BASE_VAR_DUMP_PARSABLE == output_type) { if (NULL != var->mbv_enumerator) { (void) var->mbv_enumerator->get_count(var->mbv_enumerator, &enum_count); } line_count = 8 + (var->mbv_description ? 1 : 0) + (PMIX_VAR_IS_SYNONYM(var[0]) ? 1 : synonym_count) + enum_count; *out = (char **) calloc(line_count + 1, sizeof(char *)); if (NULL == *out) { free(value_string); free(source_string); return PMIX_ERR_OUT_OF_RESOURCE; } /* build the message*/ pmix_asprintf(&tmp, "mca:%s:%s:param:%s:", framework, component, full_name); /* Output the value */ char *colon = strchr(value_string, ':'); if (NULL != colon) { pmix_asprintf(out[0] + line++, "%svalue:\"%s\"", tmp, value_string); } else { pmix_asprintf(out[0] + line++, "%svalue:%s", tmp, value_string); } /* Output the source */ pmix_asprintf(out[0] + line++, "%ssource:%s", tmp, source_string); /* Output whether it's read only or writable */ pmix_asprintf(out[0] + line++, "%sstatus:%s", tmp, PMIX_VAR_IS_SETTABLE(var[0]) ? "writeable" : "read-only"); /* If it has a help message, output the help message */ if (var->mbv_description) { pmix_asprintf(out[0] + line++, "%shelp:%s", tmp, var->mbv_description); } if (NULL != var->mbv_enumerator) { for (i = 0; i < enum_count; ++i) { const char *enum_string = NULL; int enum_value; ret = var->mbv_enumerator->get_value(var->mbv_enumerator, i, &enum_value, &enum_string); if (PMIX_SUCCESS != ret) { continue; } pmix_asprintf(out[0] + line++, "%senumerator:value:%d:%s", tmp, enum_value, enum_string); } } /* Is this variable deprecated? */ pmix_asprintf(out[0] + line++, "%sdeprecated:%s", tmp, PMIX_VAR_IS_DEPRECATED(var[0]) ? "yes" : "no"); pmix_asprintf(out[0] + line++, "%stype:%s", tmp, pmix_var_type_names[var->mbv_type]); /* Does this parameter have any synonyms or is it a synonym? */ if (PMIX_VAR_IS_SYNONYM(var[0])) { pmix_asprintf(out[0] + line++, "%ssynonym_of:name:%s", tmp, original->mbv_full_name); } else if (pmix_value_array_get_size(&var->mbv_synonyms)) { for (i = 0; i < synonym_count; ++i) { pmix_mca_base_var_t *synonym; ret = var_get(synonyms[i], &synonym, false); if (PMIX_SUCCESS != ret) { continue; } pmix_asprintf(out[0] + line++, "%ssynonym:name:%s", tmp, synonym->mbv_full_name); } } free(tmp); } else if (PMIX_MCA_BASE_VAR_DUMP_READABLE == output_type || PMIX_MCA_BASE_VAR_DUMP_READABLE_COLOR == output_type) { char *color_name = "", *color_value = "", *color_reset = ""; /* There will be at most three lines in the pretty print case */ *out = (char **) calloc(4, sizeof(char *)); if (NULL == *out) { free(value_string); free(source_string); return PMIX_ERR_OUT_OF_RESOURCE; } if (PMIX_MCA_BASE_VAR_DUMP_READABLE_COLOR == output_type) { color_name = pmix_var_dump_color[PMIX_VAR_DUMP_COLOR_VAR_NAME]; color_value = pmix_var_dump_color[PMIX_VAR_DUMP_COLOR_VAR_VALUE]; color_reset = "\033[0m"; } pmix_asprintf(out[0], "%s %s\"%s\"%s (current value: %s\"%s\"%s, data source: %s, type: %s", PMIX_VAR_IS_DEFAULT_ONLY(var[0]) ? "informational" : "parameter", color_name, full_name, color_reset, color_value, value_string, color_reset, source_string, pmix_var_type_names[var->mbv_type]); tmp = out[0][0]; if (PMIX_VAR_IS_DEPRECATED(var[0])) { pmix_asprintf(out[0], "%s, deprecated", tmp); free(tmp); tmp = out[0][0]; } /* Does this parameter have any synonyms or is it a synonym? */ if (PMIX_VAR_IS_SYNONYM(var[0])) { pmix_asprintf(out[0], "%s, synonym of: %s)", tmp, original->mbv_full_name); free(tmp); } else if (synonym_count) { pmix_asprintf(out[0], "%s, synonyms: ", tmp); free(tmp); for (i = 0; i < synonym_count; ++i) { pmix_mca_base_var_t *synonym; ret = var_get(synonyms[i], &synonym, false); if (PMIX_SUCCESS != ret) { continue; } tmp = out[0][0]; if (synonym_count == i + 1) { pmix_asprintf(out[0], "%s%s)", tmp, synonym->mbv_full_name); } else { pmix_asprintf(out[0], "%s%s, ", tmp, synonym->mbv_full_name); } free(tmp); } } else { pmix_asprintf(out[0], "%s)", tmp); free(tmp); } line++; if (var->mbv_description) { pmix_asprintf(out[0] + line++, "%s", var->mbv_description); } if (NULL != var->mbv_enumerator) { char *values; ret = var->mbv_enumerator->dump(var->mbv_enumerator, &values, PMIX_MCA_BASE_VAR_DUMP_TYPE_TO_ENUM_DUMP_TYPE(output_type)); if (PMIX_SUCCESS == ret) { pmix_asprintf(out[0] + line++, "Valid values: %s", values); free(values); } } } else if (PMIX_MCA_BASE_VAR_DUMP_SIMPLE == output_type) { *out = (char **) calloc(2, sizeof(char *)); if (NULL == *out) { free(value_string); free(source_string); return PMIX_ERR_OUT_OF_RESOURCE; } pmix_asprintf(out[0], "%s=%s (%s)", var->mbv_full_name, value_string, source_string); } free(value_string); free(source_string); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_vari.h0000664000175000017500000001174715203536752021731 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * This is the private declarations for the MCA variable system. * This file is internal to the MCA variable system and should not * need to be used by any other elements in PMIX except the * special case of the ompi_info command. * * All the rest of the doxygen documentation in this file is marked as * "internal" and won't show up unless you specifically tell doxygen * to generate internal documentation (by default, it is skipped). */ #ifndef PMIX_MCA_BASE_VAR_INTERNAL_H #define PMIX_MCA_BASE_VAR_INTERNAL_H #include "src/include/pmix_config.h" #include "src/class/pmix_hash_table.h" #include "src/class/pmix_list.h" #include "src/class/pmix_object.h" #include "src/class/pmix_pointer_array.h" #include "src/class/pmix_value_array.h" #include "src/mca/base/pmix_mca_base_var.h" BEGIN_C_DECLS /* Internal flags start at bit 16 */ #define PMIX_MCA_BASE_VAR_FLAG_EXTERNAL_MASK 0x0000ffff #define PMIX_VAR_FLAG_ISSET(var, flag) (!!((var).mbp_flags & (flag))) #define PMIX_VAR_IS_VALID(var) (!!((var).mbv_flags & PMIX_MCA_BASE_VAR_FLAG_VALID)) #define PMIX_VAR_IS_SYNONYM(var) (!!((var).mbv_flags & PMIX_MCA_BASE_VAR_FLAG_SYNONYM)) #define PMIX_VAR_IS_INTERNAL(var) (!!((var).mbv_flags & PMIX_MCA_BASE_VAR_FLAG_INTERNAL)) #define PMIX_VAR_IS_DEFAULT_ONLY(var) (!!((var).mbv_flags & PMIX_MCA_BASE_VAR_FLAG_DEFAULT_ONLY)) #define PMIX_VAR_IS_SETTABLE(var) (!!((var).mbv_flags & PMIX_MCA_BASE_VAR_FLAG_SETTABLE)) #define PMIX_VAR_IS_DEPRECATED(var) (!!((var).mbv_flags & PMIX_MCA_BASE_VAR_FLAG_DEPRECATED)) PMIX_EXPORT extern const char *pmix_var_type_names[]; PMIX_EXPORT extern const size_t pmix_var_type_sizes[]; PMIX_EXPORT extern bool pmix_mca_base_var_initialized; PMIX_EXPORT extern pmix_list_t pmix_mca_base_var_file_values; PMIX_EXPORT extern pmix_list_t pmix_mca_base_var_override_values; /** * \internal * * Structure for holding param names and values read in from files. */ struct pmix_mca_base_var_file_value_t { /** Allow this to be an PMIX OBJ */ pmix_list_item_t super; /** Parameter name */ char *mbvfv_var; /** Parameter value */ char *mbvfv_value; /** File it came from */ char *mbvfv_file; /** Line it came from */ int mbvfv_lineno; }; /** * \internal * * Convenience typedef */ typedef struct pmix_mca_base_var_file_value_t pmix_mca_base_var_file_value_t; /** * Object declaration for pmix_mca_base_var_file_value_t */ PMIX_CLASS_DECLARATION(pmix_mca_base_var_file_value_t); /** * \internal * * Get a group * * @param[in] group_index Group index * @param[out] group Returned group if it exists * @param[in] invalidok Return group even if it has been deregistered */ PMIX_EXPORT int pmix_mca_base_var_group_get_internal(const int group_index, pmix_mca_base_var_group_t **group, bool invalidok); /** * \internal * * Parse a parameter file. */ PMIX_EXPORT int pmix_mca_base_parse_paramfile(const char *paramfile, pmix_list_t *list); /** * \internal * * Add a variable to a group */ PMIX_EXPORT int pmix_mca_base_var_group_add_var(const int group_index, const int param_index); /** * \internal * * Generate a full name with _ between all of the non-NULL arguments */ PMIX_EXPORT int pmix_mca_base_var_generate_full_name4(const char *project, const char *framework, const char *component, const char *variable, char **full_name); /** * \internal * * Call save_value callback for generated internal mca parameter storing env variables */ PMIX_EXPORT int pmix_mca_base_internal_env_store(void); /** * \internal * * Initialize/finalize MCA variable groups */ PMIX_EXPORT int pmix_mca_base_var_group_init(void); PMIX_EXPORT int pmix_mca_base_var_group_finalize(void); END_C_DECLS #endif /* PMIX_MCA_BASE_VAR_INTERNAL_H */ pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_var.h0000664000175000017500000006103415203536752021552 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file * This file presents the MCA variable interface. * * Note that there are two scopes for MCA variables: "normal" and * attributes. Specifically, all MCA variables are "normal" -- some * are special and may also be found on attributes on communicators, * datatypes, or windows. * * In general, these functions are intended to be used as follows: * * - Creating MCA variables * -# Register a variable, get an index back * - Using MCA variables * -# Lookup a "normal" variable value on a specific index, or * -# Lookup an attribute variable on a specific index and * communicator / datatype / window. * * MCA variables can be defined in multiple different places. As * such, variables are \em resolved to find their value. The order * of resolution is as follows: * * - An "override" location that is only available to be set via the * pmix_mca_base_param API. * - Look for an environment variable corresponding to the MCA * variable. * - See if a file contains the MCA variable (MCA variable files are * read only once -- when the first time any mca_param_t function is * invoked). * - If nothing else was found, use the variable's default value. * * Note that there is a second header file (pmix_mca_base_vari.h) * that contains several internal type declarations for the variable * system. The internal file is only used within the variable system * itself; it should not be required by any other PMIX entities. */ #ifndef PMIX_MCA_BASE_VAR_H #define PMIX_MCA_BASE_VAR_H #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/class/pmix_value_array.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var_enum.h" #include "src/mca/base/pmix_mca_base_var_group.h" #include "src/mca/mca.h" /** * The types of MCA variables. */ typedef enum { /** The variable is of type int. */ PMIX_MCA_BASE_VAR_TYPE_INT, /** The variable is of type unsigned int */ PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_INT, /** The variable is of type unsigned long */ PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_LONG, /** The variable is of type unsigned long long */ PMIX_MCA_BASE_VAR_TYPE_UNSIGNED_LONG_LONG, /** The variable is of type size_t */ PMIX_MCA_BASE_VAR_TYPE_SIZE_T, /** The variable is of type string. */ PMIX_MCA_BASE_VAR_TYPE_STRING, /** The variable is of type string and contains version. */ PMIX_MCA_BASE_VAR_TYPE_VERSION_STRING, /** The variable is of type bool */ PMIX_MCA_BASE_VAR_TYPE_BOOL, /** The variable is of type double */ PMIX_MCA_BASE_VAR_TYPE_DOUBLE, /** Maximum variable type. */ PMIX_MCA_BASE_VAR_TYPE_MAX } pmix_mca_base_var_type_t; PMIX_EXPORT extern const char *pmix_var_type_names[]; /** * Source of an MCA variable's value */ typedef enum { /** The default value */ PMIX_MCA_BASE_VAR_SOURCE_DEFAULT, /** The value came from the command line */ PMIX_MCA_BASE_VAR_SOURCE_COMMAND_LINE, /** The value came from the environment */ PMIX_MCA_BASE_VAR_SOURCE_ENV, /** The value came from a file */ PMIX_MCA_BASE_VAR_SOURCE_FILE, /** The value came a "set" API call */ PMIX_MCA_BASE_VAR_SOURCE_SET, /** The value came from the override file */ PMIX_MCA_BASE_VAR_SOURCE_OVERRIDE, /** Maximum source type */ PMIX_MCA_BASE_VAR_SOURCE_MAX } pmix_mca_base_var_source_t; typedef enum { PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED = 0x0001 } pmix_mca_base_var_syn_flag_t; typedef enum { /** Variable is internal (hidden from *_info) */ PMIX_MCA_BASE_VAR_FLAG_INTERNAL = 0x0001, /** Variable will always be the default value. Implies !PMIX_MCA_BASE_VAR_FLAG_SETTABLE */ PMIX_MCA_BASE_VAR_FLAG_DEFAULT_ONLY = 0x0002, /** Variable can be set with mca_base_var_set() */ PMIX_MCA_BASE_VAR_FLAG_SETTABLE = 0x0004, /** Variable is deprecated */ PMIX_MCA_BASE_VAR_FLAG_DEPRECATED = 0x0008, /** Variable has been overridden */ PMIX_MCA_BASE_VAR_FLAG_OVERRIDE = 0x0010, /** Variable may not be set from a file */ PMIX_MCA_BASE_VAR_FLAG_ENVIRONMENT_ONLY = 0x0020, /** Variable should be deregistered when the group is deregistered (DWG = "deregister with group"). This flag is set automatically when you register a variable with mca_base_component_var_register(), but can also be set manually when you register a variable with mca_base_var_register(). Analogous to the MCA_BASE_PVAR_FLAG_IWG. */ PMIX_MCA_BASE_VAR_FLAG_DWG = 0x0040, /** Variable has a default value of "unset". Meaning to only * be set when the user explicitly asks for it */ PMIX_MCA_BASE_VAR_FLAG_DEF_UNSET = 0x0080, } pmix_mca_base_var_flag_t; typedef enum { PMIX_MCA_BASE_VAR_FLAG_NONE = 0x0000, /** Variable is valid */ PMIX_MCA_BASE_VAR_FLAG_VALID = 0x00010000, /** Variable is a synonym */ PMIX_MCA_BASE_VAR_FLAG_SYNONYM = 0x00020000, /** mbv_source_file needs to be freed */ PMIX_MCA_BASE_VAR_FLAG_SOURCE_FILE_NEEDS_FREE = 0x00040000 } pmix_mca_base_var_flag_internal_t; /** * Types for MCA parameters. */ typedef union { /** integer value */ int intval; /** unsigned int value */ unsigned int uintval; /** string value */ char *stringval; /** boolean value */ bool boolval; /** unsigned long value */ unsigned long ulval; /** unsigned long long value */ unsigned long long ullval; /** size_t value */ size_t sizetval; /** double value */ double lfval; } pmix_mca_base_var_storage_t; /** * Entry for holding information about an MCA variable. */ struct pmix_mca_base_var_t { /** Allow this to be an PMIX OBJ */ pmix_object_t super; /** Variable index. This will remain constant until pmix_mca_base_var_finalize() is called. */ int mbv_index; /** Group index. This will remain constant until pmix_mca_base_var_finalize() is called. This variable will be deregistered if the associated group is deregistered with pmix_mca_base_var_group_deregister() */ int mbv_group_index; /** Enum indicating the type of the variable (integer, string, boolean) */ pmix_mca_base_var_type_t mbv_type; /** String of the variable name */ char *mbv_variable_name; /** Full variable name, in case it is not __ */ char *mbv_full_name; /** Long variable name ___ */ char *mbv_long_name; char *mbv_prefix; /** List of synonym names for this variable. This *must* be a pointer (vs. a plain pmix_list_t) because we copy this whole struct into a new var for permanent storage (pmix_vale_array_append_item()), and the internal pointers in the pmix_list_t will be invalid when that happens. Hence, we simply keep a pointer to an external pmix_list_t. Synonyms are uncommon enough that this is not a big performance hit. */ pmix_value_array_t mbv_synonyms; /** Variable flags */ pmix_mca_base_var_flag_internal_t mbv_flags; /** Source of the current value */ pmix_mca_base_var_source_t mbv_source; /** Synonym for */ int mbv_synonym_for; /** Variable description */ char *mbv_description; /** File the value came from */ char *mbv_source_file; /** Value enumerator (only valid for integer variables) */ pmix_mca_base_var_enum_t *mbv_enumerator; /** Bind value for this variable (0 - none) */ int mbv_bind; /** Storage for this variable */ pmix_mca_base_var_storage_t *mbv_storage; /** File value structure */ void *mbv_file_value; }; /** * Convenience typedef. */ typedef struct pmix_mca_base_var_t pmix_mca_base_var_t; /* * Global functions for MCA */ BEGIN_C_DECLS /** * Object declarayion for pmix_mca_base_var_t */ PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_mca_base_var_t); /** * Initialize the MCA variable system. * * @retval PMIX_SUCCESS * * This function initializes the MCA variable system. It is * invoked internally (by pmix_mca_base_open()) and is only documented * here for completeness. */ PMIX_EXPORT int pmix_mca_base_var_init(void); /** * Register an MCA variable * * @param[in] project_name The name of the project associated with * this variable * @param[in] framework_name The name of the framework associated with * this variable * @param[in] component_name The name of the component associated with * this variable * @param[in] variable_name The name of this variable * @param[in] description A string describing the use and valid * values of the variable (string). * @param[in] type The type of this variable (string, int, bool). * @param[in] enumerator Enumerator describing valid values. * @param[in] bind Hint for MPIT to specify type of binding (0 = none) * @param[in] flags Flags for this variable. * @param[in] info_lvl Info level of this variable * @param[in] scope Indicates the scope of this variable * @param[in,out] storage Pointer to the value's location. * * @retval index Index value representing this variable. * @retval PMIX_ERR_OUT_OF_RESOURCE Upon failure to allocate memory. * @retval PMIX_ERROR Upon failure to register the variable. * * This function registers an MCA variable and associates it * with a specific group. * * {description} is a string of arbitrary length (verbose is good!) * for explaining what the variable is for and what its valid values * are. This message is used in help messages, such as the output * from the ompi_info executable. The {description} string is copied * internally; the caller can free {description} upon successful * return. * * {enumerator} is either NULL or a handle that was created via * pmix_mca_base_var_enum_create(), and describes the valid values of an * integer variable (i.e., one with type MCA_BASE_VAR_TYPE_INT). When * a non-NULL {enumerator} is used, the value set for this variable by * the user will be compared against the values in the enumerator. * The MCA variable system will allow the parameter to be set to * either one of the enumerator values (0, 1, 2, etc) or a string * representing one of those values. {enumerator} is retained until * either the variable is deregistered using * pmix_mca_base_var_deregister(), pmix_mca_base_var_group_deregister(), or * pmix_mca_base_var_finalize(). {enumerator} should be NULL for * parameters that do not support enumerated values. * * {flags} indicate attributes of this variable (internal, settable, * default only, etc.), as listed below. * * If MCA_BASE_VAR_FLAG_INTERNAL is set in {flags}, this variable * is not shown by default in the output of ompi_info. That is, * this variable is considered internal to the PMIX implementation * and is not supposed to be viewed / changed by the user. * * If MCA_BASE_VAR_FLAG_DEFAULT_ONLY is set in {flags}, then the value * provided in storage will not be modified by the MCA variable system * (i.e., users cannot set the value of this variable via CLI * parameter, environment variable, file, etc.). It is up to the * caller to specify (using the scope) if this value may change * (MCA_BASE_VAR_SCOPE_READONLY) or remain constant * (MCA_BASE_VAR_SCOPE_CONSTANT). MCA_BASE_VAR_FLAG_DEFAULT_ONLY must * not be specified with MCA_BASE_VAR_FLAG_SETTABLE. * * Set MCA_BASE_VAR_FLAG_DEPRECATED in {flags} to indicate that * this variable name is deprecated. The user will get a warning * if they set this variable. * * {scope} is for informational purposes to indicate how this variable * can be set, or if it is considered constant or readonly (which, by * MPI_T's definitions, are different things). See the comments in * the description of pmix_mca_base_var_scope_t for information about the * different scope meanings. * * {storage} points to a (char *), (int), or (bool) where the value of * this variable is stored ({type} indicates the type of this * pointer). The location pointed to by {storage} must exist until * the variable is deregistered. Note that the initial value in * {storage} may be overwritten if the MCA_BASE_VAR_FLAG_DEFAULT_ONLY * flag is not set (e.g., if the user sets this variable via CLI * option, environment variable, or file value). If input value of * {storage} points to a (char *), the pointed-to string will be * duplicated and maintained internally by the MCA variable system; * the caller may free the original string after this function returns * successfully. */ PMIX_EXPORT int pmix_mca_base_var_register(const char *project_name, const char *framework_name, const char *component_name, const char *variable_name, const char *description, pmix_mca_base_var_type_t type, void *storage); /** * Convenience function for registering a variable associated with a * component. * * While quite similar to pmix_mca_base_var_register(), there is one key * difference: vars registered this this function will automatically * be unregistered / made unavailable when that component is closed by * its framework. */ PMIX_EXPORT int pmix_mca_base_component_var_register( const pmix_mca_base_component_t *component, const char *variable_name, const char *description, pmix_mca_base_var_type_t type, void *storage); /** * Convenience function for registering a variable associated with a framework. This * function is equivalent to pmix_mca_base_var_register with component_name = "base" and * with the MCA_BASE_VAR_FLAG_DWG set. See pmix_mca_base_var_register(). */ PMIX_EXPORT int pmix_mca_base_framework_var_register( const pmix_mca_base_framework_t *framework, const char *variable_name, const char *help_msg, pmix_mca_base_var_type_t type, void *storage); /** * Register a synonym name for an MCA variable. * * @param[in] synonym_for The index of the original variable. This index * must not refer to a synonym. * @param[in] project_name The project this synonym belongs to. Should * not be NULL (except for legacy reasons). * @param[in] framework_name The framework this synonym belongs to. * @param[in] component_name The component this synonym belongs to. * @param[in] synonym_name The synonym name. * @param[in] flags Flags for this synonym. * * @returns index Variable index for new synonym on success. * @returns PMIX_ERR_BAD_VAR If synonym_for does not reference a valid * variable. * @returns PMIX_ERR_OUT_OF_RESOURCE If memory could not be allocated. * @returns PMIX_ERROR For all other errors. * * Upon success, this function creates a synonym MCA variable * that will be treated almost exactly like the original. The * type (int or string) is irrelevant; this function simply * creates a new name that by which the same variable value is * accessible. * * Note that the original variable name has precedence over all * synonyms. For example, consider the case if variable is * originally registered under the name "A" and is later * registered with synonyms "B" and "C". If the user sets values * for both MCA variable names "A" and "B", the value associated * with the "A" name will be used and the value associated with * the "B" will be ignored (and will not even be visible by the * pmix_mca_base_var_*() API). If the user sets values for both MCA * variable names "B" and "C" (and does *not* set a value for * "A"), it is undefined as to which value will be used. */ PMIX_EXPORT int pmix_mca_base_var_register_synonym(int synonym_for, const char *project_name, const char *framework_name, const char *component_name, const char *synonym_name, pmix_mca_base_var_syn_flag_t flags); /** * Deregister a MCA variable or synonym * * @param vari Index returned from pmix_mca_base_var_register() or * pmix_mca_base_var_register_synonym(). * * Deregistering a variable does not free the variable or any memory associated * with it. All memory will be freed and the variable index released when * pmix_mca_base_var_finalize() is called. * * If an enumerator is associated with this variable it will be dereferenced. */ PMIX_EXPORT int pmix_mca_base_var_deregister(int vari); /** * Get the current value of an MCA variable. * * @param[in] vari Index of variable * @param[in,out] value Pointer to copy the value to. Can be NULL. * @param[in,out] value_size Size of memory pointed to by value. * copied size will be returned in value_size. * @param[out] source Source of current value. Can be NULL. * @param[out] source_file Source file for the current value if * it was set from a file. * * @return PMIX_ERROR Upon failure. The contents of value are * undefined. * @return PMIX_SUCCESS Upon success. value (if not NULL) will be filled * with the variable's current value. value_size will contain the size * copied. source (if not NULL) will contain the source of the variable. * * Note: The value can be changed by the registering code without using * the pmix_mca_base_var_* interface so the source may be incorrect. */ PMIX_EXPORT int pmix_mca_base_var_get_value(int vari, void *value, pmix_mca_base_var_source_t *source, const char **source_file); /** * Find the index for an MCA variable based on its names. * * @param project_name Name of the project * @param type_name Name of the type containing the variable. * @param component_name Name of the component containing the variable. * @param param_name Name of the variable. * * @retval PMIX_ERROR If the variable was not found. * @retval vari If the variable was found. * * It is not always convenient to widely propagate a variable's index * value, or it may be necessary to look up the variable from a * different component. This function can be used to look up the index * of any registered variable. The returned index can be used with * pmix_mca_base_var_get() and pmix_mca_base_var_get_value(). */ PMIX_EXPORT int pmix_mca_base_var_find(const char *project_name, const char *type_name, const char *component_name, const char *param_name); /** * Find the index for a variable based on its full name * * @param full_name [in] Full name of the variable * @param vari [out] Index of the variable * * See pmix_mca_base_var_find(). */ PMIX_EXPORT int pmix_mca_base_var_find_by_name(const char *full_name, int *vari); /** * Check that two MCA variables were not both set to non-default * values. * * @param type_a [in] Framework name of variable A (string). * @param component_a [in] Component name of variable A (string). * @param param_a [in] Variable name of variable A (string. * @param type_b [in] Framework name of variable A (string). * @param component_b [in] Component name of variable A (string). * @param param_b [in] Variable name of variable A (string. * * This function is useful for checking that the user did not set both * of 2 mutually-exclusive MCA variables. * * This function will print an pmix_show_help() message and return * PMIX_ERR_BAD_VAR if it finds that the two variables both have * value sources that are not MCA_BASE_VAR_SOURCE_DEFAULT. This * means that both variables have been set by the user (i.e., they're * not default values). * * Note that pmix_show_help() allows itself to be hooked, so if this * happens after the aggregated pmix_show_help() system is * initialized, the messages will be aggregated (w00t). * * @returns PMIX_ERR_BAD_VAR if the two variables have sources that * are not MCA_BASE_VAR_SOURCE_DEFAULT. * @returns PMIX_SUCCESS otherwise. */ PMIX_EXPORT int pmix_mca_base_var_check_exclusive(const char *project, const char *type_a, const char *component_a, const char *param_a, const char *type_b, const char *component_b, const char *param_b); /** * Obtain basic info on a single variable (name, help message, etc) * * @param[in] vari Valid variable index. * @param[out] var Storage for the variable pointer. * * @retval PMIX_SUCCESS Upon success. * @retval pmix error code Upon failure. * * The returned pointer belongs to the MCA variable system. Do not * modify/free/retain the pointer. */ PMIX_EXPORT int pmix_mca_base_var_get(int vari, const pmix_mca_base_var_t **var); /** * Obtain the number of variables that have been registered. * * @retval count on success * @return pmix error code on error * * Note: This function does not return the number of valid MCA variables as * pmix_mca_base_var_deregister() has no impact on the variable count. The count * returned is equal to the number of calls to pmix_mca_base_var_register with * unique names. ie. two calls with the same name will not affect the count. */ PMIX_EXPORT int pmix_mca_base_var_get_count(void); /** * Obtain a list of environment variables describing the all * valid (non-default) MCA variables and their sources. * * @param[out] env A pointer to an argv-style array of key=value * strings, suitable for use in an environment * @param[out] num_env A pointer to an int, containing the length * of the env array (not including the final NULL entry). * * @retval PMIX_SUCCESS Upon success. * @retval PMIX_ERROR Upon failure. * * This function is similar to pmix_mca_base_var_dump() except that * its output is in terms of an argv-style array of key=value * strings, suitable for using in an environment. */ PMIX_EXPORT int pmix_mca_base_var_build_env(char ***env, int *num_env); /** * Shut down the MCA variable system (normally only invoked by the * MCA framework itself). * * @returns PMIX_SUCCESS This function never fails. * * This function shuts down the MCA variable repository and frees all * associated memory. No other pmix_mca_base_var*() functions can be * invoked after this function. * * This function is normally only invoked by the MCA framework itself * when the process is shutting down (e.g., during MPI_FINALIZE). It * is only documented here for completeness. */ PMIX_EXPORT int pmix_mca_base_var_finalize(void); typedef enum { /* Dump human-readable strings */ PMIX_MCA_BASE_VAR_DUMP_READABLE = 0, /* Dump easily parsable strings */ PMIX_MCA_BASE_VAR_DUMP_PARSABLE = 1, /* Dump simple name=value string */ PMIX_MCA_BASE_VAR_DUMP_SIMPLE = 2, /* Dump in color */ PMIX_MCA_BASE_VAR_DUMP_READABLE_COLOR = 3 } pmix_mca_base_var_dump_type_t; /* Supported color configuration keys * for dumping MCA variables with colors */ typedef enum { PMIX_VAR_DUMP_COLOR_VAR_NAME = 0, PMIX_VAR_DUMP_COLOR_VAR_VALUE = 1, PMIX_VAR_DUMP_COLOR_VALID_VALUES = 2, PMIX_VAR_DUMP_COLOR_KEY_COUNT } pmix_var_dump_color_key_t; extern char *pmix_var_dump_color[PMIX_VAR_DUMP_COLOR_KEY_COUNT]; /** * Dump strings describing the MCA variable at an index. * * @param[in] vari Variable index * @param[out] out Array of strings describing this variable * @param[in] output_type Type of output desired * * This function returns an array of strings describing the variable. All strings * and the array must be freed by the caller. */ PMIX_EXPORT int pmix_mca_base_var_dump(int vari, char ***out, pmix_mca_base_var_dump_type_t output_type); #define MCA_COMPILETIME_VER "print_compiletime_version" #define MCA_RUNTIME_VER "print_runtime_version" PMIX_EXPORT int pmix_mca_base_var_cache_files(bool rel_path_search); END_C_DECLS #endif /* PMIX_MCA_BASE_VAR_H */ pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_component_repository.h0000664000175000017500000001307415203536752025264 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file pmix_mca_base_component_repository.h * * This file provide the external interface to our base component * module. Most of the components that depend on it, will use the * retain_component() function to increase the reference count on a * particular component (as opposed to the retain() function, which is * internal to the pmix/mca/base). But it's convenient to have all * the functions exported from one header file rather than to separate * retain_component() and retain() into two separate header files * (i.e., have a separate header file just for retain()). */ #ifndef PMIX_MCA_BASE_COMPONENT_REPOSITORY_H #define PMIX_MCA_BASE_COMPONENT_REPOSITORY_H #include "src/include/pmix_config.h" #include "src/mca/pdl/base/base.h" #include "src/mca/pdl/pdl.h" BEGIN_C_DECLS struct pmix_mca_base_component_repository_item_t { pmix_list_item_t super; char *ri_project; char ri_type[PMIX_MCA_BASE_MAX_TYPE_NAME_LEN + 1]; char ri_name[PMIX_MCA_BASE_MAX_COMPONENT_NAME_LEN + 1]; char *ri_path; char *ri_base; pmix_pdl_handle_t *ri_dlhandle; const pmix_mca_base_component_t *ri_component_struct; int ri_refcnt; }; typedef struct pmix_mca_base_component_repository_item_t pmix_mca_base_component_repository_item_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_mca_base_component_repository_item_t); /* * Structure to track information about why a component failed to load. */ struct pmix_mca_base_failed_component_t { pmix_list_item_t super; pmix_mca_base_component_repository_item_t *comp; char *error_msg; }; typedef struct pmix_mca_base_failed_component_t pmix_mca_base_failed_component_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_mca_base_failed_component_t); /** * @brief initialize the component repository * * This function must be called before any frameworks are registered or * opened. It is responsible for setting up the repository of dynamically * loaded components. The initial search path is taken from the * pmix_mca_base_component_path MCA parameter. pmix_mca_base_open () is a * prerequisite call as it registers the pmix_mca_base_component_path parameter. */ PMIX_EXPORT int pmix_mca_base_component_repository_init(void); /** * @brief add search path for dynamically loaded components * * @param[in] path delimited list of search paths to add */ PMIX_EXPORT int pmix_mca_base_component_repository_add(const char *project, const char *path); /** * @brief return the list of components that match a given framework * * @param[in] framework framework to match * @param[out] framework_components components that match this framework * * The list returned in {framework_components} is owned by the component * repository and CAN NOT be modified by the caller. */ PMIX_EXPORT int pmix_mca_base_component_repository_get_components(pmix_mca_base_framework_t *framework, pmix_list_t **framework_components); /** * @brief finalize the mca component repository */ PMIX_EXPORT void pmix_mca_base_component_repository_finalize(void); /** * @brief open the repository item and add it to the framework's component * list * * @param[in] framework framework that matches the component * @param[in] ri dynamic component to open */ PMIX_EXPORT int pmix_mca_base_component_repository_open(pmix_mca_base_framework_t *framework, pmix_mca_base_component_repository_item_t *ri); /** * @brief Reduce the reference count of a component and dlclose it if necessary */ PMIX_EXPORT void pmix_mca_base_component_repository_release(const pmix_mca_base_component_t *component); /** * @brief Increase the reference count of a component * * Each component repository item starts with a reference count of 0. This ensures that * when a framework closes it's components the repository items are all correctly * dlclosed. This function can be used to prevent the dlclose if a component is needed * after its framework has closed the associated component. Users of this function * should call pmix_mca_base_component_repository_release() once they are finished with the * component. * * @note all components are automatically unloaded by the * pmix_mca_base_component_repository_finalize() call. */ PMIX_EXPORT int pmix_mca_base_component_repository_retain_component(const char *type, const char *name); END_C_DECLS #endif /* MCA_BASE_COMPONENT_REPOSITORY_H */ pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_alias.h0000664000175000017500000000560115203536752022051 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2020 Google, LLC. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_MCA_BASE_ALIAS_H #define PMIX_MCA_BASE_ALIAS_H #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" BEGIN_C_DECLS enum pmix_mca_base_alias_flags_t { PMIX_MCA_BASE_ALIAS_FLAG_NONE = 0, /** The aliased name has been deprecated. */ PMIX_MCA_BASE_ALIAS_FLAG_DEPRECATED = 1, }; typedef enum pmix_mca_base_alias_flags_t pmix_mca_base_alias_flags_t; struct pmix_mca_base_alias_item_t { pmix_list_item_t super; /** Name aias. */ char *component_alias; /** Alias flags. */ uint32_t alias_flags; }; typedef struct pmix_mca_base_alias_item_t pmix_mca_base_alias_item_t; PMIX_CLASS_DECLARATION(pmix_mca_base_alias_item_t); struct pmix_mca_base_alias_t { pmix_object_t super; /** List of name aliases. */ pmix_list_t component_aliases; }; typedef struct pmix_mca_base_alias_t pmix_mca_base_alias_t; PMIX_CLASS_DECLARATION(pmix_mca_base_alias_t); /** * @brief Create a alias for a component name. * * @param[in] project Project name (may be NULL) * @param[in] framework Framework name (may be NULL) * @param[in] component_name Name of component to alias (may not be NULL) * @param[in] component_alias Aliased name (may not be NULL) * @param[in] alias_flags Flags (see mca_base_alias_flags_t) * * This function aliases one component name to another. When aliased * any variable registered with this project, framework, and * component_name will have synonyms created. For example, if * pmix_btl_vader is aliased to sm then registers a variable * named btl_vader_flags then a synonym will be created with the * name btl_sm_flags. If an alias is registered early enough * (during framework registration for example) then the alias can * also be used for component selection. In the previous example * --mca btl vader and --mca btl sm would select the same * component if the synonym is registered in the btl framework * registration function. */ PMIX_EXPORT int pmix_mca_base_alias_register(const char *project, const char *framework, const char *component_name, const char *component_alias, uint32_t alias_flags); /** * @brief Check for aliases for a component. * * @param[in] project Project name (may be NULL) * @param[in] frameworek Framework name (may be NULL) * @param[in] component_name Component name (may not be NULL) */ PMIX_EXPORT const pmix_mca_base_alias_t * pmix_mca_base_alias_lookup(const char *project, const char *framework, const char *component_name); PMIX_EXPORT void pmix_mca_base_alias_cleanup(void); #endif /* PMIX_MCA_BASE_ALIAS_H */ pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_component_repository.c0000664000175000017500000005405715203536752025265 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2022 Cisco Systems, Inc. All rights reserved * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TYPES_H # include #endif #include #include #include #ifdef HAVE_UNISTD_H # include #endif #include "pmix_common.h" #include "src/class/pmix_hash_table.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_component_repository.h" #include "src/mca/mca.h" #include "src/mca/pdl/base/base.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_show_help.h" #if PMIX_HAVE_PDL_SUPPORT /* * Private types */ static void ri_constructor(pmix_mca_base_component_repository_item_t *ri); static void ri_destructor(pmix_mca_base_component_repository_item_t *ri); PMIX_CLASS_INSTANCE(pmix_mca_base_component_repository_item_t, pmix_list_item_t, ri_constructor, ri_destructor); #endif /* PMIX_HAVE_PDL_SUPPORT */ static void clf_constructor(pmix_object_t *obj) { pmix_mca_base_failed_component_t *cli = (pmix_mca_base_failed_component_t *) obj; cli->comp = NULL; cli->error_msg = NULL; } static void clf_destructor(pmix_object_t *obj) { pmix_mca_base_failed_component_t *cli = (pmix_mca_base_failed_component_t *) obj; cli->comp = NULL; if (NULL != cli->error_msg) { free(cli->error_msg); cli->error_msg = NULL; } } PMIX_CLASS_INSTANCE(pmix_mca_base_failed_component_t, pmix_list_item_t, clf_constructor, clf_destructor); /* * Private variables */ static bool initialized = false; #if PMIX_HAVE_PDL_SUPPORT static pmix_hash_table_t pmix_mca_base_component_repository; /* two-level macro for stringifying a number */ # define STRINGIFYX(x) # x # define STRINGIFY(x) STRINGIFYX(x) static int process_repository_item(const char *filename, void *data) { char *project = (char*)data; char *name; char *type; pmix_mca_base_component_repository_item_t *ri; pmix_list_t *component_list; char *base, *prefix; int ret; size_t prefixlen; base = pmix_basename(filename); if (NULL == base) { return PMIX_ERROR; } /* check if the plugin has the appropriate prefix */ pmix_asprintf(&prefix, "%s_mca_", project); pmix_asprintf(&type, "lib%s_mca_", project); if (0 != strncmp(base, prefix, strlen(prefix)) && 0 != strncmp(base, type, strlen(type))) { if (pmix_mca_base_show_load_errors(NULL, NULL)) { pmix_output_verbose( PMIX_MCA_BASE_VERBOSE_INFO, 0, "mca:base:process_repository_item filename %s has unexpected prefix - expected:\n\t%s\nor\n\t%s", filename, prefix, type); } free(base); free(prefix); free(type); return PMIX_SUCCESS; } free(type); /* read framework and component names. framework names may not include an _ * but component names may */ prefixlen = strlen(prefix); type = &base[prefixlen]; name = strchr(type, '_'); if (NULL == name) { free(base); free(prefix); return PMIX_ERR_BAD_PARAM; } *name = '\0'; ++name; free(prefix); /* lookup the associated framework list and create if it doesn't already exist */ ret = pmix_hash_table_get_value_ptr(&pmix_mca_base_component_repository, type, strlen(type), (void **) &component_list); if (PMIX_SUCCESS != ret) { component_list = PMIX_NEW(pmix_list_t); if (NULL == component_list) { free(base); /* OOM. nothing to do but fail */ return PMIX_ERR_OUT_OF_RESOURCE; } ret = pmix_hash_table_set_value_ptr(&pmix_mca_base_component_repository, type, strlen(type), (void *) component_list); if (PMIX_SUCCESS != ret) { free(base); PMIX_RELEASE(component_list); return ret; } } /* check for duplicate components */ PMIX_LIST_FOREACH (ri, component_list, pmix_mca_base_component_repository_item_t) { if (0 == strcmp(ri->ri_name, name)) { /* already scanned this component */ free(base); return PMIX_SUCCESS; } } ri = PMIX_NEW(pmix_mca_base_component_repository_item_t); if (NULL == ri) { free(base); free(project); return PMIX_ERR_OUT_OF_RESOURCE; } ri->ri_base = base; ri->ri_project = strdup(project); ri->ri_path = strdup(filename); if (NULL == ri->ri_path) { PMIX_RELEASE(ri); return PMIX_ERR_OUT_OF_RESOURCE; } /* pmix_strncpy does not guarantee a \0 */ ri->ri_type[PMIX_MCA_BASE_MAX_TYPE_NAME_LEN] = '\0'; pmix_strncpy(ri->ri_type, type, PMIX_MCA_BASE_MAX_TYPE_NAME_LEN); ri->ri_name[PMIX_MCA_BASE_MAX_TYPE_NAME_LEN] = '\0'; pmix_strncpy(ri->ri_name, name, PMIX_MCA_BASE_MAX_COMPONENT_NAME_LEN); pmix_list_append(component_list, &ri->super); return PMIX_SUCCESS; } static int file_exists(const char *filename, const char *ext) { char *final; int ret; if (NULL == ext) { return access(filename, F_OK) == 0; } ret = asprintf(&final, "%s.%s", filename, ext); if (0 > ret || NULL == final) { return 0; } ret = access(final, F_OK); free(final); return (0 == ret); } #endif /* PMIX_HAVE_PDL_SUPPORT */ int pmix_mca_base_component_repository_add(const char *project, const char *path) { #if PMIX_HAVE_PDL_SUPPORT char *path_to_use = NULL, *dir, *ctx; const char sep[] = {PMIX_ENV_SEP, '\0'}; if (NULL == path) { /* nothing to do */ return PMIX_SUCCESS; } path_to_use = strdup(path); dir = strtok_r(path_to_use, sep, &ctx); do { if (0 != pmix_pdl_foreachfile(dir, process_repository_item, (void*)project) && !(0 == strcmp(dir, pmix_mca_base_system_default_path) || 0 == strcmp(dir, pmix_mca_base_user_default_path))) { // It is not an error if a directory fails to add (e.g., // if it doesn't exist). But we should warn about it as // it is something related to "show_load_errors" pmix_show_help("help-pmix-mca-base.txt", "failed to add component dir", true, dir); } } while (NULL != (dir = strtok_r(NULL, sep, &ctx))); free(path_to_use); #else PMIX_HIDE_UNUSED_PARAMS(project, path); #endif /* PMIX_HAVE_PDL_SUPPORT */ return PMIX_SUCCESS; } /* * Initialize the repository */ int pmix_mca_base_component_repository_init(void) { /* Setup internal structures */ #if PMIX_HAVE_PDL_SUPPORT char **projects = NULL, *pathstr; char project[PMIX_MCA_BASE_MAX_TYPE_NAME_LEN + 1]; int m, n; int ret; if (!initialized) { /* Initialize the dl framework */ ret = pmix_mca_base_framework_open(&pmix_pdl_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != ret) { pmix_output(0, "%s %d:%s failed -- process will likely abort (open the dl framework " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, __func__, ret); return ret; } pmix_pdl_base_select(); PMIX_CONSTRUCT(&pmix_mca_base_component_repository, pmix_hash_table_t); ret = pmix_hash_table_init(&pmix_mca_base_component_repository, 128); if (PMIX_SUCCESS != ret) { (void) pmix_mca_base_framework_close(&pmix_pdl_base_framework); return ret; } initialized = true; } /* split on semi-colons to find projects */ projects = PMIx_Argv_split(pmix_mca_base_component_path, ';'); for (n=0; NULL != projects[n]; n++) { /* look for the '@' to delimit the project name */ for (m=0; '@' != projects[n][m]; m++) { project[m] = projects[n][m]; } project[m] = '\0'; ++m; pathstr = &projects[n][m]; ret = pmix_mca_base_component_repository_add(project, pathstr); if (PMIX_SUCCESS != ret) { PMIX_DESTRUCT(&pmix_mca_base_component_repository); (void) pmix_mca_base_framework_close(&pmix_pdl_base_framework); PMIx_Argv_free(projects); return ret; } } PMIx_Argv_free(projects); #endif /* All done */ return PMIX_SUCCESS; } int pmix_mca_base_component_repository_get_components(pmix_mca_base_framework_t *framework, pmix_list_t **framework_components) { *framework_components = NULL; #if PMIX_HAVE_PDL_SUPPORT return pmix_hash_table_get_value_ptr(&pmix_mca_base_component_repository, framework->framework_name, strlen(framework->framework_name), (void **) framework_components); #else PMIX_HIDE_UNUSED_PARAMS(framework); return PMIX_ERR_NOT_FOUND; #endif } #if PMIX_HAVE_PDL_SUPPORT static void pmix_mca_base_component_repository_release_internal(pmix_mca_base_component_repository_item_t *ri) { int group_id; group_id = pmix_mca_base_var_group_find("*", ri->ri_type, ri->ri_name); if (0 <= group_id) { /* ensure all variables are deregistered before we dlclose the component */ pmix_mca_base_var_group_deregister(group_id); } /* Close the component (and potentially unload it from memory */ if (ri->ri_dlhandle) { pmix_pdl_close(ri->ri_dlhandle); ri->ri_dlhandle = NULL; } } #endif #if PMIX_HAVE_PDL_SUPPORT static pmix_mca_base_component_repository_item_t *find_component(const char *type, const char *name) { pmix_mca_base_component_repository_item_t *ri; pmix_list_t *component_list; int ret; ret = pmix_hash_table_get_value_ptr(&pmix_mca_base_component_repository, type, strlen(type), (void **) &component_list); if (PMIX_SUCCESS != ret) { /* component does not exist in the repository */ return NULL; } PMIX_LIST_FOREACH (ri, component_list, pmix_mca_base_component_repository_item_t) { if (0 == strcmp(ri->ri_name, name)) { return ri; } } return NULL; } #endif void pmix_mca_base_component_repository_release(const pmix_mca_base_component_t *component) { #if PMIX_HAVE_PDL_SUPPORT pmix_mca_base_component_repository_item_t *ri; ri = find_component(component->pmix_mca_type_name, component->pmix_mca_component_name); if (NULL != ri && !(--ri->ri_refcnt)) { pmix_mca_base_component_repository_release_internal(ri); } #else PMIX_HIDE_UNUSED_PARAMS(component); #endif } int pmix_mca_base_component_repository_retain_component(const char *type, const char *name) { #if PMIX_HAVE_PDL_SUPPORT pmix_mca_base_component_repository_item_t *ri = find_component(type, name); if (NULL != ri) { ++ri->ri_refcnt; return PMIX_SUCCESS; } return PMIX_ERR_NOT_FOUND; #else PMIX_HIDE_UNUSED_PARAMS(type, name); return PMIX_ERR_NOT_SUPPORTED; #endif } int pmix_mca_base_component_repository_open(pmix_mca_base_framework_t *framework, pmix_mca_base_component_repository_item_t *ri) { #if PMIX_HAVE_PDL_SUPPORT pmix_mca_base_component_t *component_struct; pmix_mca_base_component_list_item_t *mitem = NULL; char *struct_name = NULL; int vl, ret; pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_INFO, 0, "pmix_mca_base_component_repository_open: examining dynamic " "%s MCA component \"%s\" at path %s", ri->ri_type, ri->ri_name, ri->ri_path); vl = pmix_mca_base_show_load_errors(ri->ri_type, ri->ri_name) ? PMIX_MCA_BASE_VERBOSE_ERROR : PMIX_MCA_BASE_VERBOSE_INFO;; /* Ensure that this component is not already loaded (should only happen if it was statically loaded). It's an error if it's already loaded because we're evaluating this file -- not this component. Hence, returning PMIX_ERR_PARAM indicates that the *file* failed to load, not the component. */ PMIX_LIST_FOREACH (mitem, &framework->framework_components, pmix_mca_base_component_list_item_t) { if (0 == strcmp(mitem->cli_component->pmix_mca_component_name, ri->ri_name)) { pmix_output_verbose( PMIX_MCA_BASE_VERBOSE_INFO, 0, "pmix_mca_base_component_repository_open: already loaded (ignored)"); return PMIX_ERR_BAD_PARAM; } } /* silence coverity issue (invalid free) */ mitem = NULL; if (NULL != ri->ri_dlhandle) { pmix_output_verbose( PMIX_MCA_BASE_VERBOSE_INFO, 0, "pmix_mca_base_component_repository_open: already loaded. returning cached component"); mitem = PMIX_NEW(pmix_mca_base_component_list_item_t); if (NULL == mitem) { return PMIX_ERR_OUT_OF_RESOURCE; } mitem->cli_component = ri->ri_component_struct; pmix_list_append(&framework->framework_components, &mitem->super); return PMIX_SUCCESS; } if (0 != strcmp(ri->ri_type, framework->framework_name)) { /* shouldn't happen. attempting to open a component belonging to * another framework. if this happens it is likely a MCA base * bug so assert */ assert(0); return PMIX_ERR_NOT_SUPPORTED; } /* Now try to load the component */ char *err_msg = NULL; if (PMIX_SUCCESS != pmix_pdl_open(ri->ri_path, true, false, &ri->ri_dlhandle, &err_msg)) { if (NULL == err_msg) { err_msg = strdup("pmix_dl_open() error message was NULL!"); } else if (file_exists(ri->ri_path, "lo") || file_exists(ri->ri_path, "so") || file_exists(ri->ri_path, "dylib") || file_exists(ri->ri_path, "dll")) { char *tmp; /* Because libltdl erroneously says "file not found" for any * type of error -- which is especially misleading when the file * is actually there but cannot be opened for some other reason * (e.g., missing symbol) -- do some simple huersitics and if * the file [probably] does exist, print a slightly better error * message. */ pmix_asprintf(&tmp, "\n dlopen error: %s\n Perhaps a missing symbol, or compiled for a different version of %s?", err_msg, framework->framework_project); err_msg = tmp; } pmix_output_verbose( vl, 0, "pmix_mca_base_component_repository_open: unable to open %s: %s (ignored)", ri->ri_path, err_msg); if (pmix_mca_base_component_track_load_errors) { pmix_mca_base_failed_component_t *f_comp = PMIX_NEW(pmix_mca_base_failed_component_t); f_comp->comp = ri; if (0 > asprintf(&(f_comp->error_msg), "%s", err_msg)) { PMIX_RELEASE(f_comp); free(err_msg); return PMIX_ERR_BAD_PARAM; } pmix_list_append(&framework->framework_failed_components, &f_comp->super); } free(err_msg); return PMIX_ERR_BAD_PARAM; } /* Successfully opened the component; now find the public struct. Malloc out enough space for it. */ do { pmix_asprintf(&struct_name, "%s_mca_%s_%s_component", ri->ri_project, ri->ri_type, ri->ri_name); mitem = PMIX_NEW(pmix_mca_base_component_list_item_t); if (NULL == mitem) { ret = PMIX_ERR_OUT_OF_RESOURCE; break; } err_msg = NULL; ret = pmix_pdl_lookup(ri->ri_dlhandle, struct_name, (void **) &component_struct, &err_msg); if (PMIX_SUCCESS != ret || NULL == component_struct) { if (NULL == err_msg) { err_msg = "pmix_dl_lookup() error message was NULL!"; } pmix_output_verbose( vl, 0, "pmix_mca_base_component_repository_open: \"%s\" does not appear to be a valid " "%s MCA dynamic component (ignored):\n %s (ret %d)", ri->ri_base, ri->ri_type, err_msg, ret); ret = PMIX_ERR_BAD_PARAM; break; } /* done with the structure name */ free(struct_name); struct_name = NULL; /* We found the public struct. Make sure its MCA major.minor version is the same as ours. TODO -- add checks for project version (from framework) */ if (!(PMIX_MCA_BASE_VERSION_MAJOR == component_struct->pmix_mca_major_version && PMIX_MCA_BASE_VERSION_MINOR == component_struct->pmix_mca_minor_version)) { pmix_output_verbose( vl, 0, "pmix_mca_base_component_repository_open: %s\n \"%s\" uses an MCA interface that is " "not recognized (component MCA v%d.%d.%d != supported MCA v%d.%d.%d) -- ignored", ri->ri_type, ri->ri_path, component_struct->pmix_mca_major_version, component_struct->pmix_mca_minor_version, component_struct->pmix_mca_release_version, PMIX_MCA_BASE_VERSION_MAJOR, PMIX_MCA_BASE_VERSION_MINOR, PMIX_MCA_BASE_VERSION_RELEASE); ret = PMIX_ERR_BAD_PARAM; break; } /* Also check that the component struct framework and component names match the expected names from the filename */ if (0 != strcmp(component_struct->pmix_mca_type_name, ri->ri_type) || 0 != strcmp(component_struct->pmix_mca_component_name, ri->ri_name)) { pmix_output_verbose( vl, 0, "Component file data does not match filename:\n %s (%s / %s) != %s %s -- ignored", ri->ri_path, ri->ri_type, ri->ri_name, component_struct->pmix_mca_type_name, component_struct->pmix_mca_component_name); ret = PMIX_ERR_BAD_PARAM; break; } /* Alles gut. Save the component struct, and register this component to be closed later. */ ri->ri_component_struct = mitem->cli_component = component_struct; ri->ri_refcnt = 1; pmix_list_append(&framework->framework_components, &mitem->super); pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_INFO, 0, "pmix_mca_base_component_repository_open: opened dynamic %s MCA " "component \"%s\"", ri->ri_type, ri->ri_name); return PMIX_SUCCESS; } while (0); if (mitem) { PMIX_RELEASE(mitem); } if (struct_name) { free(struct_name); } pmix_pdl_close(ri->ri_dlhandle); ri->ri_dlhandle = NULL; return ret; #else /* no dlopen support */ PMIX_HIDE_UNUSED_PARAMS(framework, ri); return PMIX_ERR_NOT_SUPPORTED; #endif } /* * Finalize the repository -- close everything that's still open. */ void pmix_mca_base_component_repository_finalize(void) { if (!initialized) { return; } initialized = false; #if PMIX_HAVE_PDL_SUPPORT pmix_list_t *component_list; void *node, *key; size_t key_size; int ret; ret = pmix_hash_table_get_first_key_ptr(&pmix_mca_base_component_repository, &key, &key_size, (void **) &component_list, &node); while (PMIX_SUCCESS == ret) { PMIX_LIST_RELEASE(component_list); ret = pmix_hash_table_get_next_key_ptr(&pmix_mca_base_component_repository, &key, &key_size, (void **) &component_list, node, &node); } (void) pmix_mca_base_framework_close(&pmix_pdl_base_framework); PMIX_DESTRUCT(&pmix_mca_base_component_repository); #endif } #if PMIX_HAVE_PDL_SUPPORT /* * Basic sentinel values, and construct the inner list */ static void ri_constructor(pmix_mca_base_component_repository_item_t *ri) { memset(ri->ri_type, 0, sizeof(ri->ri_type)); ri->ri_dlhandle = NULL; ri->ri_component_struct = NULL; ri->ri_path = NULL; } /* * Close a component */ static void ri_destructor(pmix_mca_base_component_repository_item_t *ri) { /* dlclose the component if it is still open */ pmix_mca_base_component_repository_release_internal(ri); /* It should be obvious, but I'll state it anyway because it bit me during debugging: after the dlclose(), the pmix_mca_base_component_t pointer is no longer valid because it has [potentially] been unloaded from memory. So don't try to use it. :-) */ if (NULL != ri->ri_project) { free(ri->ri_project); } if (NULL != ri->ri_path) { free(ri->ri_path); } if (NULL != ri->ri_base) { free(ri->ri_base); } } #endif /* PMIX_HAVE_PDL_SUPPORT */ pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_component_find.c0000664000175000017500000003067615203536752023767 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #ifdef HAVE_NETDB_H # include #endif #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_component_repository.h" #include "src/mca/mca.h" #include "src/mca/pdl/base/base.h" #include "src/mca/pinstalldirs/pinstalldirs.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_show_help.h" #if PMIX_HAVE_PDL_SUPPORT /* * Private functions */ static void find_dyn_components(const char *path, pmix_mca_base_framework_t *framework, const char **names, bool include_mode); #endif /* PMIX_HAVE_PDL_SUPPORT */ static int component_find_check(pmix_mca_base_framework_t *framework, char **requested_component_names); /* * Dummy structure for casting for open_only logic */ struct pmix_mca_base_open_only_dummy_component_t { /** MCA base component */ pmix_mca_base_component_t version; }; typedef struct pmix_mca_base_open_only_dummy_component_t pmix_mca_base_open_only_dummy_component_t; static char negate[] = "^"; static bool use_component(const bool include_mode, const char **requested_component_names, const char *component_name); /* * Function to find as many components of a given type as possible. This * includes statically-linked in components as well as opening up a * directory and looking for shared-library MCA components of the * appropriate type (load them if available). * * Return one consolidated array of (pmix_mca_base_component_t*) pointing to all * available components. */ int pmix_mca_base_component_find(const char *directory, pmix_mca_base_framework_t *framework, bool ignore_requested, bool open_dso_components) { const pmix_mca_base_component_t ***static_components = framework->framework_static_components; char **requested_component_names = NULL; pmix_mca_base_component_list_item_t *cli; bool include_mode = true; int ret; PMIX_HIDE_UNUSED_PARAMS(open_dso_components); pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, framework->framework_output, "mca: base: component_find: searching %s for %s components", (NULL == directory) ? "NULL" : directory, framework->framework_name); if (!ignore_requested) { ret = pmix_mca_base_component_parse_requested(framework->framework_selection, &include_mode, &requested_component_names); if (PMIX_SUCCESS != ret) { return ret; } } /* Find all the components that were statically linked in */ if (static_components) { for (int i = 0; NULL != static_components[i]; ++i) { if (use_component(include_mode, (const char **) requested_component_names, (*static_components[i])->pmix_mca_component_name)) { cli = PMIX_NEW(pmix_mca_base_component_list_item_t); if (NULL == cli) { ret = PMIX_ERR_OUT_OF_RESOURCE; goto component_find_out; } cli->cli_component = (*static_components[i]); pmix_list_append(&framework->framework_components, (pmix_list_item_t *) cli); } } } #if PMIX_HAVE_PDL_SUPPORT /* Find any available dynamic components in the specified directory */ if (open_dso_components && !pmix_mca_base_component_disable_dlopen) { find_dyn_components(directory, framework, (const char **) requested_component_names, include_mode); } else { pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_INFO, 0, "pmix:mca: base: component_find: dso loading for %s MCA components disabled", framework->framework_name); } #endif if (include_mode) { ret = component_find_check(framework, requested_component_names); } else { ret = PMIX_SUCCESS; } component_find_out: if (NULL != requested_component_names) { PMIx_Argv_free(requested_component_names); } /* All done */ return ret; } int pmix_mca_base_component_find_finalize(void) { return PMIX_SUCCESS; } int pmix_mca_base_components_filter(pmix_mca_base_framework_t *framework) { pmix_list_t *components = &framework->framework_components; int output_id = framework->framework_output; pmix_mca_base_component_list_item_t *cli, *next; char **requested_component_names = NULL; bool include_mode, can_use; int ret; assert(NULL != components); if (NULL == framework->framework_selection) { return PMIX_SUCCESS; } ret = pmix_mca_base_component_parse_requested(framework->framework_selection, &include_mode, &requested_component_names); if (PMIX_SUCCESS != ret) { return ret; } PMIX_LIST_FOREACH_SAFE (cli, next, components, pmix_mca_base_component_list_item_t) { const pmix_mca_base_component_t *component = cli->cli_component; can_use = use_component(include_mode, (const char **) requested_component_names, cli->cli_component->pmix_mca_component_name); if (!can_use) { pmix_list_remove_item(components, &cli->super); pmix_mca_base_component_unload(component, output_id); PMIX_RELEASE(cli); } } if (include_mode) { ret = component_find_check(framework, requested_component_names); } else { ret = PMIX_SUCCESS; } if (NULL != requested_component_names) { PMIx_Argv_free(requested_component_names); } return ret; } #if PMIX_HAVE_PDL_SUPPORT /* * Open up all directories in a given path and search for components of * the specified type (and possibly of a given name). * * Note that we use our own path iteration functionality because we * need to look at companion .pmix_info files in the same directory as * the library to generate dependencies, etc. */ static void find_dyn_components(const char *path, pmix_mca_base_framework_t *framework, const char **names, bool include_mode) { pmix_mca_base_component_repository_item_t *ri; pmix_list_t *dy_components; int ret; pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, framework->framework_output, "mca: base: find_dyn_components: checking %s for %s components", (NULL == path) ? "NULL" : path, framework->framework_name); if (NULL != path) { ret = pmix_mca_base_component_repository_add(framework->framework_project, path); if (PMIX_SUCCESS != ret) { return; } } ret = pmix_mca_base_component_repository_get_components(framework, &dy_components); if (PMIX_SUCCESS != ret) { return; } /* Iterate through the repository and find components that can be included */ PMIX_LIST_FOREACH (ri, dy_components, pmix_mca_base_component_repository_item_t) { if (use_component(include_mode, names, ri->ri_name)) { pmix_mca_base_component_repository_open(framework, ri); } } } #endif /* PMIX_HAVE_PDL_SUPPORT */ static bool use_component(const bool include_mode, const char **requested_component_names, const char *component_name) { bool found = false; const char **req_comp_name = requested_component_names; /* * If no selection is specified then we use all components * we can find. */ if (NULL == req_comp_name) { return true; } while (*req_comp_name != NULL) { if (strcmp(component_name, *req_comp_name) == 0) { found = true; break; } req_comp_name++; } /* * include_mode found | use * --------------------+------ * 0 0 | true * 0 1 | false * 1 0 | false * 1 1 | true * * -> inverted xor * As xor is a binary operator let's implement it manually before * a compiler screws it up. */ return (include_mode && found) || !(include_mode || found); } /* Ensure that *all* requested components exist. Print a warning and abort if they do not. */ static int component_find_check(pmix_mca_base_framework_t *framework, char **requested_component_names) { pmix_list_t *components = &framework->framework_components; pmix_mca_base_component_list_item_t *cli; if (NULL == requested_component_names) { return PMIX_SUCCESS; } for (int i = 0; NULL != requested_component_names[i]; ++i) { bool found = false; PMIX_LIST_FOREACH (cli, components, pmix_mca_base_component_list_item_t) { if (0 == strcmp(requested_component_names[i], cli->cli_component->pmix_mca_component_name)) { found = true; break; } } if (!found && pmix_mca_base_component_show_load_errors) { char h[PMIX_MAXHOSTNAMELEN] = {0}; gethostname(h, sizeof(h) - 1); pmix_show_help("help-pmix-mca-base.txt", "find-available:not-valid", true, h, framework->framework_name, requested_component_names[i]); if (pmix_mca_base_component_abort_on_load_error) { return PMIX_ERR_NOT_FOUND; } } } return PMIX_SUCCESS; } int pmix_mca_base_component_parse_requested(const char *requested, bool *include_mode, char ***requested_component_names) { const char *requested_orig = requested; *requested_component_names = NULL; *include_mode = true; /* See if the user requested anything */ if (NULL == requested || 0 == strlen(requested)) { return PMIX_SUCCESS; } /* Are we including or excluding? We only allow the negate character to be the *first* character of the value (but be nice and allow any number of negate characters in the beginning). */ *include_mode = requested[0] != negate[0]; /* skip over all negate symbols at the beginning */ requested += strspn(requested, negate); /* Double check to ensure that the user did not specify the negate character anywhere else in the value. */ if (NULL != strstr(requested, negate)) { pmix_show_help("help-pmix-mca-base.txt", "framework-param:too-many-negates", true, requested_orig); return PMIX_ERROR; } /* Split up the value into individual component names */ *requested_component_names = PMIx_Argv_split(requested, ','); /* All done */ return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_component_compare.c0000664000175000017500000001141615203536752024464 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" /* * Function for comparing two pmix_mca_base_component_priority_t structs so * that we can build prioritized listss of them. This assumed that * the types of the modules are the same. Sort first by priority, * second by module name, third by module version. * * Note that we actually want a *reverse* ordering here -- the al_* * functions will put "smaller" items at the head, and "larger" items * at the tail. Since we want the highest priority at the head, it * may help the gentle reader to consider this an inverse comparison. * :-) */ int pmix_mca_base_component_compare_priority(pmix_mca_base_component_priority_list_item_t *a, pmix_mca_base_component_priority_list_item_t *b) { /* First, compare the priorties */ if (a->cpli_priority > b->cpli_priority) { return -1; } else if (a->cpli_priority < b->cpli_priority) { return 1; } else { return pmix_mca_base_component_compare(a->super.cli_component, b->super.cli_component); } } int pmix_mca_base_component_compare(const pmix_mca_base_component_t *aa, const pmix_mca_base_component_t *bb) { int val; val = strncmp(aa->pmix_mca_type_name, bb->pmix_mca_type_name, PMIX_MCA_BASE_MAX_TYPE_NAME_LEN); if (val != 0) { return -val; } val = strncmp(aa->pmix_mca_component_name, bb->pmix_mca_component_name, PMIX_MCA_BASE_MAX_COMPONENT_NAME_LEN); if (val != 0) { return -val; } /* The names were equal, so compare the versions */ if (aa->pmix_mca_component_major_version > bb->pmix_mca_component_major_version) { return -1; } else if (aa->pmix_mca_component_major_version < bb->pmix_mca_component_major_version) { return 1; } else if (aa->pmix_mca_component_minor_version > bb->pmix_mca_component_minor_version) { return -1; } else if (aa->pmix_mca_component_minor_version < bb->pmix_mca_component_minor_version) { return 1; } else if (aa->pmix_mca_component_release_version > bb->pmix_mca_component_release_version) { return -1; } else if (aa->pmix_mca_component_release_version < bb->pmix_mca_component_release_version) { return 1; } return 0; } /** * compare but exclude the release version - declare compatible * if the major/minor version are the same. */ int pmix_mca_base_component_compatible(const pmix_mca_base_component_t *aa, const pmix_mca_base_component_t *bb) { int val; val = strncmp(aa->pmix_mca_type_name, bb->pmix_mca_type_name, PMIX_MCA_BASE_MAX_TYPE_NAME_LEN); if (val != 0) { return -val; } val = strncmp(aa->pmix_mca_component_name, bb->pmix_mca_component_name, PMIX_MCA_BASE_MAX_COMPONENT_NAME_LEN); if (val != 0) { return -val; } /* The names were equal, so compare the versions */ if (aa->pmix_mca_component_major_version > bb->pmix_mca_component_major_version) { return -1; } else if (aa->pmix_mca_component_major_version < bb->pmix_mca_component_major_version) { return 1; } else if (aa->pmix_mca_component_minor_version > bb->pmix_mca_component_minor_version) { return -1; } else if (aa->pmix_mca_component_minor_version < bb->pmix_mca_component_minor_version) { return 1; } return 0; } /** * Returns a string which represents the component name and version. * Has the form: comp_type.comp_name.major_version.minor_version */ char *pmix_mca_base_component_to_string(const pmix_mca_base_component_t *a) { char *str = NULL; if (0 > asprintf(&str, "%s.%s.%d.%d", a->pmix_mca_type_name, a->pmix_mca_component_name, a->pmix_mca_component_major_version, a->pmix_mca_component_minor_version)) { return NULL; } return str; } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_open.c0000664000175000017500000003042615203536752021717 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2008 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #ifdef HAVE_SYSLOG_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #include "pmix_common.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_component_repository.h" #include "src/mca/mca.h" #include "src/mca/pinstalldirs/pinstalldirs.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_output.h" #include "src/util/pmix_os_dirpath.h" #include "src/util/pmix_printf.h" /* * Public variables */ char *pmix_mca_base_component_path = NULL; int pmix_mca_base_opened = 0; char *pmix_mca_base_system_default_path = NULL; char *pmix_mca_base_user_default_path = NULL; char *pmix_mca_base_component_show_load_errors = NULL; bool pmix_mca_base_component_abort_on_load_error = false; bool pmix_mca_base_component_track_load_errors = false; bool pmix_mca_base_component_disable_dlopen = false; static char *pmix_mca_base_verbose = NULL; static char *path_from_param = NULL; /* * Private functions */ static void set_defaults(pmix_output_stream_t *lds); static void parse_verbose(char *e, pmix_output_stream_t *lds); /* * Main MCA initialization. */ int pmix_mca_base_open(const char *add_path) { #if PMIX_WANT_HOME_CONFIG_FILES char *value; #endif char **paths = NULL, *cptr; pmix_output_stream_t lds; char hostname[PMIX_MAXHOSTNAMELEN] = {0}; int var_id; int rc; if (0 < pmix_mca_base_opened) { /* allow someone to extend the component search path */ if (NULL != add_path) { /* put the requested added paths at the front */ if (NULL == pmix_mca_base_component_path) { pmix_mca_base_component_path = strdup(add_path); } else { pmix_asprintf(&cptr, "%s;%s", add_path, pmix_mca_base_component_path); free(pmix_mca_base_component_path); pmix_mca_base_component_path = cptr; } } pmix_mca_base_opened++; // track ref count return PMIX_SUCCESS; } pmix_mca_base_opened++; /* define the system and user default paths */ pmix_mca_base_system_default_path = strdup(pmix_pinstall_dirs.pmixlibdir); PMIx_Argv_append_nosize(&paths, pmix_mca_base_system_default_path); #if PMIX_WANT_HOME_CONFIG_FILES value = (char *) pmix_home_directory(geteuid()); pmix_asprintf(&pmix_mca_base_user_default_path, "%s" PMIX_PATH_SEP ".pmix" PMIX_PATH_SEP "components", value); PMIx_Argv_append_nosize(&paths, pmix_mca_base_user_default_path); #endif var_id = pmix_mca_base_var_register("pmix", "mca", "base", "component_path", "Path where to look for additional components", PMIX_MCA_BASE_VAR_TYPE_STRING, &path_from_param); (void) pmix_mca_base_var_register_synonym(var_id, "pmix", "mca", NULL, "component_path", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); if (NULL != path_from_param) { PMIx_Argv_append_nosize(&paths, path_from_param); } cptr = PMIx_Argv_join(paths, PMIX_ENV_SEP); PMIx_Argv_free(paths); if (NULL != add_path) { pmix_asprintf(&pmix_mca_base_component_path, "%s;pmix@%s", add_path, cptr); } else { pmix_asprintf(&pmix_mca_base_component_path, "pmix@%s", cptr); } free(cptr); pmix_mca_base_component_show_load_errors = PMIX_SHOW_LOAD_ERRORS_DEFAULT; var_id = pmix_mca_base_var_register( "pmix", "mca", "base", "component_show_load_errors", "Whether to show errors for components that failed to load or not. " "Valid values are \"all\" (meaning: all load failures are reported), " "\"none\" (no load failures are reported), or a comma-delimited list " "of items, each of which can be a framework/component pair or a framework " "name (only load failures from the specifically-listed items are reported). " "If the comma-delimited list is prefixed with \"^\", then orientation of " "the list is negated: warn about all load failures *except* for the listed items.", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_base_component_show_load_errors); (void) pmix_mca_base_var_register_synonym(var_id, "pmix", "mca", NULL, "component_show_load_errors", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); // Parse the mca_base_component_show_load_errors value int ret = pmix_mca_base_show_load_errors_init(); if (PMIX_SUCCESS != ret) { return ret; } pmix_mca_base_component_abort_on_load_error = false; var_id = pmix_mca_base_var_register( "pmix", "mca", "base", "abort_on_load_error", "Whether to abort when a specified component isn't found or cannot be loaded", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_mca_base_component_abort_on_load_error); pmix_mca_base_component_track_load_errors = false; var_id = pmix_mca_base_var_register( "pmix", "mca", "base", "component_track_load_errors", "Whether to track errors for components that failed to load or not", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_mca_base_component_track_load_errors); pmix_mca_base_component_disable_dlopen = false; var_id = pmix_mca_base_var_register( "pmix", "mca", "base", "component_disable_dlopen", "Whether to attempt to disable opening dynamic components or not", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_mca_base_component_disable_dlopen); (void) pmix_mca_base_var_register_synonym(var_id, "pmix", "mca", NULL, "component_disable_dlopen", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); /* What verbosity level do we want for the default 0 stream? */ pmix_mca_base_verbose = "stderr"; var_id = pmix_mca_base_var_register( "pmix", "mca", "base", "verbose", "Specifies where the default error output stream goes (this is separate from distinct help " "messages). Accepts a comma-delimited list of: stderr, stdout, syslog, " "syslogpri:, syslogid: (where str is the prefix string for all " "syslog notices), file[:filename] (if filename is not specified, a default filename is " "used), fileappend (if not specified, the file is opened for truncation), level[:N] (if " "specified, integer verbose level; otherwise, 0 is implied)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_base_verbose); (void) pmix_mca_base_var_register_synonym(var_id, "pmix", "mca", NULL, "verbose", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); memset(&lds, 0, sizeof(lds)); if (NULL != pmix_mca_base_verbose) { parse_verbose(pmix_mca_base_verbose, &lds); } else { set_defaults(&lds); } gethostname(hostname, PMIX_MAXHOSTNAMELEN - 1); rc = asprintf(&lds.lds_prefix, "[%s:%05d] ", hostname, getpid()); if (0 > rc) { if (NULL != lds.lds_file_suffix) { free(lds.lds_file_suffix); } return PMIX_ERR_OUT_OF_RESOURCE; } pmix_output_reopen(0, &lds); pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, 0, "mca: base: opening components at %s", pmix_mca_base_component_path); free(lds.lds_prefix); /* Open up the component repository */ return pmix_mca_base_component_repository_init(); } /* * Set sane default values for the lds */ static void set_defaults(pmix_output_stream_t *lds) { /* Load up defaults */ PMIX_CONSTRUCT(lds, pmix_output_stream_t); #if defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H) lds->lds_syslog_priority = LOG_INFO; #endif /* defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H) */ lds->lds_syslog_ident = "ompi"; lds->lds_want_stderr = true; } /* * Parse the value of an environment variable describing verbosity */ static void parse_verbose(char *e, pmix_output_stream_t *lds) { char *edup; char *ptr, *next; bool have_output = false; if (NULL == e) { return; } edup = strdup(e); ptr = edup; /* Now parse the environment variable */ while (NULL != ptr && strlen(ptr) > 0) { next = strchr(ptr, ','); if (NULL != next) { *next = '\0'; } if (0 == strcasecmp(ptr, "syslog")) { #if defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H) lds->lds_want_syslog = true; have_output = true; #else pmix_output(0, "syslog support requested but not available on this system"); #endif /* defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H) */ } else if (strncasecmp(ptr, "syslogpri:", 10) == 0) { #if defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H) lds->lds_want_syslog = true; have_output = true; if (strcasecmp(ptr + 10, "notice") == 0) lds->lds_syslog_priority = LOG_NOTICE; else if (strcasecmp(ptr + 10, "INFO") == 0) lds->lds_syslog_priority = LOG_INFO; else if (strcasecmp(ptr + 10, "DEBUG") == 0) lds->lds_syslog_priority = LOG_DEBUG; #else pmix_output(0, "syslog support requested but not available on this system"); #endif /* defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H) */ } else if (strncasecmp(ptr, "syslogid:", 9) == 0) { #if defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H) lds->lds_want_syslog = true; lds->lds_syslog_ident = ptr + 9; #else pmix_output(0, "syslog support requested but not available on this system"); #endif /* defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H) */ } else if (strcasecmp(ptr, "stdout") == 0) { lds->lds_want_stdout = true; have_output = true; } else if (strcasecmp(ptr, "stderr") == 0) { lds->lds_want_stderr = true; have_output = true; } else if (strcasecmp(ptr, "file") == 0 || strcasecmp(ptr, "file:") == 0) { lds->lds_want_file = true; have_output = true; } else if (strncasecmp(ptr, "file:", 5) == 0) { lds->lds_want_file = true; lds->lds_file_suffix = strdup(ptr + 5); have_output = true; } else if (strcasecmp(ptr, "fileappend") == 0) { lds->lds_want_file = true; lds->lds_want_file_append = 1; have_output = true; } else if (strncasecmp(ptr, "level", 5) == 0) { lds->lds_verbose_level = 0; if (ptr[5] == PMIX_ENV_SEP) lds->lds_verbose_level = atoi(ptr + 6); } if (NULL == next) { break; } ptr = next + 1; } /* If we didn't get an output, default to stderr */ if (!have_output) { lds->lds_want_stderr = true; } /* All done */ free(edup); } pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_alias.c0000664000175000017500000001315115203536752022043 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2020 Google, LLC. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include "pmix_common.h" #include "src/class/pmix_hash_table.h" #include "src/mca/base/pmix_mca_base_alias.h" static void pmix_mca_base_alias_init(pmix_mca_base_alias_t *alias) { PMIX_CONSTRUCT(&alias->component_aliases, pmix_list_t); } static void pmix_mca_base_alias_fini(pmix_mca_base_alias_t *alias) { PMIX_LIST_DESTRUCT(&alias->component_aliases); } PMIX_CLASS_INSTANCE(pmix_mca_base_alias_t, pmix_object_t, pmix_mca_base_alias_init, pmix_mca_base_alias_fini); static void pmix_mca_base_alias_item_init(pmix_mca_base_alias_item_t *alias_item) { alias_item->component_alias = NULL; } static void pmix_mca_base_alias_item_fini(pmix_mca_base_alias_item_t *alias_item) { free(alias_item->component_alias); } PMIX_CLASS_INSTANCE(pmix_mca_base_alias_item_t, pmix_list_item_t, pmix_mca_base_alias_item_init, pmix_mca_base_alias_item_fini); /* * local variables */ static pmix_hash_table_t *alias_hash_table; void pmix_mca_base_alias_cleanup(void) { if (!alias_hash_table) { return; } void *key; pmix_object_t *value; PMIX_HASH_TABLE_FOREACH_PTR(key, value, alias_hash_table, { PMIX_RELEASE(value); }); PMIX_RELEASE(alias_hash_table); alias_hash_table = NULL; } static int pmix_mca_base_alias_setup(void) { if (NULL != alias_hash_table) { return PMIX_SUCCESS; } alias_hash_table = PMIX_NEW(pmix_hash_table_t); if (NULL == alias_hash_table) { return PMIX_ERR_OUT_OF_RESOURCE; } int ret = pmix_hash_table_init(alias_hash_table, 32); if (PMIX_SUCCESS != ret) { PMIX_RELEASE(alias_hash_table); alias_hash_table = NULL; return ret; } return PMIX_SUCCESS; } static char *pmix_mca_base_alias_generate_name(const char *project, const char *framework, const char *component_name) { size_t project_length = project ? strlen(project) : 0; size_t framework_length = framework ? strlen(framework) : 0; size_t component_name_length = strlen(component_name); size_t length = project_length + framework_length + component_name_length + 2; char *tmp = calloc(1, length + 1); if (NULL == tmp) { return tmp; } if (project_length) { strncat(tmp, project, length); // NOTE: We use strcat() here (and not strncat()) because // we're appending a constant string with a fixed/hard-coded // length. It's the exact equivalent of strncat(tmp, "_", 1), // but strncat() would actually be more overhead. Indeed, GCC // 10 emits a warning if we use strncatd() with a compile-time // constant string as the source and a hard-coded length that // is equivalent to the length of that compile-time constant // string. So avoid the warning and use strcat(). strcat(tmp, "_"); length -= project_length + 1; } if (framework_length) { strncat(tmp, framework, length); // Use strcat() here instead of strncat(); see the comment // above for an explanation. strcat(tmp, "_"); length -= framework_length + 1; } strncat(tmp, component_name, length); return tmp; } static pmix_mca_base_alias_t *pmix_mca_base_alias_lookup_internal(const char *name) { pmix_mca_base_alias_t *alias = NULL; if (NULL == alias_hash_table) { return NULL; } (void) pmix_hash_table_get_value_ptr(alias_hash_table, name, strlen(name), (void **) &alias); return alias; } int pmix_mca_base_alias_register(const char *project, const char *framework, const char *component_name, const char *component_alias, uint32_t alias_flags) { if (NULL == component_name) { return PMIX_ERR_BAD_PARAM; } int ret = pmix_mca_base_alias_setup(); if (PMIX_SUCCESS != ret) { return ret; } char *name = pmix_mca_base_alias_generate_name(project, framework, component_name); assert(NULL != name); pmix_mca_base_alias_t *alias = pmix_mca_base_alias_lookup_internal(name); if (NULL == alias) { alias = PMIX_NEW(pmix_mca_base_alias_t); if (NULL == alias) { free(name); return PMIX_ERR_OUT_OF_RESOURCE; } pmix_hash_table_set_value_ptr(alias_hash_table, name, strlen(name), alias); free(name); name = NULL; } pmix_mca_base_alias_item_t *alias_item = PMIX_NEW(pmix_mca_base_alias_item_t); if (NULL == alias_item) { if (NULL != name) { free(name); } return PMIX_ERR_OUT_OF_RESOURCE; } alias_item->component_alias = strdup(component_alias); alias_item->alias_flags = alias_flags; pmix_list_append(&alias->component_aliases, &alias_item->super); if (NULL != name) { free(name); } return PMIX_SUCCESS; } const pmix_mca_base_alias_t *pmix_mca_base_alias_lookup(const char *project, const char *framework, const char *component_name) { if (NULL == component_name) { return NULL; } char *name = pmix_mca_base_alias_generate_name(project, framework, component_name); assert(NULL != name); const pmix_mca_base_alias_t *alias = pmix_mca_base_alias_lookup_internal(name); free(name); return alias; } pmix-6.1.1~rc2/src/mca/base/Makefile.am0000664000175000017500000000423715203536752020000 0ustar alastairalastair# # Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2010-2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017-2018 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # Need this so that the base knows where to load dynamic components from # (by default) AM_CPPFLAGS = \ $(LTDLINCL) noinst_LTLIBRARIES = libpmix_mca_base.la EXTRA_DIST = help-pmix-mca-base.txt help-pmix-mca-var.txt # Source code files headers = \ pmix_base.h \ pmix_mca_base_component_repository.h \ pmix_mca_base_var.h \ pmix_mca_base_var_enum.h \ pmix_mca_base_var_group.h \ pmix_mca_base_vari.h \ pmix_mca_base_framework.h \ pmix_mca_base_alias.h # Library libpmix_mca_base_la_SOURCES = \ $(headers) \ pmix_mca_base_close.c \ pmix_mca_base_component_compare.c \ pmix_mca_base_component_find.c \ pmix_mca_base_component_repository.c \ pmix_mca_base_components_open.c \ pmix_mca_base_components_close.c \ pmix_mca_base_components_select.c \ pmix_mca_base_list.c \ pmix_mca_base_open.c \ pmix_mca_base_var.c \ pmix_mca_base_var_enum.c \ pmix_mca_base_var_group.c \ pmix_mca_base_parse_paramfile.c \ pmix_mca_base_components_register.c \ pmix_mca_base_framework.c \ pmix_mca_base_alias.c # Unconditionally install the header files pmixdir = $(pmixincludedir)/$(subdir) pmix_HEADERS = $(headers) pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_close.c0000664000175000017500000000531515203536752022062 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2009-2022 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_component_repository.h" #include "src/mca/mca.h" #include "src/util/pmix_output.h" extern int pmix_mca_base_opened; /* * Main MCA shutdown. */ int pmix_mca_base_close(void) { assert(pmix_mca_base_opened); if (!--pmix_mca_base_opened) { /* deregister all MCA base parameters */ int group_id = pmix_mca_base_var_group_find("pmix", "mca", "base"); if (-1 < group_id) { pmix_mca_base_var_group_deregister(group_id); } /* release the default paths */ if (NULL != pmix_mca_base_system_default_path) { free(pmix_mca_base_system_default_path); pmix_mca_base_system_default_path = NULL; } if (NULL != pmix_mca_base_user_default_path) { free(pmix_mca_base_user_default_path); pmix_mca_base_user_default_path = NULL; } if (NULL != pmix_mca_base_component_path) { free(pmix_mca_base_component_path); pmix_mca_base_component_path = NULL; } /* Close down the component repository */ pmix_mca_base_component_repository_finalize(); /* Shut down the dynamic component finder */ pmix_mca_base_component_find_finalize(); /* Shut down the show_load_errors processing */ pmix_mca_base_show_load_errors_finalize(); /* Close pmix output stream 0 */ pmix_output_close(0); } /* All done */ return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/base/help-pmix-mca-var.txt0000664000175000017500000000635215203536752021734 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2011 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2013 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2018 Intel, Inc. All rights reserved. # Copyright (c) 2022-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for PMIX MCA error messages. # [missing-param-file] Process %d Unable to locate the variable file "%s" in the following search path: %s # [deprecated-mca-env] A deprecated MCA variable value was specified in the environment or on the command line. Deprecated MCA variables should be avoided; they may disappear in future releases. Deprecated variable: %s New variable: %s # [deprecated-mca-cli] A deprecated MCA variable value was specified on the command line. Deprecated MCA variables should be avoided; they may disappear in future releases. Deprecated variable: %s New variable: %s # [deprecated-mca-file] A deprecated MCA variable value was specified in an MCA variable file. Deprecated MCA variables should be avoided; they may disappear in future releases. Deprecated variable: %s Source file: %s New variable: %s # [mutually-exclusive-vars] Two mutually-exclusive MCA variables were specified. This can result in undefined behavior, such as ignoring the components that the MCA variables are supposed to affect. 1st MCA variable: %s Source of value: %s 2nd MCA variable: %s Source of value: %s # [re-register-with-different-type] An MCA variable was re-registered with a different type (i.e., it was either originally registered as an INT and re-registered as a STRING, or it was originally registered as a STRING and re-registered as an INT). This a developer error; your job may abort. MCA variable name: %s # [var-name-conflict] A name collision was detected on an MCA variable name. This can happen if two components try to register the same variable with slightly different name components. The conflicting variables are listed below: MCA variable name: %s New name: %s %s %s Existing name: %s %s %s # [overridden-param-set] WARNING: A user-supplied value attempted to set a variable that is set in the override variable file (pmix-mca-params-override.conf). Variable: %s The user-supplied value was ignored. # [invalid-value] An invalid value was supplied for an MCA variable. Variable : %s Value : %s # [invalid-value-enum] An invalid value was supplied for an enum variable. Variable : %s Value : %s Valid values : %s pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_list.c0000664000175000017500000000365215203536752021732 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" /* * Local functions */ static void cl_constructor(pmix_object_t *obj); static void cpl_constructor(pmix_object_t *obj); /* * Class instance of the pmix_mca_base_component_list_item_t class */ PMIX_CLASS_INSTANCE(pmix_mca_base_component_list_item_t, pmix_list_item_t, cl_constructor, NULL); /* * Class instance of the pmix_mca_base_component_priority_list_item_t class */ PMIX_CLASS_INSTANCE(pmix_mca_base_component_priority_list_item_t, pmix_mca_base_component_list_item_t, cpl_constructor, NULL); /* * Just do basic sentinel initialization */ static void cl_constructor(pmix_object_t *obj) { pmix_mca_base_component_list_item_t *cli = (pmix_mca_base_component_list_item_t *) obj; cli->cli_component = NULL; } /* * Just do basic sentinel initialization */ static void cpl_constructor(pmix_object_t *obj) { pmix_mca_base_component_priority_list_item_t *cpli = (pmix_mca_base_component_priority_list_item_t *) obj; cpli->cpli_priority = -1; } pmix-6.1.1~rc2/src/mca/base/pmix_base.h0000664000175000017500000002330115203536752020055 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2013-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_MCA_BASE_H #define PMIX_MCA_BASE_H #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/class/pmix_object.h" /* * These units are large enough to warrant their own .h files */ #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/mca.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_output.h" BEGIN_C_DECLS /* * Structure for making plain lists of components */ struct pmix_mca_base_component_list_item_t { pmix_list_item_t super; const pmix_mca_base_component_t *cli_component; }; typedef struct pmix_mca_base_component_list_item_t pmix_mca_base_component_list_item_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_mca_base_component_list_item_t); /* * Structure for making priority lists of components */ struct pmix_mca_base_component_priority_list_item_t { pmix_mca_base_component_list_item_t super; int cpli_priority; }; typedef struct pmix_mca_base_component_priority_list_item_t pmix_mca_base_component_priority_list_item_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_mca_base_component_priority_list_item_t); /* * Public variables */ PMIX_EXPORT extern char *pmix_mca_base_component_path; PMIX_EXPORT extern char *pmix_mca_base_component_show_load_errors; PMIX_EXPORT extern bool pmix_mca_base_component_abort_on_load_error; PMIX_EXPORT extern bool pmix_mca_base_component_track_load_errors; PMIX_EXPORT extern bool pmix_mca_base_component_disable_dlopen; PMIX_EXPORT extern char *pmix_mca_base_system_default_path; PMIX_EXPORT extern char *pmix_mca_base_user_default_path; /* * Standard verbosity levels */ enum { /** total silence */ PMIX_MCA_BASE_VERBOSE_NONE = -1, /** only errors are printed */ PMIX_MCA_BASE_VERBOSE_ERROR = 0, /** emit messages about component selection, open, and unloading */ PMIX_MCA_BASE_VERBOSE_COMPONENT = 10, /** also emit warnings */ PMIX_MCA_BASE_VERBOSE_WARN = 20, /** also emit general, user-relevant information, such as rationale as to why certain choices * or code paths were taken, information gleaned from probing the local system, etc. */ PMIX_MCA_BASE_VERBOSE_INFO = 40, /** also emit relevant tracing information (e.g., which functions were invoked / * call stack entry/exit info) */ PMIX_MCA_BASE_VERBOSE_TRACE = 60, /** also emit PMIX-developer-level (i.e,. highly detailed) information */ PMIX_MCA_BASE_VERBOSE_DEBUG = 80, /** also output anything else that might be useful */ PMIX_MCA_BASE_VERBOSE_MAX = 100, }; /* * Public functions */ /** * First function called in the MCA. * * @return PMIX_SUCCESS Upon success * @return PMIX_ERROR Upon failure * * This function starts up the entire MCA. It initializes a bunch * of built-in MCA parameters, and initialized the MCA component * repository. * * It must be the first MCA function invoked. It is normally * invoked during the initialization stage and specifically * invoked in the special case of the *_info command. */ PMIX_EXPORT int pmix_mca_base_open(const char *add_path); /** * Last function called in the MCA * * @return PMIX_SUCCESS Upon success * @return PMIX_ERROR Upon failure * * This function closes down the entire MCA. It clears all MCA * parameters and closes down the MCA component repository. * * It must be the last MCA function invoked. It is normally invoked * during the finalize stage. */ PMIX_EXPORT int pmix_mca_base_close(void); /** * A generic select function * */ PMIX_EXPORT int pmix_mca_base_select(const char *type_name, int output_id, pmix_list_t *components_available, pmix_mca_base_module_t **best_module, pmix_mca_base_component_t **best_component, int *priority_out); /** * A function for component query functions to discover if they have * been explicitly required to or requested to be selected. * * exclusive: If the specified component is the only component that is * available for selection. * */ PMIX_EXPORT int pmix_mca_base_is_component_required(pmix_list_t *components_available, pmix_mca_base_component_t *component, bool exclusive, bool *is_required); /* pmix_mca_base_component_compare.c */ PMIX_EXPORT int pmix_mca_base_component_compare_priority(pmix_mca_base_component_priority_list_item_t *a, pmix_mca_base_component_priority_list_item_t *b); PMIX_EXPORT int pmix_mca_base_component_compare(const pmix_mca_base_component_t *a, const pmix_mca_base_component_t *b); PMIX_EXPORT int pmix_mca_base_component_compatible(const pmix_mca_base_component_t *a, const pmix_mca_base_component_t *b); PMIX_EXPORT char *pmix_mca_base_component_to_string(const pmix_mca_base_component_t *a); /* pmix_mca_base_component_find.c */ PMIX_EXPORT int pmix_mca_base_component_find(const char *directory, pmix_mca_base_framework_t *framework, bool ignore_requested, bool open_dso_components); /** * Parse the requested component string and return an pmix_argv of the requested * (or not requested) components. */ PMIX_EXPORT int pmix_mca_base_component_parse_requested(const char *requested, bool *include_mode, char ***requested_component_names); /** * Filter a list of components based on a comma-delimted list of names * * @param[in] framework * * @returns PMIX_SUCCESS On success * @returns PMIX_ERR_NOT_FOUND If some component in {filter_names} is not found in * {components}. Does not apply to negated filters. * @returns pmix error code On other error. * * This function closes and releases any components that do not match the filter_name and * filter flags. */ PMIX_EXPORT int pmix_mca_base_components_filter(pmix_mca_base_framework_t *framework); /* Safely release some memory allocated by pmix_mca_base_component_find() (i.e., is safe to call even if you never called pmix_mca_base_component_find()). */ PMIX_EXPORT int pmix_mca_base_component_find_finalize(void); /* pmix_mca_base_components_register.c */ PMIX_EXPORT int pmix_mca_base_framework_components_register(struct pmix_mca_base_framework_t *framework, pmix_mca_base_register_flag_t flags); /* pmix_mca_base_components_open.c */ PMIX_EXPORT int pmix_mca_base_show_load_errors_init(void); PMIX_EXPORT int pmix_mca_base_show_load_errors_finalize(void); PMIX_EXPORT bool pmix_mca_base_show_load_errors(const char *framework_name, const char *component_name); PMIX_EXPORT int pmix_mca_base_framework_components_open(struct pmix_mca_base_framework_t *framework, pmix_mca_base_open_flag_t flags); PMIX_EXPORT int pmix_mca_base_components_open(const char *type_name, int output_id, const pmix_mca_base_component_t **static_components, pmix_list_t *components_available, bool open_dso_components); /* pmix_mca_base_components_close.c */ /** * Close and release a component. * * @param[in] component Component to close * @param[in] output_id Output id for debugging output * * After calling this function the component may no longer be used. */ PMIX_EXPORT void pmix_mca_base_component_close(const pmix_mca_base_component_t *component, int output_id); /** * Release a component without closing it. * @param[in] component Component to close * @param[in] output_id Output id for debugging output * * After calling this function the component may no longer be used. */ PMIX_EXPORT void pmix_mca_base_component_unload(const pmix_mca_base_component_t *component, int output_id); PMIX_EXPORT int pmix_mca_base_components_close(int output_id, pmix_list_t *components_available, const pmix_mca_base_component_t *skip); PMIX_EXPORT int pmix_mca_base_framework_components_close(struct pmix_mca_base_framework_t *framework, const pmix_mca_base_component_t *skip); END_C_DECLS #endif /* MCA_BASE_H */ pmix-6.1.1~rc2/src/mca/base/help-pmix-mca-base.txt0000664000175000017500000000576415203536752022064 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2022 Cisco Systems, Inc. All rights reserved # Copyright (c) 2018-2020 Intel, Inc. All rights reserved. # Copyright (c) 2022-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for PMIX MCA error messages. # [find-available:not-valid] A requested component was not found, or was unable to be opened. This means that this component is either not installed or is unable to be used on your system (e.g., sometimes this means that shared libraries that the component requires are unable to be found/loaded). Note that PMIx stopped checking at the first component that it did not find. Host: %s Framework: %s Component: %s # [framework-param:too-many-negates] MCA framework parameters can only take a single negation operator ("^"), and it must be at the beginning of the value. The following value violates this rule: %s When used, the negation operator sets the "exclusive" behavior mode, meaning that it will exclude all specified components (and implicitly include all others). If the negation operator is not specified, the "inclusive" mode is assumed, meaning that all specified components will be included (and implicitly exclude all others). For example, "^a,b" specifies the exclusive behavior and means "use all components *except* a and b", while "c,d" specifies the inclusive behavior and means "use *only* components c and d." You cannot mix inclusive and exclusive behavior. # [internal error during init] An internal error has occurred during the startup of PMIx. This is highly unusual and shouldn't happen. The following message may provide additional insight into the error: Failure at: %s (%s:%d) Error: %d (%s) # [show_load_errors: too many /] The pmix_mca_base_component_show_load_errors MCA variable cannot contain a token that has more than one "/" character in it. The pmix_mca_base_component_show_load_errors MCA variable can only contain the values: all, none, or a comma-delimited list of tokens in the form of "framework" or "framework/component". Erroneous value: %s # [failed to add component dir] The pmix_mca_base_component_path MCA variable was used to add paths to search for PMIx components. At least one directory failed to add properly: %s Check to make sure that this directory exists, is readable, etc. pmix-6.1.1~rc2/src/mca/base/pmix_mca_base_components_select.c0000664000175000017500000001240715203536752024501 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #ifdef HAVE_SYS_TYPES_H # include #endif #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_component_repository.h" #include "src/mca/mca.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" int pmix_mca_base_select(const char *type_name, int output_id, pmix_list_t *components_available, pmix_mca_base_module_t **best_module, pmix_mca_base_component_t **best_component, int *priority_out) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_mca_base_component_t *component = NULL; pmix_mca_base_module_t *module = NULL; int priority = 0, best_priority = INT32_MIN; int rc; *best_module = NULL; *best_component = NULL; pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca:base:select: Auto-selecting %s components", type_name); /* * Traverse the list of available components. * For each call their 'query' functions to determine relative priority. */ PMIX_LIST_FOREACH (cli, components_available, pmix_mca_base_component_list_item_t) { component = (pmix_mca_base_component_t *) cli->cli_component; /* * If there is a query function then use it. */ if (NULL == component->pmix_mca_query_component) { pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca:base:select:(%5s) Skipping component [%s]. It does not " "implement a query function", type_name, component->pmix_mca_component_name); continue; } /* * Query this component for the module and priority */ pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca:base:select:(%5s) Querying component [%s]", type_name, component->pmix_mca_component_name); rc = component->pmix_mca_query_component(&module, &priority); if (PMIX_ERR_FATAL == rc) { /* a fatal error was detected by this component - e.g., the * user specified a required element and the component could * not find it. In this case, we must not continue as we might * find some other component that could run, causing us to do * something the user didn't want */ return rc; } else if (PMIX_SUCCESS != rc) { /* silently skip this component */ continue; } /* * If no module was returned, then skip component */ if (NULL == module) { pmix_output_verbose( PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca:base:select:(%5s) Skipping component [%s]. Query failed to return a module", type_name, component->pmix_mca_component_name); continue; } /* * Determine if this is the best module we have seen by looking the priority */ pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca:base:select:(%5s) Query of component [%s] set priority to %d", type_name, component->pmix_mca_component_name, priority); if (priority > best_priority) { best_priority = priority; *best_component = component; *best_module = module; } } if (priority_out) { *priority_out = best_priority; } /* * Finished querying all components. * Make sure we found something in the process. */ if (NULL == *best_component) { pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca:base:select:(%5s) No component selected!", type_name); /* * Still close the non-selected components */ pmix_mca_base_components_close(0, /* Pass 0 to keep this from closing the pmix_output_handle */ components_available, NULL); return PMIX_ERR_NOT_FOUND; } pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id, "mca:base:select:(%5s) Selected component [%s]", type_name, (*best_component)->pmix_mca_component_name); /* * Close the non-selected components */ pmix_mca_base_components_close(output_id, components_available, (pmix_mca_base_component_t *) (*best_component)); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pif/0000775000175000017500000000000015203536752015602 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pif/linux_ipv6/0000775000175000017500000000000015203536752017705 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pif/linux_ipv6/owner.txt0000664000175000017500000000024415203536752021600 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner: INTEL status: maintenance pmix-6.1.1~rc2/src/mca/pif/linux_ipv6/configure.m40000664000175000017500000000242115203536752022127 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2023 Nanook Consulting. All rights reserved. # Copyright (c) 2024 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AC_DEFUN([MCA_pmix_pif_linux_ipv6_COMPILE_MODE], [ AC_MSG_CHECKING([for MCA component $1:$2 compile mode]) $3="static" AC_MSG_RESULT([$$3]) ]) # MCA_pif_config_CONFIG(action-if-can-compile, # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pif_linux_ipv6_CONFIG], [ AC_CONFIG_FILES([src/mca/pif/linux_ipv6/Makefile]) AC_REQUIRE([OAC_CHECK_OS_FLAVORS]) AC_MSG_CHECKING([if we are on Linux with TCP]) # If we have struct sockaddr and we're on Linux, then we're # happy. AS_IF([test "$pmix_found_sockaddr" = "yes" && test "$oac_found_linux" = "yes"], [AC_MSG_RESULT([yes]) $1], [AC_MSG_RESULT([no]) $2]) ])dnl pmix-6.1.1~rc2/src/mca/pif/linux_ipv6/pif_linux_ipv6.c0000664000175000017500000001326215203536752023016 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_SOCKIO_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_NET_IF_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_IFADDRS_H # include #endif #include "src/mca/pif/base/base.h" #include "src/mca/pif/pif.h" #include "src/util/pmix_output.h" #include "src/util/pmix_if.h" static int if_linux_ipv6_open(void); /* Discovers Linux IPv6 interfaces */ pmix_pif_base_component_t pmix_mca_pif_linux_ipv6_component = { PMIX_PIF_BASE_VERSION_2_0_0, /* Component name and version */ .pmix_mca_component_name = "linux_ipv6", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = if_linux_ipv6_open }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pif, linux_ipv6) /* configure using getifaddrs(3) */ static int if_linux_ipv6_open(void) { FILE *f; if ((f = fopen("/proc/net/if_inet6", "r"))) { /* IF_NAMESIZE is normally 16 on Linux, but the next scanf allows up to 21 bytes */ char ifname[PMIX_IF_NAMESIZE]; unsigned int idx, pfxlen, scope, dadstat; struct in6_addr a6; int iter; uint32_t flag; unsigned int addrbyte[PMIX_IF_NAMESIZE]; memset(addrbyte, 0, PMIX_IF_NAMESIZE * sizeof(unsigned int)); memset(ifname, 0, PMIX_IF_NAMESIZE * sizeof(char)); while (fscanf(f, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x %x %x %x %x %20s\n", &addrbyte[0], &addrbyte[1], &addrbyte[2], &addrbyte[3], &addrbyte[4], &addrbyte[5], &addrbyte[6], &addrbyte[7], &addrbyte[8], &addrbyte[9], &addrbyte[10], &addrbyte[11], &addrbyte[12], &addrbyte[13], &addrbyte[14], &addrbyte[15], &idx, &pfxlen, &scope, &dadstat, ifname) != EOF) { pmix_pif_t *intf; pmix_output_verbose( 1, pmix_pif_base_framework.framework_output, "found interface %2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x scope " "%x\n", addrbyte[0], addrbyte[1], addrbyte[2], addrbyte[3], addrbyte[4], addrbyte[5], addrbyte[6], addrbyte[7], addrbyte[8], addrbyte[9], addrbyte[10], addrbyte[11], addrbyte[12], addrbyte[13], addrbyte[14], addrbyte[15], scope); /* Only interested in global (0x00) scope */ if (scope != 0x00) { pmix_output_verbose( 1, pmix_pif_base_framework.framework_output, "skipping interface %2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x " "scope %x\n", addrbyte[0], addrbyte[1], addrbyte[2], addrbyte[3], addrbyte[4], addrbyte[5], addrbyte[6], addrbyte[7], addrbyte[8], addrbyte[9], addrbyte[10], addrbyte[11], addrbyte[12], addrbyte[13], addrbyte[14], addrbyte[15], scope); continue; } intf = PMIX_NEW(pmix_pif_t); if (NULL == intf) { pmix_output(0, "pmix_ifinit: unable to allocate %lu bytes\n", (unsigned long) sizeof(pmix_pif_t)); fclose(f); return PMIX_ERR_OUT_OF_RESOURCE; } intf->af_family = AF_INET6; for (iter = 0; iter < 16; iter++) { a6.s6_addr[iter] = addrbyte[iter]; } /* now construct the pmix_pif_t */ pmix_strncpy(intf->if_name, ifname, PMIX_IF_NAMESIZE - 1); intf->if_index = pmix_list_get_size(&pmix_if_list) + 1; intf->if_kernel_index = (uint16_t) idx; ((struct sockaddr_in6 *) &intf->if_addr)->sin6_addr = a6; ((struct sockaddr_in6 *) &intf->if_addr)->sin6_family = AF_INET6; ((struct sockaddr_in6 *) &intf->if_addr)->sin6_scope_id = scope; intf->if_mask = pfxlen; if (PMIX_SUCCESS == pmix_ifindextoflags(pmix_ifnametoindex(ifname), &flag)) { intf->if_flags = flag; } else { intf->if_flags = IFF_UP; } /* copy new interface information to heap and append to list */ pmix_list_append(&pmix_if_list, &(intf->super)); pmix_output_verbose( 1, pmix_pif_base_framework.framework_output, "added interface %2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x\n", addrbyte[0], addrbyte[1], addrbyte[2], addrbyte[3], addrbyte[4], addrbyte[5], addrbyte[6], addrbyte[7], addrbyte[8], addrbyte[9], addrbyte[10], addrbyte[11], addrbyte[12], addrbyte[13], addrbyte[14], addrbyte[15]); } /* of while */ fclose(f); } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pif/linux_ipv6/Makefile.am0000664000175000017500000000056415203536752021746 0ustar alastairalastair# # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # noinst_LTLIBRARIES = libpmix_mca_pif_linux_ipv6.la libpmix_mca_pif_linux_ipv6_la_SOURCES = pif_linux_ipv6.c pmix-6.1.1~rc2/src/mca/pif/bsdx_ipv6/0000775000175000017500000000000015203536752017506 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pif/bsdx_ipv6/owner.txt0000664000175000017500000000024415203536752021401 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner: INTEL status: maintenance pmix-6.1.1~rc2/src/mca/pif/bsdx_ipv6/configure.m40000664000175000017500000000344215203536752021734 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2023 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AC_DEFUN([MCA_pmix_pif_bsdx_ipv6_COMPILE_MODE], [ AC_MSG_CHECKING([for MCA component $1:$2 compile mode]) $3="static" AC_MSG_RESULT([$$3]) ]) # MCA_pif_config_CONFIG(action-if-can-compile, # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pif_bsdx_ipv6_CONFIG], [ AC_CONFIG_FILES([src/mca/pif/bsdx_ipv6/Makefile]) AC_REQUIRE([OAC_CHECK_OS_FLAVORS]) # If we found struct sockaddr and we're on any of the BSDs, we're # happy. I.e., this: #if defined( __NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ # defined(__386BSD__) || defined(__bsdi__) || defined(__APPLE__) AC_MSG_CHECKING([struct sockaddr]) AS_IF([test "$pmix_found_sockaddr" = "yes"], [AC_MSG_RESULT([yes (cached)]) AC_MSG_CHECKING([some flavor of BSD]) AS_IF([test "$oac_found_netbsd" = "yes" || \ test "$oac_found_freebsd" = "yes" || \ test "$oac_found_openbsd" = "yes" || \ test "$oac_found_386bsd" = "yes" || \ test "$oac_found_bsdi" = "yes" || test "$oac_found_apple" = "yes"], [AC_MSG_RESULT([yes]) $1], [AC_MSG_RESULT([no]) $2])], [AC_MSG_RESULT([no (cached)]) $2]) ])dnl pmix-6.1.1~rc2/src/mca/pif/bsdx_ipv6/pif_bsdx_ipv6.c0000664000175000017500000001471115203536752022420 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_SOCKIO_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_NET_IF_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_IFADDRS_H # include #endif #include "src/mca/pif/base/base.h" #include "src/mca/pif/pif.h" #include "src/util/pmix_output.h" #include "src/util/pmix_if.h" static int if_bsdx_ipv6_open(void); /* Discovers IPv6 interfaces for: * * NetBSD * OpenBSD * FreeBSD * 386BSD * bsdi * Apple */ pmix_pif_base_component_t pmix_mca_pif_bsdx_ipv6_component = { PMIX_PIF_BASE_VERSION_2_0_0, /* Component name and version */ .pmix_mca_component_name = "bsdx_ipv6", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = if_bsdx_ipv6_open }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pif, bsdx_ipv6) /* configure using getifaddrs(3) */ static int if_bsdx_ipv6_open(void) { struct ifaddrs **ifadd_list; struct ifaddrs *cur_ifaddrs; struct sockaddr_in6 *sin_addr; pmix_output_verbose(1, pmix_pif_base_framework.framework_output, "searching for IPv6 interfaces"); /* * the manpage claims that getifaddrs() allocates the memory, * and freeifaddrs() is later used to release the allocated memory. * however, without this malloc the call to getifaddrs() segfaults */ ifadd_list = (struct ifaddrs **) malloc(sizeof(struct ifaddrs *)); /* create the linked list of ifaddrs structs */ if (getifaddrs(ifadd_list) < 0) { pmix_output(0, "pmix_ifinit: getifaddrs() failed with error=%d\n", errno); free(ifadd_list); return PMIX_ERROR; } for (cur_ifaddrs = *ifadd_list; NULL != cur_ifaddrs; cur_ifaddrs = cur_ifaddrs->ifa_next) { pmix_pif_t *intf; struct in6_addr a6; /* skip non-ipv6 interface addresses */ if (AF_INET6 != cur_ifaddrs->ifa_addr->sa_family) { pmix_output_verbose(1, pmix_pif_base_framework.framework_output, "skipping non-ipv6 interface %s[%d].\n", cur_ifaddrs->ifa_name, (int) cur_ifaddrs->ifa_addr->sa_family); continue; } /* skip interface if it is down (IFF_UP not set) */ if (0 == (cur_ifaddrs->ifa_flags & IFF_UP)) { pmix_output_verbose(1, pmix_pif_base_framework.framework_output, "skipping non-up interface %s.\n", cur_ifaddrs->ifa_name); continue; } /* skip if it is a point-to-point interface */ /* TODO: do we really skip p2p? */ if (0 != (cur_ifaddrs->ifa_flags & IFF_POINTOPOINT)) { pmix_output_verbose(1, pmix_pif_base_framework.framework_output, "skipping p2p interface %s.\n", cur_ifaddrs->ifa_name); continue; } sin_addr = (struct sockaddr_in6 *) cur_ifaddrs->ifa_addr; /* * skip IPv6 address starting with fe80:, as this is supposed to be * link-local scope. sockaddr_in6->sin6_scope_id doesn't always work * TODO: test whether scope id is set to a sensible value on * linux and/or bsd (including osx) * * MacOSX: fe80::... has a scope of 0, but ifconfig -a shows * a scope of 4 on that particular machine, * so the scope returned by getifaddrs() isn't working properly */ if ((IN6_IS_ADDR_LINKLOCAL(&sin_addr->sin6_addr))) { pmix_output_verbose(1, pmix_pif_base_framework.framework_output, "skipping link-local ipv6 address on interface " "%s with scope %d.\n", cur_ifaddrs->ifa_name, sin_addr->sin6_scope_id); continue; } if (0 < pmix_output_get_verbosity(pmix_pif_base_framework.framework_output)) { char *addr_name = (char *) malloc(48 * sizeof(char)); inet_ntop(AF_INET6, &sin_addr->sin6_addr, addr_name, 48 * sizeof(char)); pmix_output(0, "ipv6 capable interface %s discovered, address %s.\n", cur_ifaddrs->ifa_name, addr_name); free(addr_name); } /* fill values into the pmix_pif_t */ memcpy(&a6, &(sin_addr->sin6_addr), sizeof(struct in6_addr)); intf = PMIX_NEW(pmix_pif_t); if (NULL == intf) { pmix_output(0, "pmix_ifinit: unable to allocate %lu bytes\n", sizeof(pmix_pif_t)); free(ifadd_list); return PMIX_ERR_OUT_OF_RESOURCE; } intf->af_family = AF_INET6; pmix_strncpy(intf->if_name, cur_ifaddrs->ifa_name, PMIX_IF_NAMESIZE - 1); intf->if_index = pmix_list_get_size(&pmix_if_list) + 1; ((struct sockaddr_in6 *) &intf->if_addr)->sin6_addr = a6; ((struct sockaddr_in6 *) &intf->if_addr)->sin6_family = AF_INET6; /* since every scope != 0 is ignored, we just set the scope to 0 */ ((struct sockaddr_in6 *) &intf->if_addr)->sin6_scope_id = 0; /* * hardcoded netmask, adrian says that's ok */ intf->if_mask = 64; intf->if_flags = cur_ifaddrs->ifa_flags; /* * FIXME: figure out how to gain access to the kernel index * (or create our own), getifaddrs() does not contain such * data */ intf->if_kernel_index = (uint16_t) if_nametoindex(cur_ifaddrs->ifa_name); pmix_list_append(&pmix_if_list, &(intf->super)); } /* of for loop over ifaddrs list */ free(ifadd_list); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pif/bsdx_ipv6/Makefile.am0000664000175000017500000000056115203536752021544 0ustar alastairalastair# # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # noinst_LTLIBRARIES = libpmix_mca_pif_bsdx_ipv6.la libpmix_mca_pif_bsdx_ipv6_la_SOURCES = pif_bsdx_ipv6.c pmix-6.1.1~rc2/src/mca/pif/base/0000775000175000017500000000000015203536752016514 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pif/base/owner.txt0000664000175000017500000000024015203536752020403 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner: project status:active pmix-6.1.1~rc2/src/mca/pif/base/pif_base_components.c0000664000175000017500000000570215203536752022701 0ustar alastairalastair/* * Copyright (c) 2010-2013 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "pmix_config.h" #include "pmix_common.h" #include "src/mca/mca.h" #include "src/mca/pif/base/base.h" #include "src/mca/pif/base/static-components.h" #include "src/mca/pif/pif.h" #include "src/util/pmix_output.h" /* instantiate the global list of interfaces */ pmix_list_t pmix_if_list = PMIX_LIST_STATIC_INIT; bool pmix_if_do_not_resolve = false; static int pmix_pif_base_register(pmix_mca_base_register_flag_t flags); static int pmix_pif_base_open(pmix_mca_base_open_flag_t flags); static int pmix_pif_base_close(void); static void pmix_pif_construct(pmix_pif_t *obj); static bool frameopen = false; /* instance the pmix_pif_t object */ PMIX_CLASS_INSTANCE(pmix_pif_t, pmix_list_item_t, pmix_pif_construct, NULL); PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, pif, NULL, pmix_pif_base_register, pmix_pif_base_open, pmix_pif_base_close, pmix_mca_pif_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); static int pmix_pif_base_register(pmix_mca_base_register_flag_t flags) { (void) flags; pmix_if_do_not_resolve = false; (void) pmix_mca_base_framework_var_register(&pmix_pif_base_framework, "do_not_resolve", "If nonzero, do not attempt to resolve interfaces", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_if_do_not_resolve); return PMIX_SUCCESS; } static int pmix_pif_base_open(pmix_mca_base_open_flag_t flags) { if (frameopen) { return PMIX_SUCCESS; } frameopen = true; /* setup the global list */ PMIX_CONSTRUCT(&pmix_if_list, pmix_list_t); return pmix_mca_base_framework_components_open(&pmix_pif_base_framework, flags); } static int pmix_pif_base_close(void) { pmix_list_item_t *item; if (!frameopen) { return PMIX_SUCCESS; } frameopen = false; while (NULL != (item = pmix_list_remove_first(&pmix_if_list))) { PMIX_RELEASE(item); } PMIX_DESTRUCT(&pmix_if_list); return pmix_mca_base_framework_components_close(&pmix_pif_base_framework, NULL); } static void pmix_pif_construct(pmix_pif_t *obj) { memset(obj->if_name, 0, sizeof(obj->if_name)); obj->if_index = -1; obj->if_kernel_index = (uint16_t) -1; obj->af_family = PF_UNSPEC; obj->if_flags = 0; obj->if_speed = 0; memset(&obj->if_addr, 0, sizeof(obj->if_addr)); obj->if_mask = 0; obj->if_bandwidth = 0; memset(obj->if_mac, 0, sizeof(obj->if_mac)); obj->ifmtu = 0; } pmix-6.1.1~rc2/src/mca/pif/base/base.h0000664000175000017500000000113615203536752017600 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016 Intel, Inc. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PIF_BASE_H #define PMIX_PIF_BASE_H #include "src/include/pmix_config.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/pif/pif.h" BEGIN_C_DECLS /* * Framework declaration */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_pif_base_framework; END_C_DECLS #endif /* PMIX_BASE_PIF_H */ pmix-6.1.1~rc2/src/mca/pif/base/Makefile.am0000664000175000017500000000044515203536752020553 0ustar alastairalastair# # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers += \ base/base.h libmca_pif_la_SOURCES += \ base/pif_base_components.c pmix-6.1.1~rc2/src/mca/pif/posix_ipv4/0000775000175000017500000000000015203536752017706 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pif/posix_ipv4/owner.txt0000664000175000017500000000024415203536752021601 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner: INTEL status: maintenance pmix-6.1.1~rc2/src/mca/pif/posix_ipv4/pif_posix.c0000664000175000017500000002327415203536752022062 0ustar alastairalastair/* * Copyright (c) 2010-2013 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_SOCKIO_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_NET_IF_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_IFADDRS_H # include #endif #include "src/mca/pif/base/base.h" #include "src/mca/pif/pif.h" #include "src/util/pmix_output.h" #include "src/util/pmix_if.h" static int if_posix_open(void); /* Supports all flavors of posix except those * BSD-flavors supported elsewhere */ pmix_pif_base_component_t pmix_mca_pif_posix_ipv4_component = { PMIX_PIF_BASE_VERSION_2_0_0, /* Component name and version */ .pmix_mca_component_name = "posix_ipv4", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = if_posix_open }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pif, posix_ipv4) /* convert a netmask (in network byte order) to CIDR notation */ static int prefix(uint32_t netmask) { uint32_t mask = ntohl(netmask); int plen = 0; if (0 == mask) { plen = 32; } else { while ((mask % 2) == 0) { plen += 1; mask /= 2; } } return (32 - plen); } /* configure using getifaddrs(3) */ static int if_posix_open(void) { int sd; int lastlen, rem; char *ptr; struct ifconf ifconf; int ifc_len; bool successful_locate = false; struct ifreq *ifr; pmix_pif_t *intf; int length; /* Create the internet socket to test with. Must use AF_INET; using AF_UNSPEC or AF_INET6 will cause everything to fail. */ if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { pmix_output(0, "pmix_ifinit: socket() failed with errno=%d\n", errno); return PMIX_ERROR; } /* * Get Network Interface configuration * * Some notes on the behavior of ioctl(..., SIOCGIFCONF,...) * when not enough space is allocated for all the entries. * * - Solaris returns -1, errno EINVAL if there is not enough * space * - OS X returns 0, sets .ifc_len to the space used by the * by the entries that did fit. * - Linux returns 0, sets .ifc_len to the space required to * hold all the entries (although it only writes what will * fit in the buffer of .ifc_len passed to the function). * - FreeBSD returns 0, sets .ifc_len to 0. * * Everyone else seems to do one of the four. */ lastlen = 0; ifc_len = sizeof(struct ifreq) * DEFAULT_NUMBER_INTERFACES; do { ifconf.ifc_len = ifc_len; ifconf.ifc_req = (struct ifreq *) malloc(ifc_len); if (NULL == ifconf.ifc_req) { close(sd); return PMIX_ERROR; } /* initialize the memory so valgrind and purify won't * complain. Since this isn't performance critical, just * always memset. */ memset(ifconf.ifc_req, 0, ifconf.ifc_len); if (ioctl(sd, SIOCGIFCONF, &ifconf) < 0) { /* if we got an einval, we probably don't have enough space. so we'll fall down and try to expand our space */ if (errno != EINVAL && lastlen != 0) { pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFCONF) \ failed with errno=%d", errno); free(ifconf.ifc_req); close(sd); return PMIX_ERROR; } } else { /* if ifc_len is 0 or different than what we set it to at call to ioctl, try again with a bigger buffer. else stop */ if (ifconf.ifc_len == lastlen && ifconf.ifc_len > 0) { /* we didn't expand. we're done */ successful_locate = true; break; } lastlen = ifconf.ifc_len; } /* Yes, we overflowed (or had an EINVAL on the ioctl). Loop back around and try again with a bigger buffer */ free(ifconf.ifc_req); ifc_len = (ifc_len == 0) ? 1 : ifc_len * 2; } while (ifc_len < MAX_PIFCONF_SIZE); if (!successful_locate) { pmix_output(0, "pmix_ifinit: unable to find network interfaces."); close(sd); return PMIX_ERROR; } /* * Setup indexes */ ifr = (struct ifreq *) malloc(ifc_len); ptr = (char *) ifconf.ifc_req; rem = ifconf.ifc_len; /* loop through all interfaces */ while (rem > 0) { memset(ifr, 0, ifc_len); memcpy(ifr, ptr, rem); /* compute offset for entries */ #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN length = sizeof(struct sockaddr); if (ifr->ifr_addr.sa_len > length) { length = ifr->ifr_addr.sa_len; } length += sizeof(ifr->ifr_name); #else length = sizeof(struct ifreq); #endif rem -= length; ptr += length; /* see if we like this entry */ if (AF_INET != ifr->ifr_addr.sa_family) { continue; } if (ioctl(sd, SIOCGIFFLAGS, ifr) < 0) { pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFFLAGS) failed with errno=%d", errno); continue; } if ((ifr->ifr_flags & IFF_UP) == 0) { continue; } #ifdef IFF_SLAVE /* Is this a slave to a load balancer or bonded channel? If so, don't use it -- pick up the master instead */ if ((ifr->ifr_flags & IFF_SLAVE) != 0) { continue; } #endif intf = PMIX_NEW(pmix_pif_t); if (NULL == intf) { pmix_output(0, "pmix_ifinit: unable to allocated %lu bytes\n", (unsigned long) sizeof(pmix_pif_t)); free(ifconf.ifc_req); close(sd); free(ifr); return PMIX_ERR_OUT_OF_RESOURCE; } intf->af_family = AF_INET; /* copy entry over into our data structure */ memset(intf->if_name, 0, sizeof(intf->if_name)); pmix_strncpy(intf->if_name, ifr->ifr_name, sizeof(intf->if_name) - 1); intf->if_flags = ifr->ifr_flags; /* every new address gets its own internal if_index */ intf->if_index = pmix_list_get_size(&pmix_if_list) + 1; pmix_output_verbose(1, pmix_pif_base_framework.framework_output, "found interface %s", intf->if_name); /* assign the kernel index to distinguish different NICs */ #ifndef SIOCGIFINDEX intf->if_kernel_index = intf->if_index; #else if (ioctl(sd, SIOCGIFINDEX, ifr) < 0) { pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFINDEX) failed with errno=%d", errno); PMIX_RELEASE(intf); continue; } # if defined(ifr_ifindex) intf->if_kernel_index = ifr->ifr_ifindex; # elif defined(ifr_index) intf->if_kernel_index = ifr->ifr_index; # else intf->if_kernel_index = -1; # endif #endif /* SIOCGIFINDEX */ /* This call returns IPv4 addresses only. Use SIOCGLIFADDR instead */ if (ioctl(sd, SIOCGIFADDR, ifr) < 0) { pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFADDR) failed with errno=%d", errno); PMIX_RELEASE(intf); break; } if (AF_INET != ifr->ifr_addr.sa_family) { PMIX_RELEASE(intf); continue; } /* based on above, we know this is an IPv4 address... */ memcpy(&intf->if_addr, &ifr->ifr_addr, sizeof(struct sockaddr_in)); if (ioctl(sd, SIOCGIFNETMASK, ifr) < 0) { pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFNETMASK) failed with errno=%d", errno); PMIX_RELEASE(intf); continue; } /* generate CIDR and assign to netmask */ intf->if_mask = prefix(((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr); #if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_HWADDR) /* get the MAC address */ if (ioctl(sd, SIOCGIFHWADDR, ifr) < 0) { pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFHWADDR) failed with errno=%d", errno); break; } memcpy(intf->if_mac, ifr->ifr_hwaddr.sa_data, 6); #endif #if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU) /* get the MTU */ if (ioctl(sd, SIOCGIFMTU, ifr) < 0) { pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFMTU) failed with errno=%d", errno); break; } intf->ifmtu = ifr->ifr_mtu; #endif pmix_output_verbose(1, pmix_pif_base_framework.framework_output, "adding interface %s", intf->if_name); pmix_list_append(&pmix_if_list, &(intf->super)); } free(ifconf.ifc_req); close(sd); free(ifr); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pif/posix_ipv4/configure.m40000664000175000017500000000416415203536752022136 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2023 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AC_DEFUN([MCA_pmix_pif_posix_ipv4_COMPILE_MODE], [ AC_MSG_CHECKING([for MCA component $1:$2 compile mode]) $3="static" AC_MSG_RESULT([$$3]) ]) # MCA_pif_config_CONFIG(action-if-can-compile, # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pif_posix_ipv4_CONFIG], [ AC_CONFIG_FILES([src/mca/pif/posix_ipv4/Makefile]) PMIX_VAR_SCOPE_PUSH([pmix_pif_posix_ipv4_happy]) pmix_pif_posix_ipv4_happy=no AC_REQUIRE([OAC_CHECK_OS_FLAVORS]) # If we found struct sockaddr and we're NOT on most of the BSDs, # we're happy. I.e., if posix but not: #if defined(__NetBSD__) || defined(__FreeBSD__) || \ # defined(__OpenBSD__) || defined(__DragonFly__) AC_MSG_CHECKING([struct sockaddr]) AS_IF([test "$pmix_found_sockaddr" = "yes"], [AC_MSG_RESULT([yes (cached)]) AC_MSG_CHECKING([not NetBSD, FreeBSD, OpenBSD, Apple, or DragonFly]) AS_IF([test "$oac_found_netbsd" = "no" && test "$oac_found_freebsd" = "no" && test "$oac_found_openbsd" = "no" && test "$oac_found_dragonfly" = "no" && test "$oac_found_apple" = "no"], [AC_MSG_RESULT([yes]) pmix_pif_posix_ipv4_happy=yes], [AC_MSG_RESULT([no])] )], [AC_MSG_RESULT([no (cached)])] ) AS_IF([test "$pmix_pif_posix_ipv4_happy" = "yes"], [AC_CHECK_MEMBERS([struct ifreq.ifr_hwaddr], [], [], [[#include ]]) AC_CHECK_MEMBERS([struct ifreq.ifr_mtu], [], [], [[#include ]]) ]) AS_IF([test "$pmix_pif_posix_ipv4_happy" = "yes"], [$1], [$2]); ])dnl pmix-6.1.1~rc2/src/mca/pif/posix_ipv4/Makefile.am0000664000175000017500000000055715203536752021751 0ustar alastairalastair# # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # noinst_LTLIBRARIES = libpmix_mca_pif_posix_ipv4.la libpmix_mca_pif_posix_ipv4_la_SOURCES = pif_posix.c pmix-6.1.1~rc2/src/mca/pif/bsdx_ipv4/0000775000175000017500000000000015203536752017504 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pif/bsdx_ipv4/owner.txt0000664000175000017500000000024415203536752021377 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner: INTEL status: maintenance pmix-6.1.1~rc2/src/mca/pif/bsdx_ipv4/configure.m40000664000175000017500000000332315203536752021730 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2023 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AC_DEFUN([MCA_pmix_pif_bsdx_ipv4_COMPILE_MODE], [ AC_MSG_CHECKING([for MCA component $1:$2 compile mode]) $3="static" AC_MSG_RESULT([$$3]) ]) # MCA_pif_config_CONFIG(action-if-can-compile, # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pif_bsdx_ipv4_CONFIG], [ AC_CONFIG_FILES([src/mca/pif/bsdx_ipv4/Makefile]) AC_REQUIRE([OAC_CHECK_OS_FLAVORS]) # If we found struct sockaddr and we're on any of the BSDs, we're # happy. I.e., this: #if defined(__NetBSD__) || defined(__FreeBSD__) || \ # defined(__OpenBSD__) || defined(__DragonFly__) AC_MSG_CHECKING([struct sockaddr]) AS_IF([test "$pmix_found_sockaddr" = "yes"], [AC_MSG_RESULT([yes (cached)]) AC_MSG_CHECKING([NetBSD, FreeBSD, OpenBSD, Apple, or DragonFly]) AS_IF([test "$oac_found_netbsd" = "yes" || \ test "$oac_found_freebsd" = "yes" || \ test "$oac_found_openbsd" = "yes" || \ test "$oac_found_dragonfly" = "yes" || test "$oac_found_apple" = "yes"], [AC_MSG_RESULT([yes]) $1], [AC_MSG_RESULT([no]) $2])], [AC_MSG_RESULT([no (cached)]) $2]) ]) pmix-6.1.1~rc2/src/mca/pif/bsdx_ipv4/Makefile.am0000664000175000017500000000055515203536752021545 0ustar alastairalastair# # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # noinst_LTLIBRARIES = libpmix_mca_pif_bsdx_ipv4.la libpmix_mca_pif_bsdx_ipv4_la_SOURCES = pif_bsdx.c pmix-6.1.1~rc2/src/mca/pif/bsdx_ipv4/pif_bsdx.c0000664000175000017500000001070115203536752021445 0ustar alastairalastair/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_SOCKIO_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_NET_IF_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_IFADDRS_H # include #endif #include "src/mca/pif/base/base.h" #include "src/mca/pif/pif.h" #include "src/util/pmix_output.h" #include "src/util/pmix_if.h" static int if_bsdx_open(void); /* Supports specific flavors of BSD: * NetBSD * FreeBSD * OpenBSD * DragonFly */ pmix_pif_base_component_t pmix_mca_pif_bsdx_ipv4_component = { PMIX_PIF_BASE_VERSION_2_0_0, /* Component name and version */ .pmix_mca_component_name = "bsdx_ipv4", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = if_bsdx_open }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pif, bsdx_ipv4) /* convert a netmask (in network byte order) to CIDR notation */ static int prefix(uint32_t netmask) { uint32_t mask = ntohl(netmask); int plen = 0; if (0 == mask) { plen = 32; } else { while ((mask % 2) == 0) { plen += 1; mask /= 2; } } return (32 - plen); } /* configure using getifaddrs(3) */ static int if_bsdx_open(void) { struct ifaddrs **ifadd_list; struct ifaddrs *cur_ifaddrs; struct sockaddr_in *sin_addr; /* * the manpage claims that getifaddrs() allocates the memory, * and freeifaddrs() is later used to release the allocated memory. * however, without this malloc the call to getifaddrs() segfaults */ ifadd_list = (struct ifaddrs **) malloc(sizeof(struct ifaddrs *)); /* create the linked list of ifaddrs structs */ if (getifaddrs(ifadd_list) < 0) { pmix_output(0, "pmix_ifinit: getifaddrs() failed with error=%d\n", errno); return PMIX_ERROR; } for (cur_ifaddrs = *ifadd_list; NULL != cur_ifaddrs; cur_ifaddrs = cur_ifaddrs->ifa_next) { pmix_pif_t *intf; struct in_addr a4; /* skip non- af_inet interface addresses */ if (AF_INET != cur_ifaddrs->ifa_addr->sa_family) { continue; } /* skip interface if it is down (IFF_UP not set) */ if (0 == (cur_ifaddrs->ifa_flags & IFF_UP)) { continue; } /* skip if it is a point-to-point interface */ /* TODO: do we really skip p2p? */ if (0 != (cur_ifaddrs->ifa_flags & IFF_POINTOPOINT)) { continue; } sin_addr = (struct sockaddr_in *) cur_ifaddrs->ifa_addr; intf = PMIX_NEW(pmix_pif_t); if (NULL == intf) { pmix_output(0, "pmix_ifinit: unable to allocate %d bytes\n", (int) sizeof(pmix_pif_t)); return PMIX_ERR_OUT_OF_RESOURCE; } intf->af_family = AF_INET; /* fill values into the pmix_pif_t */ memcpy(&a4, &(sin_addr->sin_addr), sizeof(struct in_addr)); pmix_strncpy(intf->if_name, cur_ifaddrs->ifa_name, PMIX_IF_NAMESIZE - 1); intf->if_index = pmix_list_get_size(&pmix_if_list) + 1; ((struct sockaddr_in *) &intf->if_addr)->sin_addr = a4; ((struct sockaddr_in *) &intf->if_addr)->sin_family = AF_INET; ((struct sockaddr_in *) &intf->if_addr)->sin_len = cur_ifaddrs->ifa_addr->sa_len; intf->if_mask = prefix(sin_addr->sin_addr.s_addr); intf->if_flags = cur_ifaddrs->ifa_flags; intf->if_kernel_index = (uint16_t) if_nametoindex(cur_ifaddrs->ifa_name); pmix_list_append(&pmix_if_list, &(intf->super)); } /* of for loop over ifaddrs list */ return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pif/Makefile.am0000664000175000017500000000111215203536752017631 0ustar alastairalastair# # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # main library setup noinst_LTLIBRARIES = libmca_pif.la libmca_pif_la_SOURCES = # local files headers = pif.h libmca_pif_la_SOURCES += $(headers) # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.am distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/pif/pif.h0000664000175000017500000000416415203536752016536 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2010-2013 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_MCA_PIF_PIF_H #define PMIX_MCA_PIF_PIF_H #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_SOCKIO_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_NET_IF_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_IFADDRS_H # include #endif #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/util/pmix_if.h" BEGIN_C_DECLS /* * Define INADDR_NONE if we don't have it. Solaris is the only system * where I have found that it does not exist, and the man page for * inet_addr() says that it returns -1 upon failure. On Linux and * other systems with INADDR_NONE, it's just a #define to -1 anyway. * So just #define it to -1 here if it doesn't already exist. */ #if !defined(INADDR_NONE) # define INADDR_NONE -1 #endif #define DEFAULT_NUMBER_INTERFACES 10 #define MAX_PIFCONF_SIZE 10 * 1024 * 1024 /* "global" list of available interfaces */ extern pmix_list_t pmix_if_list; /* global flags */ extern bool pmix_if_do_not_resolve; /** * Structure for if components. */ typedef pmix_mca_base_component_t pmix_pif_base_component_t; /* * Macro for use in components that are of type pif */ #define PMIX_PIF_BASE_VERSION_2_0_0 PMIX_MCA_BASE_VERSION_1_0_0("pif", 2, 0, 0) END_C_DECLS #endif /* PMIX_MCA_PIF_PIF_H */ pmix-6.1.1~rc2/src/mca/pstat/0000775000175000017500000000000015203536752016157 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pstat/test/0000775000175000017500000000000015203536752017136 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pstat/test/pstat_test_component.c0000664000175000017500000000554215203536752023564 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "pmix_config.h" #include "pmix_common.h" #include "pstat_test.h" #include "src/mca/pstat/pstat.h" /* * Public string showing the pstat ompi_test component version number */ const char *pmix_pstat_test_component_version_string = "PMIX test pstat MCA component version " PMIX_VERSION; /* * Local function */ static int pstat_test_component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ const pmix_pstat_base_component_t pmix_mca_pstat_test_component = { /* Indicate that we are a pstat v1.1.0 component (which also implies a specific MCA version) */ PMIX_PSTAT_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "test", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), .pmix_mca_query_component = pstat_test_component_query, }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pstat, test) static int pstat_test_component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 20; *module = (pmix_mca_base_module_t *) &pmix_pstat_test_module; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pstat/test/owner.txt0000664000175000017500000000026015203536752021027 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner: Nanook Consulting status: maintenance pmix-6.1.1~rc2/src/mca/pstat/test/pstat_test.c0000664000175000017500000010241415203536752021476 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYS_TIME_H # include #endif #include "src/include/pmix_globals.h" #include "src/mca/pstat/base/base.h" #include "src/mca/pstat/pstat.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_printf.h" #include "pstat_test.h" /* * API functions */ static pmix_status_t module_init(void); static pmix_status_t query(pmix_proc_t *requestor, const pmix_info_t *monitor, pmix_status_t error, const pmix_info_t directives[], size_t ndirs, pmix_info_t **results, size_t *nresults); static pmix_status_t module_fini(void); /* * Plinux pstat module */ const pmix_pstat_base_module_t pmix_pstat_test_module = { /* Initialization function */ .init = module_init, .query = query, .finalize = module_fini }; static pmix_status_t module_init(void) { return PMIX_SUCCESS; } static pmix_status_t module_fini(void) { return PMIX_SUCCESS; } static pmix_status_t proc_stat(void *answer, pmix_peer_t *peer, pmix_procstats_t *pst) { pmix_proc_t proc; pmix_status_t rc; char state[2]; int32_t i32; float fval; uint16_t u16; void *cache; time_t sample_time; struct timeval evtime; pmix_data_array_t darray; time(&sample_time); cache = PMIx_Info_list_start(); // start with the proc ID PMIx_Load_procid(&proc, peer->info->pname.nspace, peer->info->pname.rank); rc = PMIx_Info_list_add(cache, PMIX_PROCID, &proc, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } // add the pid rc = PMIx_Info_list_add(cache, PMIX_PROC_PID, &peer->info->pid, PMIX_PID); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } // add the hostname rc = PMIx_Info_list_add(cache, PMIX_HOSTNAME, pmix_globals.hostname, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } /* save the cmd name */ if (pst->cmdline) { rc = PMIx_Info_list_add(cache, PMIX_CMD_LINE, "test-stats", PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } state[0] = 'R'; state[1] = '\0'; if (pst->state) { rc = PMIx_Info_list_add(cache, PMIX_PROC_OS_STATE, state, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } evtime.tv_sec = 1234; evtime.tv_usec = 5678; if (pst->time) { rc = PMIx_Info_list_add(cache, PMIX_PROC_TIME, (void*)&evtime, PMIX_TIMEVAL); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } /* save the priority */ if (pst->pri) { i32 = 5; rc = PMIx_Info_list_add(cache, PMIX_PROC_PRIORITY, &i32, PMIX_INT32); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } /* get number of threads */ if (pst->nthreads) { u16 = 10; rc = PMIx_Info_list_add(cache, PMIX_PROC_NUM_THREADS, &u16, PMIX_UINT16); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } /* finally - get the processor */ if (pst->cpu) { u16 = 2; rc = PMIx_Info_list_add(cache, PMIX_PROC_CPU, &u16, PMIX_UINT16); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (pst->pkvsize) { fval = 1.38; rc = PMIx_Info_list_add(cache, PMIX_PROC_PEAK_VSIZE, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (pst->vsize) { fval = 7.92; rc = PMIx_Info_list_add(cache, PMIX_PROC_VSIZE, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (pst->rss) { fval = 3.01; rc = PMIx_Info_list_add(cache, PMIX_PROC_RSS, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (pst->pss) { fval = 0.32; rc = PMIx_Info_list_add(cache, PMIX_PROC_PSS, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } // record the sample time rc = PMIx_Info_list_add(cache, PMIX_PROC_SAMPLE_TIME, &sample_time, PMIX_TIME); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } // add this to the final answer rc = PMIx_Info_list_convert(cache, &darray); PMIx_Info_list_release(cache); if (PMIX_SUCCESS != rc) { return rc; } rc = PMIx_Info_list_add(answer, PMIX_PROC_RESOURCE_USAGE, &darray, PMIX_DATA_ARRAY); return rc; } static pmix_status_t disk_stat(void *answer, char **disks, pmix_dkstats_t *dkst) { char *dptr; void *cache; int n; uint64_t u64; pmix_data_array_t darray; time_t sample_time; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(disks); time(&sample_time); for (n=0; n < 2; n++) { /* take the fields of interest */ cache = PMIx_Info_list_start(); // start with the diskID pmix_asprintf(&dptr, "sd%02d", n); rc = PMIx_Info_list_add(cache, PMIX_DISK_ID, dptr, PMIX_STRING); free(dptr); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } if (dkst->rdcompleted) { u64 = 123456; rc = PMIx_Info_list_add(cache, PMIX_DISK_READ_COMPLETED, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (dkst->rdmerged) { u64 = 789; rc = PMIx_Info_list_add(cache, PMIX_DISK_READ_MERGED, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (dkst->rdsectors) { u64 = 123; rc = PMIx_Info_list_add(cache, PMIX_DISK_READ_SECTORS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (dkst->rdms) { u64 = 1902; rc = PMIx_Info_list_add(cache, PMIX_DISK_READ_MILLISEC, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (dkst->wrtcompleted) { u64 = 12334; rc = PMIx_Info_list_add(cache, PMIX_DISK_WRITE_COMPLETED, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (dkst->wrtmerged) { u64 = 5678; rc = PMIx_Info_list_add(cache, PMIX_DISK_WRITE_MERGED, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (dkst->wrtsectors) { u64 = 9032; rc = PMIx_Info_list_add(cache, PMIX_DISK_WRITE_SECTORS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (dkst->wrtms) { u64 = 89324; rc = PMIx_Info_list_add(cache, PMIX_DISK_WRITE_MILLISEC, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (dkst->ioprog) { u64 = 123; rc = PMIx_Info_list_add(cache, PMIX_DISK_IO_IN_PROGRESS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (dkst->ioms) { u64 = 2343545546; rc = PMIx_Info_list_add(cache, PMIX_DISK_IO_MILLISEC, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (dkst->ioweight) { u64 = 3452; rc = PMIx_Info_list_add(cache, PMIX_DISK_IO_WEIGHTED, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } // record the sample time rc = PMIx_Info_list_add(cache, PMIX_DISK_SAMPLE_TIME, &sample_time, PMIX_TIME); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } // add this to the final answer rc = PMIx_Info_list_convert(cache, &darray); PMIx_Info_list_release(cache); if (PMIX_SUCCESS != rc) { return rc; } rc = PMIx_Info_list_add(answer, PMIX_DISK_RESOURCE_USAGE, &darray, PMIX_DATA_ARRAY); if (PMIX_SUCCESS != rc) { return rc; } } return PMIX_SUCCESS; } static pmix_status_t net_stat(void *answer, char**nets, pmix_netstats_t *netst) { char *dptr; void *cache; int n; uint64_t u64; pmix_data_array_t darray; time_t sample_time; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(nets); /* read the file one line at a time */ for (n=0; n < 3; n++) { time(&sample_time); /* take the fields of interest */ cache = PMIx_Info_list_start(); // start with the network ID pmix_asprintf(&dptr, "net%03d", n); rc = PMIx_Info_list_add(cache, PMIX_NETWORK_ID, dptr, PMIX_STRING); free(dptr); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } if (netst->rcvdb) { u64 = 32353453; rc = PMIx_Info_list_add(cache, PMIX_NET_RECVD_BYTES, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (netst->rcvdp) { u64 = 2325325; rc = PMIx_Info_list_add(cache, PMIX_NET_RECVD_PCKTS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (netst->rcvde) { u64 = 134; rc = PMIx_Info_list_add(cache, PMIX_NET_RECVD_ERRS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (netst->sntb) { u64 = 939092; rc = PMIx_Info_list_add(cache, PMIX_NET_SENT_BYTES, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (netst->sntp) { u64 = 235235435; rc = PMIx_Info_list_add(cache, PMIX_NET_SENT_PCKTS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } if (netst->snte) { u64 = 23253; rc = PMIx_Info_list_add(cache, PMIX_NET_SENT_ERRS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } // record the sample time rc = PMIx_Info_list_add(cache, PMIX_NET_SAMPLE_TIME, &sample_time, PMIX_TIME); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } // add this to the final answer rc = PMIx_Info_list_convert(cache, &darray); PMIx_Info_list_release(cache); if (PMIX_SUCCESS != rc) { return rc; } rc = PMIx_Info_list_add(answer, PMIX_NETWORK_RESOURCE_USAGE, &darray, PMIX_DATA_ARRAY); if (PMIX_SUCCESS != rc) { return rc; } } return PMIX_SUCCESS; } static pmix_status_t node_stat(void *ilist, pmix_ndstats_t *ndst) { float fval; pmix_status_t rc; time_t sample_time; time(&sample_time); /* we only care about the first three numbers */ fval = 0.34; if (ndst->la) { rc = PMIx_Info_list_add(ilist, PMIX_NODE_LOAD_AVG, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } fval = 1.67; if (ndst->la5) { rc = PMIx_Info_list_add(ilist, PMIX_NODE_LOAD_AVG5, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } fval = 3.789; if (ndst->la15) { rc = PMIx_Info_list_add(ilist, PMIX_NODE_LOAD_AVG15, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } if (ndst->mtot) { fval = 17.9; rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_TOTAL, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } if (ndst->mfree) { fval = 12.8; rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_FREE, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } if (ndst->mbuf) { fval = 23.2; rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_BUFFERS, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } if (ndst->mcached) { fval = 1.343; rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_CACHED, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } if (ndst->mswapcached) { fval = 13.98; rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_SWAP_CACHED, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } if (ndst->mswaptot) { fval = 32.1; rc = PMIx_Info_list_add(ilist, PMIX_NODE_SWAP_TOTAL, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } if (ndst->mswapfree) { fval = 9.3; rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_SWAP_FREE, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } if (ndst->mmap) { fval = 0.5; rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_MAPPED, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } rc = PMIx_Info_list_add(ilist, PMIX_NODE_SAMPLE_TIME, &sample_time, PMIX_TIME); if (PMIX_SUCCESS != rc) { return rc; } return PMIX_SUCCESS; } static void evrelease(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t*)cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_RELEASE(cb); } static void update(int sd, short args, void *cbdata) { pmix_pstat_op_t *op = (pmix_pstat_op_t*)cbdata; void *answer, *ilist; pmix_peerlist_t *plist; pmix_status_t rc; pmix_data_array_t darray; pmix_cb_t *cb; pmix_procstats_t zproc; pmix_ndstats_t znd; pmix_netstats_t znet; pmix_dkstats_t zdk; bool nettaken, dktaken, noreset; PMIX_HIDE_UNUSED_PARAMS(sd, args); cb = op->cb; if (NULL == cb) { answer = PMIx_Info_list_start(); noreset = false; } else { answer = cb->cbdata; noreset = true; } PMIX_PROCSTATS_INIT(&zproc); PMIX_NDSTATS_INIT(&znd); PMIX_NETSTATS_INIT(&znet); PMIX_DKSTATS_INIT(&zdk); nettaken = false; dktaken = false; if (0 != memcmp(&op->pstats, &zproc, sizeof(pmix_procstats_t))) { PMIX_LIST_FOREACH(plist, &op->peers, pmix_peerlist_t) { rc = proc_stat(answer, plist->peer, &op->pstats); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIx_Info_list_release(answer); goto reset; } } } if (0 != memcmp(&op->ndstats, &znd, sizeof(pmix_ndstats_t))) { ilist = PMIx_Info_list_start(); // start with hostname rc = PMIx_Info_list_add(ilist, PMIX_HOSTNAME, pmix_globals.hostname, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } // add our nodeID rc = PMIx_Info_list_add(ilist, PMIX_NODEID, &pmix_globals.nodeid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } // collect the stats rc = node_stat(ilist, &op->ndstats); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } if (0 != memcmp(&op->netstats, &znet, sizeof(pmix_netstats_t))) { nettaken = true; rc = net_stat(ilist, op->nets, &op->netstats); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } } if (0 != memcmp(&op->dkstats, &zdk, sizeof(pmix_dkstats_t))) { dktaken = true; rc = disk_stat(ilist, op->disks, &op->dkstats); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } } // add this to the final answer rc = PMIx_Info_list_convert(ilist, &darray); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } PMIx_Info_list_release(ilist); rc = PMIx_Info_list_add(answer, PMIX_NODE_RESOURCE_USAGE, &darray, PMIX_DATA_ARRAY); PMIX_DATA_ARRAY_DESTRUCT(&darray); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(answer); goto reset; } } if (!nettaken && 0 != memcmp(&op->netstats, &znet, sizeof(pmix_netstats_t))) { rc = net_stat(answer, op->nets, &op->netstats); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(answer); goto reset; } } if (!dktaken && 0 != memcmp(&op->dkstats, &zdk, sizeof(pmix_dkstats_t))) { rc = disk_stat(answer, op->disks, &op->dkstats); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(answer); goto reset; } } if (NULL == cb) { // convert to info array rc = PMIx_Info_list_convert(answer, &darray); PMIx_Info_list_release(answer); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto reset; } // setup the event cb = PMIX_NEW(pmix_cb_t); cb->info = (pmix_info_t*)darray.array; cb->ninfo = darray.size; cb->infocopy = true; rc = PMIx_Notify_event(op->eventcode, &pmix_globals.myid, PMIX_RANGE_LOCAL, cb->info, cb->ninfo, evrelease, (void*)cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } reset: if (!noreset) { // reset the timer pmix_event_evtimer_add(&op->ev, &op->tv); } } /* if we are being called, then we already know that the request involves * this node - otherwise, we wouldn't have been called, except where noted */ static pmix_status_t query(pmix_proc_t *requestor, const pmix_info_t *monitor, pmix_status_t eventcode, const pmix_info_t directives[], size_t ndirs, pmix_info_t **results, size_t *nresults) { pmix_info_t *iptr; size_t sz; size_t n, m; int k; pmix_peer_t *ptr; pmix_proc_t proc, *procs; pmix_node_pid_t *ppid; pmix_status_t rc; bool tgtprocsgiven; pmix_data_array_t darray; pmix_pstat_op_t *op; pmix_netstats_t znet; pmix_dkstats_t zdk; pmix_info_t *xfer; pmix_cb_t cb; PMIX_HIDE_UNUSED_PARAMS(requestor); *results = NULL; *nresults = 0; PMIX_NETSTATS_INIT(&znet); PMIX_DKSTATS_INIT(&zdk); if (PMIx_Check_key(monitor->key, PMIX_MONITOR_CANCEL)) { // cancel an existing monitor operation - ID must be the provided value if (monitor->value.type != PMIX_STRING) { return PMIX_ERR_BAD_PARAM; } // cycle through our list of ops operations if (0 == pmix_list_get_size(&pmix_pstat_base.ops)) { // we don't have any operations - this is okay return PMIX_SUCCESS; } PMIX_LIST_FOREACH(op, &pmix_pstat_base.ops, pmix_pstat_op_t) { if (0 == strcmp(monitor->value.data.string, op->id)) { // terminate this operation pmix_list_remove_item(&pmix_pstat_base.ops, &op->super); PMIX_RELEASE(op); return PMIX_SUCCESS; } } // didn't find the operation - this is okay return PMIX_SUCCESS; } op = PMIX_NEW(pmix_pstat_op_t); op->eventcode = eventcode; for (n=0; n < ndirs; n++) { // did they give us an ID for this request? if (PMIx_Check_key(directives[n].key, PMIX_MONITOR_ID)) { op->id = strdup(directives[n].value.data.string); } else if (PMIx_Check_key(directives[n].key, PMIX_MONITOR_RESOURCE_RATE)) { // they are asking us to update it at regular intervals rc = PMIx_Value_get_number(&directives[n].value, (void*)&op->rate, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(op); return rc; } } if (NULL != op->id && 0 < op->rate) { // don't keep searching if unnecessary break; } } // see what data we are being asked to collect if (PMIx_Check_key(monitor->key, PMIX_MONITOR_PROC_RESOURCE_USAGE)) { tgtprocsgiven = false; // see which values are to be returned iptr = (pmix_info_t*)monitor->value.data.darray->array; sz = monitor->value.data.darray->size; pmix_pstat_parse_procstats(&op->pstats, iptr, sz); // we already know this request involves us since it was checked // before calling us, so see which of our processes are included if (NULL == directives) { // all of our processes are included - no ID or rate can be included for (k=0; k < pmix_server_globals.clients.size; k++) { ptr = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, k); if (NULL == ptr) { continue; } PMIX_PSTAT_APPEND_PEER_UNIQUE(&op->peers, ptr); } goto processprocs; } // check for specific procs and directives for (n=0; n < ndirs; n++) { if (PMIx_Check_key(directives[n].key, PMIX_MONITOR_TARGET_PROCS)) { if (PMIX_DATA_ARRAY != directives[n].value.type || NULL == directives[n].value.data.darray || NULL == directives[n].value.data.darray->array) { PMIX_RELEASE(op); return PMIX_ERR_BAD_PARAM; } tgtprocsgiven = true; // they specified the procs procs = (pmix_proc_t*)directives[n].value.data.darray->array; sz = directives[n].value.data.darray->size; for (m=0; m < sz; m++) { for (k=0; k < pmix_server_globals.clients.size; k++) { ptr = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, k); if (NULL == ptr) { continue; } PMIx_Load_procid(&proc, ptr->info->pname.nspace, ptr->info->pname.rank); if (PMIx_Check_procid(&procs[m], &proc)) { PMIX_PSTAT_APPEND_PEER_UNIQUE(&op->peers, ptr); break; } } } } if (PMIx_Check_key(directives[n].key, PMIX_MONITOR_TARGET_PIDS)) { if (PMIX_DATA_ARRAY != directives[n].value.type || NULL == directives[n].value.data.darray || NULL == directives[n].value.data.darray->array) { PMIX_RELEASE(op); return PMIX_ERR_BAD_PARAM; } tgtprocsgiven = true; // is our node included? ppid = (pmix_node_pid_t*)directives[n].value.data.darray->array; sz = directives[n].value.data.darray->size; for (m=0; m < sz; m++) { // see if this node is us if (ppid[m].nodeid == pmix_globals.nodeid || pmix_check_local(ppid[m].hostname)) { // is this one of our procs? for (k=0; k < pmix_server_globals.clients.size; k++) { ptr = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, k); if (NULL == ptr) { continue; } if (ppid[m].pid == ptr->info->pid) { PMIX_PSTAT_APPEND_PEER_UNIQUE(&op->peers, ptr); break; } } } } } } // when we come out of the loop, it is possible that we were not // given any target procs via any of the attributes. In this case, // we assume that we are to take all local procs if (!tgtprocsgiven) { for (k=0; k < pmix_server_globals.clients.size; k++) { ptr = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, k); if (NULL == ptr) { continue; } PMIX_PSTAT_APPEND_PEER_UNIQUE(&op->peers, ptr); } } processprocs: PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.cbdata = PMIx_Info_list_start(); op->cb = &cb; update(0, 0, (void*)op); // convert to info array rc = PMIx_Info_list_convert(cb.cbdata, &darray); PMIx_Info_list_release(cb.cbdata); PMIX_DESTRUCT(&cb); op->cb = NULL; if (PMIX_SUCCESS != rc) { PMIX_RELEASE(op); return rc; } *results = (pmix_info_t*)darray.array; *nresults = darray.size; // if we were given a rate, then setup the event to generate // the requested updates if (0 < op->rate) { pmix_list_append(&pmix_pstat_base.ops, &op->super); PMIX_PSTAT_OP_START(op, op->rate, update); } else { // otherwise, this was a one-time request, so we are done with the op PMIX_RELEASE(op); } return PMIX_SUCCESS; } if (PMIx_Check_key(monitor->key, PMIX_MONITOR_NODE_RESOURCE_USAGE)) { // we already know we are a target node since we are // being called iptr = (pmix_info_t*)monitor->value.data.darray->array; sz = monitor->value.data.darray->size; // determine what stats to return - might include net and disk values pmix_pstat_parse_ndstats(&op->ndstats, iptr, sz); pmix_pstat_parse_netstats(&op->nets, &op->netstats, iptr, sz); pmix_pstat_parse_dkstats(&op->disks, &op->dkstats, iptr, sz); // start collecting response PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.cbdata = PMIx_Info_list_start(); op->cb = &cb; // start with hostname rc = PMIx_Info_list_add(cb.cbdata, PMIX_HOSTNAME, pmix_globals.hostname, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cb.cbdata); op->cb = NULL; PMIX_DESTRUCT(&cb); PMIX_RELEASE(op); return rc; } // add our nodeID rc = PMIx_Info_list_add(cb.cbdata, PMIX_NODEID, &pmix_globals.nodeid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cb.cbdata); op->cb = NULL; PMIX_DESTRUCT(&cb); PMIX_RELEASE(op); return rc; } // collect the stats update(0, 0, (void*)op); // add this to the final answer rc = PMIx_Info_list_convert(cb.cbdata, &darray); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cb.cbdata); op->cb = NULL; PMIX_DESTRUCT(&cb); PMIX_RELEASE(op); return rc; } PMIx_Info_list_release(cb.cbdata); PMIX_DESTRUCT(&cb); op->cb = NULL; PMIX_INFO_CREATE(xfer, 1); PMIX_INFO_LOAD(xfer, PMIX_NODE_RESOURCE_USAGE, &darray, PMIX_DATA_ARRAY); PMIX_DATA_ARRAY_DESTRUCT(&darray); *results = xfer; *nresults = 1; // if we were given a rate, then setup the event to generate // the requested updates if (0 < op->rate) { pmix_list_append(&pmix_pstat_base.ops, &op->super); PMIX_PSTAT_OP_START(op, op->rate, update); } else { // otherwise, this was a one-time request, so we are done with the op PMIX_RELEASE(op); } return PMIX_SUCCESS; } if (PMIx_Check_key(monitor->key, PMIX_MONITOR_DISK_RESOURCE_USAGE)) { // we already know we are a target node since we are // being called iptr = (pmix_info_t*)monitor->value.data.darray->array; sz = monitor->value.data.darray->size; // assemble any provided disk IDs and/or stat specifications pmix_pstat_parse_dkstats(&op->disks, &op->dkstats, iptr, sz); // collect the stats PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.cbdata = PMIx_Info_list_start(); op->cb = &cb; update(0, 0, (void*)op); // convert to info array rc = PMIx_Info_list_convert(cb.cbdata, &darray); PMIx_Info_list_release(cb.cbdata); PMIX_DESTRUCT(&cb); op->cb = NULL; if (PMIX_SUCCESS != rc) { PMIX_RELEASE(op); return rc; } *results = (pmix_info_t*)darray.array; *nresults = darray.size; // if we were given a rate, then setup the event to generate // the requested updates if (0 < op->rate) { pmix_list_append(&pmix_pstat_base.ops, &op->super); PMIX_PSTAT_OP_START(op, op->rate, update); } else { // otherwise, this was a one-time request, so we are done with the op PMIX_RELEASE(op); } return PMIX_SUCCESS; } if (PMIx_Check_key(monitor->key, PMIX_MONITOR_NET_RESOURCE_USAGE)) { // we already know we are a target node since we are // being called iptr = (pmix_info_t*)monitor->value.data.darray->array; sz = monitor->value.data.darray->size; // assemble any provided network IDs and/or stat specifications pmix_pstat_parse_netstats(&op->nets, &op->netstats, iptr, sz); // collect the stats PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.cbdata = PMIx_Info_list_start(); op->cb = &cb; update(0, 0, (void*)op); // convert to info array rc = PMIx_Info_list_convert(cb.cbdata, &darray); PMIx_Info_list_release(cb.cbdata); PMIX_DESTRUCT(&cb); op->cb = NULL; if (PMIX_SUCCESS != rc) { PMIX_RELEASE(op); return rc; } *results = (pmix_info_t*)darray.array; *nresults = darray.size; // if we were given a rate, then setup the event to generate // the requested updates if (0 < op->rate) { pmix_list_append(&pmix_pstat_base.ops, &op->super); PMIX_PSTAT_OP_START(op, op->rate, update); } else { // otherwise, this was a one-time request, so we are done with the op PMIX_RELEASE(op); } return PMIX_SUCCESS; } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pstat/test/Makefile.am0000664000175000017500000000335515203536752021200 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2010-2020 Cisco Systems, Inc. All rights reserved # Copyright (c) 2017 IBM Corporation. All rights reserved. # Copyright (c) 2019-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # sources = \ pstat_test.h \ pstat_test_component.c \ pstat_test.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pstat_test_DSO component_noinst = component_install = pmix_mca_pstat_test.la else component_noinst = libpmix_mca_pstat_test.la component_install = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component_install) pmix_mca_pstat_test_la_SOURCES = $(sources) pmix_mca_pstat_test_la_LDFLAGS = -module -avoid-version pmix_mca_pstat_test_la_LIBADD = $(top_builddir)/src/libpmix.la noinst_LTLIBRARIES = $(component_noinst) libpmix_mca_pstat_test_la_SOURCES =$(sources) libpmix_mca_pstat_test_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/pstat/test/pstat_test.h0000664000175000017500000000271215203536752021503 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef pmix_pstat_TEST_EXPORT_H #define pmix_pstat_TEST_EXPORT_H #include "pmix_config.h" #include "src/mca/mca.h" #include "src/mca/pstat/pstat.h" BEGIN_C_DECLS /* * Globally exported variable */ PMIX_EXPORT extern const pmix_pstat_base_component_t pmix_mca_pstat_test_component; PMIX_EXPORT extern const pmix_pstat_base_module_t pmix_pstat_test_module; END_C_DECLS #endif /* pmix_pstat_TEST_EXPORT_H */ pmix-6.1.1~rc2/src/mca/pstat/base/0000775000175000017500000000000015203536752017071 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pstat/base/pstat_base_fns.c0000664000175000017500000001555515203536752022243 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2014-2019 Intel, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/mca/pstat/base/base.h" #include "src/mca/pstat/pstat.h" void pmix_pstat_parse_procstats(pmix_procstats_t *pst, pmix_info_t *info, size_t sz) { size_t n; if (NULL == info) { PMIX_PROCSTATS_ALL(pst); } else { PMIX_PROCSTATS_INIT(pst); for (n=0; n < sz; n++) { if (PMIx_Check_key(info[n].key, PMIX_PROC_OS_STATE)) { pst->state = true; } else if (PMIx_Check_key(info[n].key, PMIX_PROC_TIME)) { pst->time = true; } else if (PMIx_Check_key(info[n].key, PMIX_PROC_PERCENT_CPU)) { pst->pctcpu = true; } else if (PMIx_Check_key(info[n].key, PMIX_PROC_PRIORITY)) { pst->pri = true; } else if (PMIx_Check_key(info[n].key, PMIX_PROC_NUM_THREADS)) { pst->nthreads = true; } else if (PMIx_Check_key(info[n].key, PMIX_PROC_PSS)) { pst->pss = true; } else if (PMIx_Check_key(info[n].key, PMIX_PROC_VSIZE)) { pst->vsize = true; } else if (PMIx_Check_key(info[n].key, PMIX_PROC_RSS)) { pst->rss = true; } else if (PMIx_Check_key(info[n].key, PMIX_PROC_PEAK_VSIZE)) { pst->pkvsize = true; } else if (PMIx_Check_key(info[n].key, PMIX_PROC_CPU)) { pst->cpu = true; } } } } void pmix_pstat_parse_dkstats(char ***disks, pmix_dkstats_t *dkst, pmix_info_t *info, size_t sz) { size_t n; if (NULL == info) { PMIX_DKSTATS_ALL(dkst); } else { PMIX_DKSTATS_INIT(dkst); for (n=0; n < sz; n++) { if (PMIx_Check_key(info[n].key, PMIX_DISK_ID)) { PMIx_Argv_append_nosize(disks, info[n].value.data.string); } else if (PMIx_Check_key(info[n].key, PMIX_DISK_READ_COMPLETED)) { dkst->rdcompleted = true; } else if (PMIx_Check_key(info[n].key, PMIX_DISK_READ_MERGED)) { dkst->rdmerged = true; } else if (PMIx_Check_key(info[n].key, PMIX_DISK_READ_SECTORS)) { dkst->rdsectors = true; } else if (PMIx_Check_key(info[n].key, PMIX_DISK_READ_MILLISEC)) { dkst->rdms = true; } else if (PMIx_Check_key(info[n].key, PMIX_DISK_WRITE_COMPLETED)) { dkst->wrtcompleted = true; } else if (PMIx_Check_key(info[n].key, PMIX_DISK_WRITE_MERGED)) { dkst->wrtmerged = true; } else if (PMIx_Check_key(info[n].key, PMIX_DISK_WRITE_SECTORS)) { dkst->wrtsectors = true; } else if (PMIx_Check_key(info[n].key, PMIX_DISK_WRITE_MILLISEC)) { dkst->wrtms = true; } else if (PMIx_Check_key(info[n].key, PMIX_DISK_IO_IN_PROGRESS)) { dkst->ioprog = true; } else if (PMIx_Check_key(info[n].key, PMIX_DISK_IO_MILLISEC)) { dkst->ioms = true; } else if (PMIx_Check_key(info[n].key, PMIX_DISK_IO_WEIGHTED)) { dkst->ioweight = true; } } } } void pmix_pstat_parse_netstats(char ***nets, pmix_netstats_t *netst, pmix_info_t *info, size_t sz) { size_t n; if (NULL == info) { PMIX_NETSTATS_ALL(netst); } else { PMIX_NETSTATS_INIT(netst); for (n=0; n < sz; n++) { if (PMIx_Check_key(info[n].key, PMIX_NETWORK_ID)) { PMIx_Argv_append_nosize(nets, info[n].value.data.string); } else if (PMIx_Check_key(info[n].key, PMIX_NET_RECVD_BYTES)) { netst->rcvdb = true; } else if (PMIx_Check_key(info[n].key, PMIX_NET_RECVD_PCKTS)) { netst->rcvdp = true; } else if (PMIx_Check_key(info[n].key, PMIX_NET_RECVD_ERRS)) { netst->rcvde = true; } else if (PMIx_Check_key(info[n].key, PMIX_NET_SENT_BYTES)) { netst->sntb = true; } else if (PMIx_Check_key(info[n].key, PMIX_NET_SENT_PCKTS)) { netst->sntp = true; } else if (PMIx_Check_key(info[n].key, PMIX_NET_SENT_ERRS)) { netst->snte = true; } } } } void pmix_pstat_parse_ndstats(pmix_ndstats_t *ndst, pmix_info_t *info, size_t sz) { size_t n; if (NULL == info) { PMIX_NDSTATS_ALL(ndst); } else { PMIX_NDSTATS_INIT(ndst); for (n=0; n < sz; n++) { if (PMIx_Check_key(info[n].key, PMIX_NODE_LOAD_AVG)) { ndst->la = true; } else if (PMIx_Check_key(info[n].key, PMIX_NODE_LOAD_AVG5)) { ndst->la5 = true; } else if (PMIx_Check_key(info[n].key, PMIX_NODE_LOAD_AVG15)) { ndst->la15 = true; } else if (PMIx_Check_key(info[n].key, PMIX_NODE_MEM_TOTAL)) { ndst->mtot = true; } else if (PMIx_Check_key(info[n].key, PMIX_NODE_MEM_FREE)) { ndst->mfree = true; } else if (PMIx_Check_key(info[n].key, PMIX_NODE_MEM_BUFFERS)) { ndst->mbuf = true; } else if (PMIx_Check_key(info[n].key, PMIX_NODE_MEM_CACHED)) { ndst->mcached = true; } else if (PMIx_Check_key(info[n].key, PMIX_NODE_MEM_SWAP_CACHED)) { ndst->mswapcached = true; } else if (PMIx_Check_key(info[n].key, PMIX_NODE_SWAP_TOTAL)) { ndst->mswaptot = true; } else if (PMIx_Check_key(info[n].key, PMIX_NODE_MEM_SWAP_FREE)) { ndst->mswapfree = true; } else if (PMIx_Check_key(info[n].key, PMIX_NODE_MEM_MAPPED)) { ndst->mmap = true; } } } } pmix-6.1.1~rc2/src/mca/pstat/base/pstat_base_select.c0000664000175000017500000000440615203536752022725 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/mca/pstat/base/base.h" #include "src/mca/pstat/pstat.h" /* * Globals */ int pmix_pstat_base_select(void) { int ret, exit_status = PMIX_SUCCESS; pmix_pstat_base_component_t *best_component = NULL; pmix_pstat_base_module_t *best_module = NULL; /* * Select the best component */ if (PMIX_SUCCESS != pmix_mca_base_select("pstat", pmix_pstat_base_framework.framework_output, &pmix_pstat_base_framework.framework_components, (pmix_mca_base_module_t **) &best_module, (pmix_mca_base_component_t **) &best_component, NULL)) { /* It is okay if we don't find a runnable component - default * to the unsupported default. */ goto cleanup; } /* Save the winner */ pmix_pstat_base_component = best_component; pmix_pstat = *best_module; /* Initialize the winner */ if (PMIX_SUCCESS != (ret = pmix_pstat.init())) { exit_status = ret; goto cleanup; } cleanup: return exit_status; } pmix-6.1.1~rc2/src/mca/pstat/base/pstat_base_frame.c0000664000175000017500000001326015203536752022536 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2014-2019 Intel, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/mca/pstat/base/base.h" #include "src/mca/pstat/pstat.h" #include "src/runtime/pmix_progress_threads.h" #include "src/util/pmix_output.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public pmix_mca_base_component_t struct. */ #include "src/mca/pstat/base/static-components.h" /* unsupported functions */ static pmix_status_t pmix_pstat_base_unsupported_init(void); static pmix_status_t pmix_pstat_base_unsupported_query(pmix_proc_t *requestor, const pmix_info_t *monitor, pmix_status_t error, const pmix_info_t directives[], size_t ndirs, pmix_info_t **results, size_t *nresults); static pmix_status_t pmix_pstat_base_unsupported_finalize(void); /* * Globals */ pmix_pstat_base_component_t *pmix_pstat_base_component = NULL; pmix_pstat_base_module_t pmix_pstat = { pmix_pstat_base_unsupported_init, pmix_pstat_base_unsupported_query, pmix_pstat_base_unsupported_finalize }; pmix_pstat_base_t pmix_pstat_base = { .evbase = NULL, .ops = PMIX_LIST_STATIC_INIT }; static bool use_separate_thread = false; static int pmix_pstat_register(pmix_mca_base_register_flag_t flags) { (void) flags; (void) pmix_mca_base_var_register("pmix", "pstat", "base", "use_separate_thread", "Use a separate thread for monitoring local procs resource usage", PMIX_MCA_BASE_VAR_TYPE_BOOL, &use_separate_thread); return PMIX_SUCCESS; } /* Use default register/open/close functions */ static int pmix_pstat_base_close(void) { PMIX_LIST_DESTRUCT(&pmix_pstat_base.ops); /* let the selected module finalize */ if (NULL != pmix_pstat.finalize) { pmix_pstat.finalize(); } if (use_separate_thread && NULL != pmix_pstat_base.evbase) { (void) pmix_progress_thread_stop("PSTAT"); pmix_event_base_free(pmix_pstat_base.evbase); } return pmix_mca_base_framework_components_close(&pmix_pstat_base_framework, NULL); } static int pmix_pstat_base_open(pmix_mca_base_open_flag_t flags) { if (use_separate_thread) { /* create an event base and progress thread for us */ pmix_pstat_base.evbase = pmix_progress_thread_init("PSTAT"); if (NULL == pmix_pstat_base.evbase) { return PMIX_ERROR; } } else { pmix_pstat_base.evbase = pmix_globals.evbase; } PMIX_CONSTRUCT(&pmix_pstat_base.ops, pmix_list_t); /* Open up all available components */ return pmix_mca_base_framework_components_open(&pmix_pstat_base_framework, flags); } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, pstat, "process statistics", pmix_pstat_register, pmix_pstat_base_open, pmix_pstat_base_close, pmix_mca_pstat_base_static_components, 0); static pmix_status_t pmix_pstat_base_unsupported_init(void) { return PMIX_ERR_NOT_SUPPORTED; } static pmix_status_t pmix_pstat_base_unsupported_query(pmix_proc_t *requestor, const pmix_info_t *monitor, pmix_status_t error, const pmix_info_t directives[], size_t ndirs, pmix_info_t **results, size_t *nresults) { PMIX_HIDE_UNUSED_PARAMS(requestor, monitor, error, directives, ndirs, results, nresults); return PMIX_ERR_NOT_SUPPORTED; } static pmix_status_t pmix_pstat_base_unsupported_finalize(void) { return PMIX_ERR_NOT_SUPPORTED; } static void opcon(pmix_pstat_op_t *p) { p->id = NULL; p->active = false; p->rate = 0; PMIX_CONSTRUCT(&p->peers, pmix_list_t); p->disks = NULL; p->nets = NULL; PMIX_PROCSTATS_INIT(&p->pstats); PMIX_NDSTATS_INIT(&p->ndstats); PMIX_NETSTATS_INIT(&p->netstats); PMIX_DKSTATS_INIT(&p->dkstats); p->cb = NULL; } static void opdes(pmix_pstat_op_t *p) { if (p->active) { pmix_event_del(&p->ev); } if (NULL != p->id) { free(p->id); } PMIX_LIST_DESTRUCT(&p->peers); if (NULL != p->disks) { PMIx_Argv_free(p->disks); } if (NULL != p->nets) { PMIx_Argv_free(p->nets); } } PMIX_CLASS_INSTANCE(pmix_pstat_op_t, pmix_list_item_t, opcon, opdes); pmix-6.1.1~rc2/src/mca/pstat/base/base.h0000664000175000017500000001361715203536752020164 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PSTAT_BASE_H #define PMIX_PSTAT_BASE_H #include "pmix_config.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/pstat/pstat.h" /* * Global functions for MCA overall pstat open and close */ BEGIN_C_DECLS /** * Framework structure declaration for this framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_pstat_base_framework; /** * Select an available component. * * @return PMIX_SUCCESS Upon success. * @return PMIX_NOT_FOUND If no component can be selected. * @return PMIX_ERROR Upon other failure. * * At the end of this process, we'll either have a single * component that is selected and initialized, or no component was * selected. If no component was selected, subsequent invocation * of the pstat functions will return an error indicating no data * could be obtained */ PMIX_EXPORT int pmix_pstat_base_select(void); PMIX_EXPORT extern pmix_pstat_base_component_t *pmix_pstat_base_component; typedef struct { pmix_event_base_t *evbase; pmix_list_t ops; } pmix_pstat_base_t; PMIX_EXPORT extern pmix_pstat_base_t pmix_pstat_base; typedef struct { bool cmdline; bool pctcpu; bool state; bool time; bool pri; bool nthreads; bool cpu; bool vsize; bool pkvsize; bool rss; bool pss; } pmix_procstats_t; #define PMIX_PROCSTATS_INIT(a) \ memset(a, 0, sizeof(pmix_procstats_t)) #define PMIX_PROCSTATS_ALL(a) \ memset(a, 1, sizeof(pmix_procstats_t)) typedef struct { bool rdcompleted; bool rdmerged; bool rdsectors; bool rdms; bool wrtcompleted; bool wrtmerged; bool wrtsectors; bool wrtms; bool ioprog; bool ioms; bool ioweight; } pmix_dkstats_t; #define PMIX_DKSTATS_INIT(a) \ memset(a, 0, sizeof(pmix_dkstats_t)) #define PMIX_DKSTATS_ALL(a) \ memset(a, 1, sizeof(pmix_dkstats_t)) typedef struct { bool rcvdb; bool rcvdp; bool rcvde; bool sntb; bool sntp; bool snte; } pmix_netstats_t; #define PMIX_NETSTATS_INIT(a) \ memset(a, 0, sizeof(pmix_netstats_t)) #define PMIX_NETSTATS_ALL(a) \ memset(a, 1, sizeof(pmix_netstats_t)) typedef struct { bool la; bool la5; bool la15; bool mtot; bool mfree; bool mbuf; bool mcached; bool mswapcached; bool mswaptot; bool mswapfree; bool mmap; } pmix_ndstats_t; #define PMIX_NDSTATS_INIT(a) \ memset(a, 0, sizeof(pmix_ndstats_t)) #define PMIX_NDSTATS_ALL(a) \ memset(a, 1, sizeof(pmix_ndstats_t)) typedef struct { pmix_list_item_t super; pmix_proc_t requestor; char *id; pmix_event_t ev; struct timeval tv; bool active; uint32_t rate; pmix_status_t eventcode; pmix_list_t peers; char **disks; char **nets; pmix_procstats_t pstats; pmix_dkstats_t dkstats; pmix_netstats_t netstats; pmix_ndstats_t ndstats; pmix_cb_t *cb; } pmix_pstat_op_t; PMIX_CLASS_DECLARATION(pmix_pstat_op_t); // p - pmix_pstat_op_t* // s - time in seconds // cb - callback function that will execute the collection #define PMIX_PSTAT_OP_START(p, s, cb) \ do { \ pmix_event_evtimer_set(pmix_pstat_base.evbase, &(p)->ev, (cb), (p)); \ (p)->tv.tv_sec = (s); \ (p)->tv.tv_usec = 0; \ PMIX_OUTPUT_VERBOSE((1, pmix_pstat_base_framework.framework_output, \ "defining pstat event: %ld sec at %s:%d", \ (long) (p)->tv.tv_sec, __FILE__, __LINE__)); \ PMIX_POST_OBJECT(p); \ (p)->active = true; \ pmix_event_evtimer_add(&(p)->ev, &(p)->tv); \ } while (0); #define PMIX_PSTAT_APPEND_PEER_UNIQUE(pl, pr) \ do { \ bool f = false; \ pmix_peerlist_t *_p; \ PMIX_LIST_FOREACH(_p, pl, pmix_peerlist_t) { \ if (_p->peer == (pr)) { \ f = true; \ break; \ } \ } \ if (!f) { \ _p = PMIX_NEW(pmix_peerlist_t); \ _p->peer = (pr); \ pmix_list_append(pl, &(_p->super)); \ } \ } while(0) PMIX_EXPORT void pmix_pstat_parse_procstats(pmix_procstats_t *pst, pmix_info_t *info, size_t sz); PMIX_EXPORT void pmix_pstat_parse_dkstats(char ***disks, pmix_dkstats_t *dkst, pmix_info_t *info, size_t sz); PMIX_EXPORT void pmix_pstat_parse_netstats(char ***nets, pmix_netstats_t *netst, pmix_info_t *info, size_t sz); PMIX_EXPORT void pmix_pstat_parse_ndstats(pmix_ndstats_t *ndst, pmix_info_t *info, size_t sz); END_C_DECLS #endif /* PMIX_BASE_PSTAT_H */ pmix-6.1.1~rc2/src/mca/pstat/base/Makefile.am0000664000175000017500000000174315203536752021132 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2019 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers += \ base/base.h libmca_pstat_la_SOURCES += \ base/pstat_base_select.c \ base/pstat_base_frame.c \ base/pstat_base_fns.c pmix-6.1.1~rc2/src/mca/pstat/plinux/0000775000175000017500000000000015203536752017476 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pstat/plinux/owner.txt0000664000175000017500000000026015203536752021367 0ustar alastairalastair# # owner/status file # owner: institution that is responsible for this package # status: e.g. active, maintenance, unmaintained # owner: Nanook Consulting status: maintenance pmix-6.1.1~rc2/src/mca/pstat/plinux/pstat_plinux_component.c0000664000175000017500000000541415203536752024462 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "pmix_config.h" #include "pmix_common.h" #include "pstat_plinux.h" #include "src/mca/pstat/pstat.h" /* * Public string showing the pstat ompi_plinux component version number */ const char *pmix_pstat_plinux_component_version_string = "PMIX plinux pstat MCA component version " PMIX_VERSION; /* * Local function */ static int pstat_plinux_component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ const pmix_pstat_base_component_t pmix_mca_pstat_plinux_component = { PMIX_PSTAT_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "plinux", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), .pmix_mca_query_component = pstat_plinux_component_query, }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pstat, plinux) static int pstat_plinux_component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 80; *module = (pmix_mca_base_module_t *) &pmix_pstat_plinux_module; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pstat/plinux/pstat_plinux_module.c0000664000175000017500000014474515203536752023760 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2013 Los Alamos National Security, LLC. All rights reserved. * Copyright (c) 2013-2019 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" /* This component will only be compiled on Plinux, where we are guaranteed to have and friends */ #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_TIME_H # include #endif #include /* for HZ to convert jiffies to actual time */ #include "src/include/pmix_globals.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_printf.h" #include "src/mca/pstat/base/base.h" #include "pstat_plinux.h" /* * API functions */ static pmix_status_t plinux_module_init(void); static pmix_status_t query(pmix_proc_t *requestor, const pmix_info_t *monitor, pmix_status_t error, const pmix_info_t directives[], size_t ndirs, pmix_info_t **results, size_t *nresults); static pmix_status_t plinux_module_fini(void); /* * Plinux pstat module */ const pmix_pstat_base_module_t pmix_pstat_plinux_module = { /* Initialization function */ .init = plinux_module_init, .query = query, .finalize = plinux_module_fini }; #define PMIX_STAT_MAX_LENGTH 1024 /* Local functions */ static char *local_getline(FILE *fp); static char *local_stripper(char *data); static void local_getfields(char *data, char ***fields); /* Local data */ static char input[PMIX_STAT_MAX_LENGTH]; static pmix_status_t plinux_module_init(void) { return PMIX_SUCCESS; } static pmix_status_t plinux_module_fini(void) { return PMIX_SUCCESS; } static char *next_field(char *ptr, int barrier) { int i = 0; /* we are probably pointing to the last char * of the current field, so look for whitespace */ while (!isspace(*ptr) && i < barrier) { ptr++; /* step over the current char */ i++; } /* now look for the next field */ while (isspace(*ptr) && i < barrier) { ptr++; i++; } return ptr; } static float convert_value(char *value) { char *ptr; float fval; /* compute base value */ fval = (float) strtoul(value, &ptr, 10); /* get the unit multiplier */ if (NULL != ptr && NULL != strstr(ptr, "kB")) { fval /= 1024.0; } return fval; } static pmix_status_t proc_stat(void *answer, pmix_peer_t *peer, pmix_procstats_t *pst) { pmix_proc_t proc; pmix_status_t rc; char data[4096], state[2]; int fd; int32_t i32; size_t numchars; char *ptr, *eptr; int len, itime; float fval; double dtime; uint16_t u16; FILE *fp; char *dptr, *value; void *cache; struct timeval evtime; time_t sample_time; pmix_data_array_t darray; time(&sample_time); cache = PMIx_Info_list_start(); // start with the proc ID PMIx_Load_procid(&proc, peer->info->pname.nspace, peer->info->pname.rank); rc = PMIx_Info_list_add(cache, PMIX_PROCID, &proc, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } // add the pid rc = PMIx_Info_list_add(cache, PMIX_PROC_PID, &peer->info->pid, PMIX_PID); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } // add the hostname rc = PMIx_Info_list_add(cache, PMIX_HOSTNAME, pmix_globals.hostname, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } /* create the stat filename for this proc */ numchars = pmix_snprintf(data, sizeof(data), "/proc/%d/stat", peer->info->pid); if (numchars >= sizeof(data)) { PMIx_Info_list_release(cache); return PMIX_ERROR; } if (0 > (fd = open(data, O_RDONLY))) { /* can't access this file - most likely, this means we * aren't really on a supported system, or the proc no * longer exists. Just return an error */ PMIx_Info_list_release(cache); return PMIX_ERROR; } /* absorb all of the file's contents in one gulp - we'll process * it once it is in memory for speed */ memset(data, 0, sizeof(data)); len = read(fd, data, sizeof(data) - 1); if (len < 0) { /* This shouldn't happen! */ close(fd); PMIx_Info_list_release(cache); return PMIX_ERROR; } close(fd); /* remove newline at end */ data[len] = '\0'; /* the stat file consists of a single line in a carefully formatted * form. Parse it field by field as per proc(3) to get the ones we want */ /* the cmd is surrounded by parentheses - find the start */ if (NULL == (ptr = strchr(data, '('))) { /* no cmd => something wrong with data, return error */ PMIx_Info_list_release(cache); return PMIX_ERR_BAD_PARAM; } /* step over the paren */ ptr++; /* find the ending paren */ if (NULL == (eptr = strchr(ptr, ')'))) { /* no end to cmd => something wrong with data, return error */ PMIx_Info_list_release(cache); return PMIX_ERR_BAD_PARAM; } /* save the cmd name, up to the limit of the array */ *eptr = '\0'; if (pst->cmdline) { rc = PMIx_Info_list_add(cache, PMIX_CMD_LINE, ptr, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } *eptr = ')'; /* move to the next field in the data */ ptr = next_field(eptr, len); /* next is the process state - a single character */ state[0] = *ptr; state[1] = '\0'; if (pst->state) { rc = PMIx_Info_list_add(cache, PMIX_PROC_OS_STATE, state, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } /* move to next field */ ptr = next_field(ptr, len); /* skip fields until we get to the times */ ptr = next_field(ptr, len); /* ppid */ ptr = next_field(ptr, len); /* pgrp */ ptr = next_field(ptr, len); /* session */ ptr = next_field(ptr, len); /* tty_nr */ ptr = next_field(ptr, len); /* tpgid */ ptr = next_field(ptr, len); /* flags */ ptr = next_field(ptr, len); /* minflt */ ptr = next_field(ptr, len); /* cminflt */ ptr = next_field(ptr, len); /* majflt */ ptr = next_field(ptr, len); /* cmajflt */ /* grab the process time usage fields */ itime = strtoul(ptr, &ptr, 10); /* utime */ itime += strtoul(ptr, &ptr, 10); /* add the stime */ /* convert to time in seconds */ dtime = (double) itime / (double) HZ; evtime.tv_sec = (int) dtime; evtime.tv_usec = (int) (1000000.0 * (dtime - evtime.tv_sec)); if (pst->time) { rc = PMIx_Info_list_add(cache, PMIX_PROC_TIME, (void*)&evtime, PMIX_TIMEVAL); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } /* move to next field */ ptr = next_field(ptr, len); /* skip fields until we get to priority */ ptr = next_field(ptr, len); /* cutime */ ptr = next_field(ptr, len); /* cstime */ /* save the priority */ i32 = strtol(ptr, &ptr, 10); if (pst->pri) { rc = PMIx_Info_list_add(cache, PMIX_PROC_PRIORITY, &i32, PMIX_INT32); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } /* move to next field */ ptr = next_field(ptr, len); /* skip nice */ ptr = next_field(ptr, len); /* get number of threads */ u16 = strtoul(ptr, &ptr, 10); if (pst->nthreads) { rc = PMIx_Info_list_add(cache, PMIX_PROC_NUM_THREADS, &u16, PMIX_UINT16); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } /* move to next field */ ptr = next_field(ptr, len); /* skip fields until we get to processor id */ ptr = next_field(ptr, len); /* itrealvalue */ ptr = next_field(ptr, len); /* starttime */ ptr = next_field(ptr, len); /* vsize */ ptr = next_field(ptr, len); /* rss */ ptr = next_field(ptr, len); /* rss limit */ ptr = next_field(ptr, len); /* startcode */ ptr = next_field(ptr, len); /* endcode */ ptr = next_field(ptr, len); /* startstack */ ptr = next_field(ptr, len); /* kstkesp */ ptr = next_field(ptr, len); /* kstkeip */ ptr = next_field(ptr, len); /* signal */ ptr = next_field(ptr, len); /* blocked */ ptr = next_field(ptr, len); /* sigignore */ ptr = next_field(ptr, len); /* sigcatch */ ptr = next_field(ptr, len); /* wchan */ ptr = next_field(ptr, len); /* nswap */ ptr = next_field(ptr, len); /* cnswap */ ptr = next_field(ptr, len); /* exit_signal */ /* finally - get the processor */ u16 = strtol(ptr, NULL, 10); if (pst->cpu) { rc = PMIx_Info_list_add(cache, PMIX_PROC_CPU, &u16, PMIX_UINT16); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } } /* that's all we care about from this data - ignore the rest */ /* now create the status filename for this proc */ memset(data, 0, sizeof(data)); numchars = pmix_snprintf(data, sizeof(data), "/proc/%d/status", peer->info->pid); if (numchars >= sizeof(data)) { PMIx_Info_list_release(cache); return PMIX_ERROR; } if (NULL == (fp = fopen(data, "r"))) { /* ignore this */ goto complete; } /* parse it according to proc(3) */ while (NULL != (dptr = local_getline(fp))) { if (NULL == (value = local_stripper(dptr))) { /* cannot process */ continue; } /* look for VmPeak */ if (0 == strncmp(dptr, "VmPeak", strlen("VmPeak"))) { if (pst->pkvsize) { fval = convert_value(value); rc = PMIx_Info_list_add(cache, PMIX_PROC_PEAK_VSIZE, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); fclose(fp); return rc; } } } else if (0 == strncmp(dptr, "VmSize", strlen("VmSize"))) { if (pst->vsize) { fval = convert_value(value); rc = PMIx_Info_list_add(cache, PMIX_PROC_VSIZE, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); fclose(fp); return rc; } } } else if (0 == strncmp(dptr, "VmRSS", strlen("VmRSS"))) { if (pst->rss) { fval = convert_value(value); rc = PMIx_Info_list_add(cache, PMIX_PROC_RSS, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); fclose(fp); return rc; } } } } fclose(fp); /* now create the smaps filename for this proc */ memset(data, 0, sizeof(data)); numchars = pmix_snprintf(data, sizeof(data), "/proc/%d/smaps", peer->info->pid); if (numchars >= sizeof(data)) { PMIx_Info_list_release(cache); return PMIX_ERROR; } if (NULL == (fp = fopen(data, "r"))) { /* ignore this */ goto complete; } /* parse it to find lines that start with "Pss" */ fval = 0.0; while (NULL != (dptr = local_getline(fp))) { if (NULL == (value = local_stripper(dptr))) { /* cannot process */ continue; } /* look for Pss */ if (0 == strncmp(dptr, "Pss", strlen("Pss"))) { fval += convert_value(value); } } if (0.0 < fval && pst->pss) { rc = PMIx_Info_list_add(cache, PMIX_PROC_PSS, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); fclose(fp); return rc; } } fclose(fp); complete: // record the sample time rc = PMIx_Info_list_add(cache, PMIX_PROC_SAMPLE_TIME, &sample_time, PMIX_TIME); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); return rc; } // add this to the final answer rc = PMIx_Info_list_convert(cache, &darray); PMIx_Info_list_release(cache); if (PMIX_SUCCESS != rc) { return rc; } rc = PMIx_Info_list_add(answer, PMIX_PROC_RESOURCE_USAGE, &darray, PMIX_DATA_ARRAY); return rc; } static pmix_status_t disk_stat(void *answer, char **disks, pmix_dkstats_t *dkst) { FILE *fp; char *dptr; char **fields = NULL; void *cache; size_t n; bool takeit; uint64_t u64; pmix_data_array_t darray; time_t sample_time; pmix_status_t rc; /* look for the diskstats file */ if (NULL == (fp = fopen("/proc/diskstats", "r"))) { /* not an error if we don't find this one as it * isn't critical */ return PMIX_ERR_NOT_FOUND; } /* read the file one line at a time */ while (NULL != (dptr = local_getline(fp))) { /* look for the local disks */ if (NULL == strstr(dptr, "sd")) { continue; } /* parse to extract the fields */ fields = NULL; local_getfields(dptr, &fields); if (NULL == fields) { continue; } if (14 < PMIx_Argv_count(fields)) { PMIx_Argv_free(fields); continue; } // see if this is a disk they want if (NULL == disks) { takeit = true; } else { takeit = false; for (n=0; NULL != disks[n]; n++) { if (0 == strcmp(fields[2], disks[n])) { takeit = true; break; } } } if (!takeit) { PMIx_Argv_free(fields); continue; } time(&sample_time); /* take the fields of interest */ cache = PMIx_Info_list_start(); // start with the diskID rc = PMIx_Info_list_add(cache, PMIX_DISK_ID, fields[2], PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } if (dkst->rdcompleted) { u64 = strtoul(fields[3], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_DISK_READ_COMPLETED, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (dkst->rdmerged) { u64 = strtoul(fields[4], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_DISK_READ_MERGED, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (dkst->rdsectors) { u64 = strtoul(fields[5], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_DISK_READ_SECTORS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (dkst->rdms) { u64 = strtoul(fields[6], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_DISK_READ_MILLISEC, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (dkst->wrtcompleted) { u64 = strtoul(fields[7], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_DISK_WRITE_COMPLETED, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (dkst->wrtmerged) { u64 = strtoul(fields[8], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_DISK_WRITE_MERGED, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (dkst->wrtsectors) { u64 = strtoul(fields[9], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_DISK_WRITE_SECTORS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (dkst->wrtms) { u64 = strtoul(fields[10], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_DISK_WRITE_MILLISEC, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (dkst->ioprog) { u64 = strtoul(fields[10], NULL, 11); rc = PMIx_Info_list_add(cache, PMIX_DISK_IO_IN_PROGRESS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (dkst->ioms) { u64 = strtoul(fields[10], NULL, 12); rc = PMIx_Info_list_add(cache, PMIX_DISK_IO_MILLISEC, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (dkst->ioweight) { u64 = strtoul(fields[10], NULL, 13); rc = PMIx_Info_list_add(cache, PMIX_DISK_IO_WEIGHTED, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } // record the sample time rc = PMIx_Info_list_add(cache, PMIX_DISK_SAMPLE_TIME, &sample_time, PMIX_TIME); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } // add this to the final answer rc = PMIx_Info_list_convert(cache, &darray); PMIx_Info_list_release(cache); PMIx_Argv_free(fields); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } rc = PMIx_Info_list_add(answer, PMIX_DISK_RESOURCE_USAGE, &darray, PMIX_DATA_ARRAY); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } } fclose(fp); return PMIX_SUCCESS; } static pmix_status_t net_stat(void *answer, char**nets, pmix_netstats_t *netst) { FILE *fp; char *dptr, *ptr; char **fields; void *cache; size_t n; bool takeit; uint64_t u64; pmix_data_array_t darray; time_t sample_time; pmix_status_t rc; /* look for the netstats file */ if (NULL == (fp = fopen("/proc/net/dev", "r"))) { /* not an error if we don't find this one as it * isn't critical */ return PMIX_ERR_NOT_FOUND; } /* skip the first two lines as they are headers */ local_getline(fp); local_getline(fp); /* read the file one line at a time */ while (NULL != (dptr = local_getline(fp))) { /* the interface is at the start of the line */ if (NULL == (ptr = strchr(dptr, ':'))) { continue; } *ptr = '\0'; ptr++; /* parse to extract the fields */ fields = NULL; local_getfields(ptr, &fields); if (NULL == fields) { continue; } if (11 < PMIx_Argv_count(fields)) { PMIx_Argv_free(fields); continue; } // see if this is a network they want if (NULL == nets) { takeit = true; } else { takeit = false; for (n=0; NULL != nets[n]; n++) { if (0 == strcmp(dptr, nets[n])) { takeit = true; break; } } } if (!takeit) { PMIx_Argv_free(fields); continue; } time(&sample_time); /* take the fields of interest */ cache = PMIx_Info_list_start(); // start with the network ID rc = PMIx_Info_list_add(cache, PMIX_NETWORK_ID, dptr, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } if (netst->rcvdb) { u64 = strtoul(fields[0], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_NET_RECVD_BYTES, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (netst->rcvdp) { u64 = strtoul(fields[1], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_NET_RECVD_PCKTS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (netst->rcvde) { u64 = strtoul(fields[2], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_NET_RECVD_ERRS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (netst->sntb) { u64 = strtoul(fields[8], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_NET_SENT_BYTES, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (netst->sntp) { u64 = strtoul(fields[9], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_NET_SENT_PCKTS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } if (netst->snte) { u64 = strtoul(fields[10], NULL, 10); rc = PMIx_Info_list_add(cache, PMIX_NET_SENT_ERRS, &u64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } } // record the sample time rc = PMIx_Info_list_add(cache, PMIX_NET_SAMPLE_TIME, &sample_time, PMIX_TIME); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cache); PMIx_Argv_free(fields); fclose(fp); return rc; } // add this to the final answer rc = PMIx_Info_list_convert(cache, &darray); PMIx_Info_list_release(cache); PMIx_Argv_free(fields); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } rc = PMIx_Info_list_add(answer, PMIX_NETWORK_RESOURCE_USAGE, &darray, PMIX_DATA_ARRAY); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } } fclose(fp); return PMIX_SUCCESS; } static pmix_status_t node_stat(void *ilist, pmix_ndstats_t *ndst) { int fd; FILE *fp; char data[4096], *ptr, *value, *dptr, *eptr; int len; float fval; pmix_status_t rc; time_t sample_time; time(&sample_time); /* get the loadavg data */ if (0 > (fd = open("/proc/loadavg", O_RDONLY))) { /* not an error if we don't find this one as it * isn't critical */ return PMIX_ERR_NOT_FOUND; } /* absorb all of the file's contents in one gulp - we'll process * it once it is in memory for speed */ memset(data, 0, sizeof(data)); len = read(fd, data, sizeof(data) - 1); close(fd); if (len < 0) { return PMIX_ERR_FILE_READ_FAILURE; } /* remove newline at end */ data[len] = '\0'; /* we only care about the first three numbers */ fval = strtof(data, &ptr); if (ndst->la) { rc = PMIx_Info_list_add(ilist, PMIX_NODE_LOAD_AVG, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } fval = strtof(ptr, &eptr); if (ndst->la5) { rc = PMIx_Info_list_add(ilist, PMIX_NODE_LOAD_AVG5, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } fval = strtof(eptr, NULL); if (ndst->la15) { rc = PMIx_Info_list_add(ilist, PMIX_NODE_LOAD_AVG15, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { return rc; } } /* see if we can open the meminfo file */ if (NULL == (fp = fopen("/proc/meminfo", "r"))) { /* ignore this */ return PMIX_ERR_NOT_FOUND; } /* read the file one line at a time */ while (NULL != (dptr = local_getline(fp))) { if (NULL == (value = local_stripper(dptr))) { /* cannot process */ continue; } if (0 == strcmp(dptr, "MemTotal")) { if (ndst->mtot) { fval = convert_value(value); rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_TOTAL, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } } } else if (0 == strcmp(dptr, "MemFree")) { if (ndst->mfree) { fval = convert_value(value); rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_FREE, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } } } else if (0 == strcmp(dptr, "Buffers")) { if (ndst->mbuf) { fval = convert_value(value); rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_BUFFERS, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } } } else if (0 == strcmp(dptr, "Cached")) { if (ndst->mcached) { fval = convert_value(value); rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_CACHED, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } } } else if (0 == strcmp(dptr, "SwapCached")) { if (ndst->mswapcached) { fval = convert_value(value); rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_SWAP_CACHED, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } } } else if (0 == strcmp(dptr, "SwapTotal")) { if (ndst->mswaptot) { fval = convert_value(value); rc = PMIx_Info_list_add(ilist, PMIX_NODE_SWAP_TOTAL, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } } } else if (0 == strcmp(dptr, "SwapFree")) { if (ndst->mswapfree) { fval = convert_value(value); rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_SWAP_FREE, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } } } else if (0 == strcmp(dptr, "Mapped")) { if (ndst->mmap) { fval = convert_value(value); rc = PMIx_Info_list_add(ilist, PMIX_NODE_MEM_MAPPED, &fval, PMIX_FLOAT); if (PMIX_SUCCESS != rc) { fclose(fp); return rc; } } } } fclose(fp); rc = PMIx_Info_list_add(ilist, PMIX_NODE_SAMPLE_TIME, &sample_time, PMIX_TIME); return rc; } static void evrelease(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t*)cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_RELEASE(cb); } static void update(int sd, short args, void *cbdata) { pmix_pstat_op_t *op = (pmix_pstat_op_t*)cbdata; void *answer, *ilist; pmix_peerlist_t *plist; pmix_status_t rc; pmix_data_array_t darray; pmix_cb_t *cb; pmix_procstats_t zproc; pmix_ndstats_t znd; pmix_netstats_t znet; pmix_dkstats_t zdk; bool nettaken, dktaken, noreset; PMIX_HIDE_UNUSED_PARAMS(sd, args); cb = op->cb; if (NULL == cb) { answer = PMIx_Info_list_start(); noreset = false; } else { answer = cb->cbdata; noreset = true; } PMIX_PROCSTATS_INIT(&zproc); PMIX_NDSTATS_INIT(&znd); PMIX_NETSTATS_INIT(&znet); PMIX_DKSTATS_INIT(&zdk); nettaken = false; dktaken = false; // start with general directives if (op->active) { // avoid the default event PMIX_INFO_LIST_ADD(rc, answer, PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); /* target this notification solely to the requestor */ PMIX_INFO_LIST_ADD(rc, answer, PMIX_EVENT_CUSTOM_RANGE, &op->requestor, PMIX_PROC); } // check for pstat request if (0 != memcmp(&op->pstats, &zproc, sizeof(pmix_procstats_t))) { PMIX_LIST_FOREACH(plist, &op->peers, pmix_peerlist_t) { rc = proc_stat(answer, plist->peer, &op->pstats); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIx_Info_list_release(answer); goto reset; } } } // check for node stats if (0 != memcmp(&op->ndstats, &znd, sizeof(pmix_ndstats_t))) { ilist = PMIx_Info_list_start(); // start with hostname rc = PMIx_Info_list_add(ilist, PMIX_HOSTNAME, pmix_globals.hostname, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } // add our nodeID rc = PMIx_Info_list_add(ilist, PMIX_NODEID, &pmix_globals.nodeid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } // collect the stats rc = node_stat(ilist, &op->ndstats); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } if (0 != memcmp(&op->netstats, &znet, sizeof(pmix_netstats_t))) { nettaken = true; rc = net_stat(ilist, op->nets, &op->netstats); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } } if (0 != memcmp(&op->dkstats, &zdk, sizeof(pmix_dkstats_t))) { dktaken = true; rc = disk_stat(ilist, op->disks, &op->dkstats); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } } // add this to the final answer rc = PMIx_Info_list_convert(ilist, &darray); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); PMIx_Info_list_release(answer); goto reset; } PMIx_Info_list_release(ilist); rc = PMIx_Info_list_add(answer, PMIX_NODE_RESOURCE_USAGE, &darray, PMIX_DATA_ARRAY); PMIX_DATA_ARRAY_DESTRUCT(&darray); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(answer); goto reset; } } // check for net stats if (!nettaken && 0 != memcmp(&op->netstats, &znet, sizeof(pmix_netstats_t))) { rc = net_stat(answer, op->nets, &op->netstats); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(answer); goto reset; } } // check for disk stats if (!dktaken && 0 != memcmp(&op->dkstats, &zdk, sizeof(pmix_dkstats_t))) { rc = disk_stat(answer, op->disks, &op->dkstats); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(answer); goto reset; } } if (NULL == cb) { // convert to info array rc = PMIx_Info_list_convert(answer, &darray); PMIx_Info_list_release(answer); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto reset; } // setup the event cb = PMIX_NEW(pmix_cb_t); cb->info = (pmix_info_t*)darray.array; cb->ninfo = darray.size; cb->infocopy = true; rc = PMIx_Notify_event(op->eventcode, &pmix_globals.myid, PMIX_RANGE_CUSTOM, cb->info, cb->ninfo, evrelease, (void*)cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } reset: if (!noreset) { // reset the timer pmix_event_evtimer_add(&op->ev, &op->tv); } } static pmix_status_t query(pmix_proc_t *requestor, const pmix_info_t *monitor, pmix_status_t eventcode, const pmix_info_t directives[], size_t ndirs, pmix_info_t **results, size_t *nresults) { pmix_info_t *iptr; size_t sz; size_t n, m; int k; pmix_peer_t *ptr; pmix_proc_t proc, *procs; pmix_node_pid_t *ppid; pmix_status_t rc; bool tgtprocsgiven; pmix_data_array_t darray; pmix_pstat_op_t *op; pmix_netstats_t znet; pmix_dkstats_t zdk; pmix_info_t *xfer; pmix_cb_t cb; *results = NULL; *nresults = 0; PMIX_NETSTATS_INIT(&znet); PMIX_DKSTATS_INIT(&zdk); if (PMIx_Check_key(monitor->key, PMIX_MONITOR_CANCEL)) { // cancel an existing monitor operation - ID must be the provided value if (monitor->value.type != PMIX_STRING) { return PMIX_ERR_BAD_PARAM; } // cycle through our list of ops operations if (0 == pmix_list_get_size(&pmix_pstat_base.ops)) { // we don't have any operations - this is okay return PMIX_SUCCESS; } PMIX_LIST_FOREACH(op, &pmix_pstat_base.ops, pmix_pstat_op_t) { if (0 == strcmp(monitor->value.data.string, op->id)) { // terminate this operation pmix_list_remove_item(&pmix_pstat_base.ops, &op->super); PMIX_RELEASE(op); return PMIX_SUCCESS; } } // didn't find the operation - this is okay return PMIX_SUCCESS; } op = PMIX_NEW(pmix_pstat_op_t); memcpy(&op->requestor, requestor, sizeof(pmix_proc_t)); op->eventcode = eventcode; for (n=0; n < ndirs; n++) { // did they give us an ID for this request? if (PMIx_Check_key(directives[n].key, PMIX_MONITOR_ID)) { op->id = strdup(directives[n].value.data.string); } else if (PMIx_Check_key(directives[n].key, PMIX_MONITOR_RESOURCE_RATE)) { // they are asking us to update it at regular intervals rc = PMIx_Value_get_number(&directives[n].value, (void*)&op->rate, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(op); return rc; } } if (NULL != op->id && 0 < op->rate) { // don't keep searching if unnecessary break; } } // see what data we are being asked to collect if (PMIx_Check_key(monitor->key, PMIX_MONITOR_PROC_RESOURCE_USAGE)) { tgtprocsgiven = false; // see which values are to be returned iptr = (pmix_info_t*)monitor->value.data.darray->array; sz = monitor->value.data.darray->size; pmix_pstat_parse_procstats(&op->pstats, iptr, sz); // we already know this request involves us since it was checked // before calling us, so see which of our processes are included if (NULL == directives) { // all of our processes are included - no ID or rate can be included for (k=0; k < pmix_server_globals.clients.size; k++) { ptr = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, k); if (NULL == ptr) { continue; } PMIX_PSTAT_APPEND_PEER_UNIQUE(&op->peers, ptr); } goto processprocs; } // check for specific procs and directives for (n=0; n < ndirs; n++) { if (PMIx_Check_key(directives[n].key, PMIX_MONITOR_TARGET_PROCS)) { if (PMIX_DATA_ARRAY != directives[n].value.type || NULL == directives[n].value.data.darray || NULL == directives[n].value.data.darray->array) { PMIX_RELEASE(op); return PMIX_ERR_BAD_PARAM; } tgtprocsgiven = true; // they specified the procs procs = (pmix_proc_t*)directives[n].value.data.darray->array; sz = directives[n].value.data.darray->size; for (m=0; m < sz; m++) { for (k=0; k < pmix_server_globals.clients.size; k++) { ptr = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, k); if (NULL == ptr) { continue; } PMIx_Load_procid(&proc, ptr->info->pname.nspace, ptr->info->pname.rank); if (PMIx_Check_procid(&procs[m], &proc)) { PMIX_PSTAT_APPEND_PEER_UNIQUE(&op->peers, ptr); break; } } } } if (PMIx_Check_key(directives[n].key, PMIX_MONITOR_TARGET_PIDS)) { if (PMIX_DATA_ARRAY != directives[n].value.type || NULL == directives[n].value.data.darray || NULL == directives[n].value.data.darray->array) { PMIX_RELEASE(op); return PMIX_ERR_BAD_PARAM; } tgtprocsgiven = true; // is our node included? ppid = (pmix_node_pid_t*)directives[n].value.data.darray->array; sz = directives[n].value.data.darray->size; for (m=0; m < sz; m++) { // see if this node is us if (ppid[m].nodeid == pmix_globals.nodeid || pmix_check_local(ppid[m].hostname)) { // is this one of our procs? for (k=0; k < pmix_server_globals.clients.size; k++) { ptr = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, k); if (NULL == ptr) { continue; } if (ppid[m].pid == ptr->info->pid) { PMIX_PSTAT_APPEND_PEER_UNIQUE(&op->peers, ptr); break; } } } } } } // when we come out of the loop, it is possible that we were not // given any target procs via any of the attributes. In this case, // we assume that we are to take all local procs if (!tgtprocsgiven) { for (k=0; k < pmix_server_globals.clients.size; k++) { ptr = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, k); if (NULL == ptr) { continue; } PMIX_PSTAT_APPEND_PEER_UNIQUE(&op->peers, ptr); } } processprocs: PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.cbdata = PMIx_Info_list_start(); op->cb = &cb; update(0, 0, (void*)op); // convert to info array rc = PMIx_Info_list_convert(cb.cbdata, &darray); PMIx_Info_list_release(cb.cbdata); PMIX_DESTRUCT(&cb); op->cb = NULL; if (PMIX_SUCCESS != rc) { PMIX_DATA_ARRAY_DESTRUCT(&darray); PMIX_RELEASE(op); if (PMIX_ERR_EMPTY == rc) { // this is not an error rc = PMIX_SUCCESS; } return rc; } *results = (pmix_info_t*)darray.array; *nresults = darray.size; // if we were given a rate, then setup the event to generate // the requested updates if (0 < op->rate) { pmix_list_append(&pmix_pstat_base.ops, &op->super); PMIX_PSTAT_OP_START(op, op->rate, update); } else { // otherwise, this was a one-time request, so we are done with the op PMIX_RELEASE(op); } return PMIX_SUCCESS; } if (PMIx_Check_key(monitor->key, PMIX_MONITOR_NODE_RESOURCE_USAGE)) { // we already know we are a target node since we are // being called iptr = (pmix_info_t*)monitor->value.data.darray->array; sz = monitor->value.data.darray->size; // determine what stats to return - might include net and disk values pmix_pstat_parse_ndstats(&op->ndstats, iptr, sz); pmix_pstat_parse_netstats(&op->nets, &op->netstats, iptr, sz); pmix_pstat_parse_dkstats(&op->disks, &op->dkstats, iptr, sz); // start collecting response PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.cbdata = PMIx_Info_list_start(); op->cb = &cb; // start with hostname rc = PMIx_Info_list_add(cb.cbdata, PMIX_HOSTNAME, pmix_globals.hostname, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cb.cbdata); op->cb = NULL; PMIX_DESTRUCT(&cb); PMIX_RELEASE(op); return rc; } // add our nodeID rc = PMIx_Info_list_add(cb.cbdata, PMIX_NODEID, &pmix_globals.nodeid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cb.cbdata); op->cb = NULL; PMIX_DESTRUCT(&cb); PMIX_RELEASE(op); return rc; } // collect the stats update(0, 0, (void*)op); // add this to the final answer rc = PMIx_Info_list_convert(cb.cbdata, &darray); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(cb.cbdata); op->cb = NULL; PMIX_DESTRUCT(&cb); PMIX_RELEASE(op); return rc; } // if the array has only two items in it, then those are the hostname // and nodeID we provided and not any data - this is equivalent to // "empty" as no data was found PMIx_Info_list_release(cb.cbdata); PMIX_DESTRUCT(&cb); op->cb = NULL; // if the array has only two items in it, then those are the hostname // and nodeID we provided and not any data - this is equivalent to // "empty" as no data was found if (3 > darray.size) { PMIX_DATA_ARRAY_DESTRUCT(&darray); PMIX_RELEASE(op); return PMIX_SUCCESS; } PMIX_INFO_CREATE(xfer, 1); PMIX_INFO_LOAD(xfer, PMIX_NODE_RESOURCE_USAGE, &darray, PMIX_DATA_ARRAY); PMIX_DATA_ARRAY_DESTRUCT(&darray); *results = xfer; *nresults = 1; // if we were given a rate, then setup the event to generate // the requested updates if (0 < op->rate) { pmix_list_append(&pmix_pstat_base.ops, &op->super); PMIX_PSTAT_OP_START(op, op->rate, update); } else { // otherwise, this was a one-time request, so we are done with the op PMIX_RELEASE(op); } return PMIX_SUCCESS; } if (PMIx_Check_key(monitor->key, PMIX_MONITOR_DISK_RESOURCE_USAGE)) { // we already know we are a target node since we are // being called iptr = (pmix_info_t*)monitor->value.data.darray->array; sz = monitor->value.data.darray->size; // assemble any provided disk IDs and/or stat specifications pmix_pstat_parse_dkstats(&op->disks, &op->dkstats, iptr, sz); // collect the stats PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.cbdata = PMIx_Info_list_start(); op->cb = &cb; update(0, 0, (void*)op); // convert to info array rc = PMIx_Info_list_convert(cb.cbdata, &darray); PMIx_Info_list_release(cb.cbdata); PMIX_DESTRUCT(&cb); op->cb = NULL; if (PMIX_SUCCESS != rc) { PMIX_DATA_ARRAY_DESTRUCT(&darray); PMIX_RELEASE(op); if (PMIX_ERR_EMPTY == rc) { // empty = nothing found, not an error rc = PMIX_SUCCESS; } return rc; } *results = (pmix_info_t*)darray.array; *nresults = darray.size; // if we were given a rate, then setup the event to generate // the requested updates if (0 < op->rate) { pmix_list_append(&pmix_pstat_base.ops, &op->super); PMIX_PSTAT_OP_START(op, op->rate, update); } else { // otherwise, this was a one-time request, so we are done with the op PMIX_RELEASE(op); } return PMIX_SUCCESS; } if (PMIx_Check_key(monitor->key, PMIX_MONITOR_NET_RESOURCE_USAGE)) { // we already know we are a target node since we are // being called iptr = (pmix_info_t*)monitor->value.data.darray->array; sz = monitor->value.data.darray->size; // assemble any provided network IDs and/or stat specifications pmix_pstat_parse_netstats(&op->nets, &op->netstats, iptr, sz); // collect the stats PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.cbdata = PMIx_Info_list_start(); op->cb = &cb; update(0, 0, (void*)op); // convert to info array rc = PMIx_Info_list_convert(cb.cbdata, &darray); PMIx_Info_list_release(cb.cbdata); PMIX_DESTRUCT(&cb); op->cb = NULL; if (PMIX_SUCCESS != rc) { PMIX_RELEASE(op); if (PMIX_ERR_EMPTY == rc) { // empty = nothing found, not an error rc = PMIX_SUCCESS; } return rc; } *results = (pmix_info_t*)darray.array; *nresults = darray.size; // if we were given a rate, then setup the event to generate // the requested updates if (0 < op->rate) { pmix_list_append(&pmix_pstat_base.ops, &op->super); PMIX_PSTAT_OP_START(op, op->rate, update); } else { // otherwise, this was a one-time request, so we are done with the op PMIX_RELEASE(op); } return PMIX_SUCCESS; } return PMIX_SUCCESS; } static char *local_getline(FILE *fp) { char *ret, *ptr; ret = fgets(input, PMIX_STAT_MAX_LENGTH, fp); if (NULL != ret) { input[strlen(input) - 1] = '\0'; /* remove newline */ /* strip leading white space */ ptr = input; while (!isalnum(*ptr)) { ptr++; } return ptr; } return NULL; } static char *local_stripper(char *data) { char *ptr, *end, *enddata; int len = strlen(data); /* find the colon */ if (NULL == (end = strchr(data, ':'))) { return NULL; } ptr = end; --end; /* working backwards, look for first non-whitespace */ while (end != data && !isalnum(*end)) { --end; } ++end; *end = '\0'; /* now look for value */ ptr++; enddata = &(data[len - 1]); while (ptr != enddata && !isalnum(*ptr)) { ++ptr; } return ptr; } static void local_getfields(char *dptr, char ***fields) { char *ptr, *end; /* set default */ *fields = NULL; /* find the beginning */ ptr = dptr; while ('\0' != *ptr && !isalnum(*ptr)) { ptr++; } if ('\0' == *ptr) { return; } /* working from this point, find the end of each * alphanumeric field and store it on the stack. * Then shift across the white space to the start * of the next one */ end = ptr; /* ptr points to an alnum */ end++; /* look at next character */ while ('\0' != *end) { /* find the end of this alpha string */ while ('\0' != *end && isalnum(*end)) { end++; } /* terminate it */ *end = '\0'; /* store it on the stack */ PMIx_Argv_append_nosize(fields, ptr); /* step across any white space */ end++; while ('\0' != *end && !isalnum(*end)) { end++; } if ('\0' == *end) { ptr = NULL; break; } ptr = end; end++; } if (NULL != ptr) { /* have a hanging field */ PMIx_Argv_append_nosize(fields, ptr); } } pmix-6.1.1~rc2/src/mca/pstat/plinux/configure.m40000664000175000017500000000313315203536752021721 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2010-2020 Cisco Systems, Inc. All rights reserved # Copyright (c) 2019 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_pstat_linux_CONFIG(action-if-can-compile, # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pstat_plinux_CONFIG],[ AC_CONFIG_FILES([src/mca/pstat/plinux/Makefile]) AS_IF([test "$oac_found_linux" = "yes" && test -r "/proc/cpuinfo"], [pstat_plinux_happy="yes"], [pstat_plinux_happy="no"]) AS_IF([test "$pstat_plinux_happy" = "yes"], [AC_CHECK_DECLS([HZ], [], [pstat_plinux_happy="no"], [AC_INCLUDES_DEFAULT #include ])]) AS_IF([test "$pstat_plinux_happy" = "yes"], [$1], [$2]) ]) pmix-6.1.1~rc2/src/mca/pstat/plinux/pstat_plinux.h0000664000175000017500000000302115203536752022375 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Processor stats for Posix systems. * */ #ifndef pmix_pstat_PLINUX_EXPORT_H #define pmix_pstat_PLINUX_EXPORT_H #include "pmix_config.h" #include "src/mca/mca.h" #include "src/mca/pstat/pstat.h" BEGIN_C_DECLS /** * Globally exported variable */ PMIX_EXPORT extern const pmix_pstat_base_component_t pmix_mca_pstat_plinux_component; PMIX_EXPORT extern const pmix_pstat_base_module_t pmix_pstat_plinux_module; END_C_DECLS #endif /* pmix_pstat_PLINUX_EXPORT_H */ pmix-6.1.1~rc2/src/mca/pstat/plinux/Makefile.am0000664000175000017500000000341115203536752021531 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2010-2020 Cisco Systems, Inc. All rights reserved # Copyright (c) 2017 IBM Corporation. All rights reserved. # Copyright (c) 2019-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # sources = \ pstat_plinux.h \ pstat_plinux_component.c \ pstat_plinux_module.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pstat_plinux_DSO component_noinst = component_install = pmix_mca_pstat_plinux.la else component_noinst = libpmix_mca_pstat_plinux.la component_install = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component_install) pmix_mca_pstat_plinux_la_SOURCES = $(sources) pmix_mca_pstat_plinux_la_LDFLAGS = -module -avoid-version pmix_mca_pstat_plinux_la_LIBADD = $(top_builddir)/src/libpmix.la noinst_LTLIBRARIES = $(component_noinst) libpmix_mca_pstat_plinux_la_SOURCES =$(sources) libpmix_mca_pstat_plinux_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/pstat/pstat.h0000664000175000017500000000457715203536752017500 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2007 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2008 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * pstat (process statistics) framework component interface. * * Intent * * To support the ompi-top utility. * */ #ifndef PMIX_MCA_PSTAT_H #define PMIX_MCA_PSTAT_H #include "pmix_config.h" #include "pmix_common.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" BEGIN_C_DECLS /** * Module initialization function. Should return PMIX_SUCCESS. */ typedef pmix_status_t (*pmix_pstat_base_module_init_fn_t)(void); typedef pmix_status_t (*pmix_pstat_base_module_query_fn_t)(pmix_proc_t *requestor, const pmix_info_t *monitor, pmix_status_t error, const pmix_info_t directives[], size_t ndirs, pmix_info_t **results, size_t *nresults); typedef pmix_status_t (*pmix_pstat_base_module_fini_fn_t)(void); /** * Structure for pstat components. */ typedef pmix_mca_base_component_t pmix_pstat_base_component_t; /** * Structure for pstat modules */ struct pmix_pstat_base_module_1_0_0_t { pmix_pstat_base_module_init_fn_t init; pmix_pstat_base_module_query_fn_t query; pmix_pstat_base_module_fini_fn_t finalize; }; /** * Convenience typedef */ typedef struct pmix_pstat_base_module_1_0_0_t pmix_pstat_base_module_1_0_0_t; typedef struct pmix_pstat_base_module_1_0_0_t pmix_pstat_base_module_t; /** * Macro for use in components that are of type pstat */ #define PMIX_PSTAT_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("pstat", 1, 0, 0) /* Global structure for accessing pstat functions */ PMIX_EXPORT extern pmix_pstat_base_module_t pmix_pstat; END_C_DECLS #endif /* PMIX_MCA_PSTAT_H */ pmix-6.1.1~rc2/src/mca/pstat/Makefile.am0000664000175000017500000000231715203536752020216 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2010-2020 Cisco Systems, Inc. All rights reserved # Copyright (c) 2019 Intel, Inc. All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # main library setup noinst_LTLIBRARIES = libmca_pstat.la libmca_pstat_la_SOURCES = # local files headers = pstat.h libmca_pstat_la_SOURCES += $(headers) # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.am distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/pgpu/0000775000175000017500000000000015203536752015777 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pgpu/amd/0000775000175000017500000000000015203536752016540 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pgpu/amd/pgpu_amd_component.c0000664000175000017500000001044715203536752022570 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/pgpu/base/base.h" #include "src/util/pmix_argv.h" #include "pgpu_amd.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_register(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_pgpu_amd_component_t pmix_mca_pgpu_amd_component = { .super = { PMIX_PGPU_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "amd", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_register_component_params = component_register, .pmix_mca_query_component = component_query, }, .include = NULL, .exclude = NULL }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pgpu, amd) static pmix_status_t component_register(void) { pmix_mca_base_component_t *component = &pmix_mca_pgpu_amd_component.super.base; pmix_mca_pgpu_amd_component.incparms = NULL; (void) pmix_mca_base_component_var_register( component, "include_envars", "Comma-delimited list of envars to harvest (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, NULL, 0, 0, PMIX_INFO_LVL_2, PMIX_MCA_BASE_VAR_SCOPE_LOCAL, &pmix_mca_pgpu_amd_component.incparms); if (NULL != pmix_mca_pgpu_amd_component.incparms) { pmix_mca_pgpu_amd_component.include = PMIx_Argv_split(pmix_mca_pgpu_amd_component.incparms, ','); } pmix_mca_pgpu_amd_component.excparms = NULL; (void) pmix_mca_base_component_var_register( component, "exclude_envars", "Comma-delimited list of envars to exclude (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, NULL, 0, 0, PMIX_INFO_LVL_2, PMIX_MCA_BASE_VAR_SCOPE_LOCAL, &pmix_mca_pgpu_amd_component.excparms); if (NULL != pmix_mca_pgpu_amd_component.excparms) { pmix_mca_pgpu_amd_component.exclude = PMIx_Argv_split(pmix_mca_pgpu_amd_component.excparms, ','); } return PMIX_SUCCESS; } static pmix_status_t component_open(void) { pmix_status_t rc; rc = pmix_hwloc_check_vendor(&pmix_globals.topology, 0x1022, 0x302); return rc; } static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { /* check our topology to see if we have any AMD devices */ *priority = 20; *module = (pmix_mca_base_module_t *) &pmix_pgpu_amd_module; return PMIX_SUCCESS; } static pmix_status_t component_close(void) { return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pgpu/amd/pgpu_amd.h0000664000175000017500000000163415203536752020511 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PGPU_AMD_H #define PMIX_PGPU_AMD_H #include "src/include/pmix_config.h" #include "src/mca/pgpu/pgpu.h" BEGIN_C_DECLS typedef struct { pmix_pgpu_base_component_t super; char *incparms; char *excparms; char **include; char **exclude; } pmix_pgpu_amd_component_t; /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_pgpu_amd_component_t pmix_mca_pgpu_amd_component; extern pmix_pgpu_module_t pmix_pgpu_amd_module; /* define a key for any blob we need to send in a launch msg */ #define PMIX_PGPU_AMD_BLOB "pmix.pgpu.amd.blob" /* define an inventory key */ #define PMIX_PGPU_AMD_INVENTORY_KEY "pmix.pgpu.amd.inventory" END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pgpu/amd/configure.m40000664000175000017500000000212615203536752020764 0ustar alastairalastair# -*- shell-script -*- # # Copyright (C) 2015-2017 Mellanox Technologies, Inc. # All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2016 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_pmix_pgpu_amd_CONFIG(prefix, [action-if-found], [action-if-not-found]) # -------------------------------------------------------- AC_DEFUN([MCA_pmix_pgpu_amd_CONFIG],[ AC_CONFIG_FILES([src/mca/pgpu/amd/Makefile]) AS_IF([test "yes" = "no"], [$1 pmix_pgpu_amd_happy=yes], [$2 pmix_pgpu_amd_happy=no]) PMIX_SUMMARY_ADD([GPUs], [AMD], [],[$pmix_pgpu_amd_happy])])]) ]) pmix-6.1.1~rc2/src/mca/pgpu/amd/Makefile.am0000664000175000017500000000363515203536752020603 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = pgpu_amd.h sources = \ pgpu_amd_component.c \ pgpu_amd.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pgpu_amd_DSO lib = lib_sources = component = pmix_mca_pgpu_amd.la component_sources = $(headers) $(sources) else lib = libpmix_mca_pgpu_amd.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_pgpu_amd_la_SOURCES = $(component_sources) pmix_mca_pgpu_amd_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_pgpu_amd_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_pgpu_amd_la_SOURCES = $(lib_sources) libpmix_mca_pgpu_amd_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/pgpu/amd/pgpu_amd.c0000664000175000017500000002050615203536752020503 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/pcompress/pcompress.h" #include "src/mca/preg/preg.h" #include "src/util/alfg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "pgpu_amd.h" #include "src/mca/pgpu/base/base.h" #include "src/mca/pgpu/pgpu.h" static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); static pmix_status_t setup_local(pmix_nspace_env_cache_t *ns, pmix_info_t info[], size_t ninfo); static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory); static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs); pmix_pgpu_module_t pmix_pgpu_amd_module = { .name = "amd", .allocate = allocate, .setup_local = setup_local, .collect_inventory = collect_inventory, .deliver_inventory = deliver_inventory }; /* NOTE: if there is any binary data to be transferred, then * this function MUST pack it for transport as the host will * not know how to do so */ static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist) { pmix_buffer_t mydata; // Buffer used to store information to be transmitted (scratch storage) pmix_kval_t *kv; pmix_byte_object_t bo; bool envars = false; pmix_status_t rc; pmix_list_t cache; size_t n; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu:amd:allocate for nspace %s", nptr->nspace); if (NULL == info) { return PMIX_ERR_TAKE_NEXT_OPTION; } for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ENVARS)) { envars = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ALL)) { envars = PMIX_INFO_TRUE(&info[n]); } } /* setup a buffer - we will pack the info into it for transmission to * the backend compute node daemons */ PMIX_CONSTRUCT(&mydata, pmix_buffer_t); if (envars) { pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu: amd harvesting envars %s excluding %s", (NULL == pmix_mca_pgpu_amd_component.incparms) ? "NONE" : pmix_mca_pgpu_amd_component.incparms, (NULL == pmix_mca_pgpu_amd_component.excparms) ? "NONE" : pmix_mca_pgpu_amd_component.excparms); /* harvest envars to pass along */ PMIX_CONSTRUCT(&cache, pmix_list_t); if (NULL != pmix_mca_pgpu_amd_component.include) { rc = pmix_util_harvest_envars(pmix_mca_pgpu_amd_component.include, pmix_mca_pgpu_amd_component.exclude, &cache); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&cache); PMIX_DESTRUCT(&mydata); return rc; } /* pack anything that was found */ PMIX_LIST_FOREACH (kv, &cache, pmix_kval_t) { PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &mydata, &kv->value->data.envar, 1, PMIX_ENVAR); } PMIX_LIST_DESTRUCT(&cache); } } /* load all our results into a buffer for xmission to the backend */ PMIX_KVAL_NEW(kv, PMIX_PGPU_AMD_BLOB); if (NULL == kv || NULL == kv->value) { PMIX_DESTRUCT(&mydata); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_BYTE_OBJECT; PMIX_UNLOAD_BUFFER(&mydata, bo.bytes, bo.size); /* to help scalability, compress this blob */ if (pmix_compress.compress((uint8_t *) bo.bytes, bo.size, (uint8_t **) &kv->value->data.bo.bytes, &kv->value->data.bo.size)) { kv->value->type = PMIX_COMPRESSED_BYTE_OBJECT; } else { kv->value->data.bo.bytes = bo.bytes; kv->value->data.bo.size = bo.size; } PMIX_DESTRUCT(&mydata); pmix_list_append(ilist, &kv->super); return PMIX_SUCCESS; } /* PMIx_server_setup_local_support calls the "setup_local" function. * The Standard requires that this come _after_ the host calls the * PMIx_server_register_nspace function to ensure that any required information * is available to the components. Thus, we have the PMIX_NODE_MAP and * PMIX_PROC_MAP available to us and can use them here. * * When the host calls "setup_local", it passes down an array * containing the information the "lead" server (e.g., "mpirun") collected * from PMIx_server_setup_application. In this case, we search for a blob * that our "allocate" function may have included in that info. */ static pmix_status_t setup_local(pmix_nspace_env_cache_t *ns, pmix_info_t info[], size_t ninfo) { size_t n; pmix_buffer_t bkt; int32_t cnt; pmix_status_t rc = PMIX_SUCCESS; uint8_t *data; size_t size; bool release = false; pmix_envar_list_item_t *ev; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu:amd:setup_local with %lu info", (unsigned long) ninfo); /* prep the unpack buffer */ PMIX_CONSTRUCT(&bkt, pmix_buffer_t); for (n = 0; n < ninfo; n++) { /* look for my key */ if (PMIX_CHECK_KEY(&info[n], PMIX_PGPU_AMD_BLOB)) { pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu:amd:setup_local found my blob"); /* if this is a compressed byte object, decompress it */ if (PMIX_COMPRESSED_BYTE_OBJECT == info[n].value.type) { pmix_compress.decompress(&data, &size, (uint8_t *) info[n].value.data.bo.bytes, info[n].value.data.bo.size); release = true; } else { data = (uint8_t *) info[n].value.data.bo.bytes; size = info[n].value.data.bo.size; } PMIX_LOAD_BUFFER_NON_DESTRUCT(pmix_globals.mypeer, &bkt, data, size); /* all we packed was envars, so just cycle thru */ ev = PMIX_NEW(pmix_envar_list_item_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &ev->envar, &cnt, PMIX_ENVAR); while (PMIX_SUCCESS == rc) { pmix_list_append(&ns->envars, &ev->super); /* get the next envar */ ev = PMIX_NEW(pmix_envar_list_item_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &ev->envar, &cnt, PMIX_ENVAR); } // we will have created one more envar than we want PMIX_RELEASE(ev); /* we are done */ break; } } if (release) { free(data); } return rc; } static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory) { /* search the topology for AMD GPUs */ PMIX_HIDE_UNUSED_PARAMS(directives, ndirs, inventory); return PMIX_SUCCESS; } static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs) { /* look for our inventory blob */ PMIX_HIDE_UNUSED_PARAMS(info, ninfo, directives, ndirs); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pgpu/nvd/0000775000175000017500000000000015203536752016566 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pgpu/nvd/pgpu_nvd.h0000664000175000017500000000163415203536752020565 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PGPU_NVD_H #define PMIX_PGPU_NVD_H #include "src/include/pmix_config.h" #include "src/mca/pgpu/pgpu.h" BEGIN_C_DECLS typedef struct { pmix_pgpu_base_component_t super; char *incparms; char *excparms; char **include; char **exclude; } pmix_pgpu_nvd_component_t; /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_pgpu_nvd_component_t pmix_mca_pgpu_nvd_component; extern pmix_pgpu_module_t pmix_pgpu_nvd_module; /* define a key for any blob we need to send in a launch msg */ #define PMIX_PGPU_NVD_BLOB "pmix.pgpu.nvd.blob" /* define an inventory key */ #define PMIX_PGPU_NVD_INVENTORY_KEY "pmix.pgpu.nvd.inventory" END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pgpu/nvd/pgpu_nvd.c0000664000175000017500000002047615203536752020565 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/pcompress/pcompress.h" #include "src/mca/preg/preg.h" #include "src/util/alfg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "pgpu_nvd.h" #include "src/mca/pgpu/base/base.h" #include "src/mca/pgpu/pgpu.h" static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); static pmix_status_t setup_local(pmix_nspace_env_cache_t *ns, pmix_info_t info[], size_t ninfo); static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory); static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs); pmix_pgpu_module_t pmix_pgpu_nvd_module = { .name = "nvd", .allocate = allocate, .setup_local = setup_local, .collect_inventory = collect_inventory, .deliver_inventory = deliver_inventory }; /* NOTE: if there is any binary data to be transferred, then * this function MUST pack it for transport as the host will * not know how to do so */ static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist) { pmix_buffer_t mydata; // Buffer used to store information to be transmitted (scratch storage) pmix_kval_t *kv; pmix_byte_object_t bo; bool envars = false; pmix_status_t rc; pmix_list_t cache; size_t n; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu:nvd:allocate for nspace %s", nptr->nspace); if (NULL == info) { return PMIX_ERR_TAKE_NEXT_OPTION; } for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ENVARS)) { envars = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ALL)) { envars = PMIX_INFO_TRUE(&info[n]); } } /* setup a buffer - we will pack the info into it for transmission to * the backend compute node daemons */ PMIX_CONSTRUCT(&mydata, pmix_buffer_t); if (envars) { pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu: nvd harvesting envars %s excluding %s", (NULL == pmix_mca_pgpu_nvd_component.incparms) ? "NONE" : pmix_mca_pgpu_nvd_component.incparms, (NULL == pmix_mca_pgpu_nvd_component.excparms) ? "NONE" : pmix_mca_pgpu_nvd_component.excparms); /* harvest envars to pass along */ PMIX_CONSTRUCT(&cache, pmix_list_t); if (NULL != pmix_mca_pgpu_nvd_component.include) { rc = pmix_util_harvest_envars(pmix_mca_pgpu_nvd_component.include, pmix_mca_pgpu_nvd_component.exclude, &cache); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&cache); PMIX_DESTRUCT(&mydata); return rc; } /* pack anything that was found */ PMIX_LIST_FOREACH (kv, &cache, pmix_kval_t) { PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &mydata, &kv->value->data.envar, 1, PMIX_ENVAR); } PMIX_LIST_DESTRUCT(&cache); } } /* load all our results into a buffer for xmission to the backend */ PMIX_KVAL_NEW(kv, PMIX_PGPU_NVD_BLOB); if (NULL == kv || NULL == kv->value) { PMIX_DESTRUCT(&mydata); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_BYTE_OBJECT; PMIX_UNLOAD_BUFFER(&mydata, bo.bytes, bo.size); /* to help scalability, compress this blob */ if (pmix_compress.compress((uint8_t *) bo.bytes, bo.size, (uint8_t **) &kv->value->data.bo.bytes, &kv->value->data.bo.size)) { kv->value->type = PMIX_COMPRESSED_BYTE_OBJECT; } else { kv->value->data.bo.bytes = bo.bytes; kv->value->data.bo.size = bo.size; } PMIX_DESTRUCT(&mydata); pmix_list_append(ilist, &kv->super); return PMIX_SUCCESS; } /* PMIx_server_setup_local_support calls the "setup_local" function. * The Standard requires that this come _after_ the host calls the * PMIx_server_register_nspace function to ensure that any required information * is available to the components. Thus, we have the PMIX_NODE_MAP and * PMIX_PROC_MAP available to us and can use them here. * * When the host calls "setup_local", it passes down an array * containing the information the "lead" server (e.g., "mpirun") collected * from PMIx_server_setup_application. In this case, we search for a blob * that our "allocate" function may have included in that info. */ static pmix_status_t setup_local(pmix_nspace_env_cache_t *ns, pmix_info_t info[], size_t ninfo) { size_t n; pmix_buffer_t bkt; int32_t cnt; pmix_status_t rc = PMIX_SUCCESS; uint8_t *data; size_t size; bool release = false; pmix_envar_list_item_t *ev; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu:nvd:setup_local with %lu info", (unsigned long) ninfo); /* prep the unpack buffer */ PMIX_CONSTRUCT(&bkt, pmix_buffer_t); for (n = 0; n < ninfo; n++) { /* look for my key */ if (PMIX_CHECK_KEY(&info[n], PMIX_PGPU_NVD_BLOB)) { pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu:nvd:setup_local found my blob"); /* if this is a compressed byte object, decompress it */ if (PMIX_COMPRESSED_BYTE_OBJECT == info[n].value.type) { pmix_compress.decompress(&data, &size, (uint8_t *) info[n].value.data.bo.bytes, info[n].value.data.bo.size); release = true; } else { data = (uint8_t *) info[n].value.data.bo.bytes; size = info[n].value.data.bo.size; } PMIX_LOAD_BUFFER_NON_DESTRUCT(pmix_globals.mypeer, &bkt, data, size); /* all we packed was envars, so just cycle thru */ ev = PMIX_NEW(pmix_envar_list_item_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &ev->envar, &cnt, PMIX_ENVAR); while (PMIX_SUCCESS == rc) { pmix_list_append(&ns->envars, &ev->super); /* get the next envar */ ev = PMIX_NEW(pmix_envar_list_item_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &ev->envar, &cnt, PMIX_ENVAR); } // we will have created one more envar than we want PMIX_RELEASE(ev); /* we are done */ break; } } if (release) { free(data); } return rc; } static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory) { /* search the topology for nvd GPUs */ PMIX_HIDE_UNUSED_PARAMS(directives, ndirs, inventory); return PMIX_SUCCESS; } static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs) { /* look for our inventory blob */ PMIX_HIDE_UNUSED_PARAMS(info, ninfo, directives, ndirs); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pgpu/nvd/configure.m40000664000175000017500000000213215203536752021007 0ustar alastairalastair# -*- shell-script -*- # # Copyright (C) 2015-2017 Mellanox Technologies, Inc. # All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2016 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_pmix_pgpu_nvd_CONFIG(prefix, [action-if-found], [action-if-not-found]) # -------------------------------------------------------- AC_DEFUN([MCA_pmix_pgpu_nvd_CONFIG],[ AC_CONFIG_FILES([src/mca/pgpu/nvd/Makefile]) AS_IF([test "yes" = "no"], [$1 pmix_pgpu_nvd_happy=yes], [$2 pmix_pgpu_nvd_happy=no]) PMIX_SUMMARY_ADD([GPUs], [NVIDIA], [], [$pmix_pgpu_nvd_happy])])]) ]) pmix-6.1.1~rc2/src/mca/pgpu/nvd/Makefile.am0000664000175000017500000000363515203536752020631 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = pgpu_nvd.h sources = \ pgpu_nvd_component.c \ pgpu_nvd.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pgpu_nvd_DSO lib = lib_sources = component = pmix_mca_pgpu_nvd.la component_sources = $(headers) $(sources) else lib = libpmix_mca_pgpu_nvd.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_pgpu_nvd_la_SOURCES = $(component_sources) pmix_mca_pgpu_nvd_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_pgpu_nvd_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_pgpu_nvd_la_SOURCES = $(lib_sources) libpmix_mca_pgpu_nvd_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/pgpu/nvd/pgpu_nvd_component.c0000664000175000017500000001041315203536752022635 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/pgpu/base/base.h" #include "src/util/pmix_argv.h" #include "pgpu_nvd.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_register(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_pgpu_nvd_component_t pmix_mca_pgpu_nvd_component = { .super = { PMIX_PGPU_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "nvd", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_register_component_params = component_register, .pmix_mca_query_component = component_query, }, .include = NULL, .exclude = NULL }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pgpu, nvidia) static pmix_status_t component_register(void) { pmix_mca_base_component_t *component = &pmix_mca_pgpu_nvd_component.super.base; pmix_mca_pgpu_nvd_component.incparms = "CUDA_*,NCCL_*"; (void) pmix_mca_base_component_var_register( component, "include_envars", "Comma-delimited list of envars to harvest (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, NULL, 0, 0, PMIX_INFO_LVL_2, PMIX_MCA_BASE_VAR_SCOPE_LOCAL, &pmix_mca_pgpu_nvd_component.incparms); if (NULL != pmix_mca_pgpu_nvd_component.incparms) { pmix_mca_pgpu_nvd_component.include = PMIx_Argv_split(pmix_mca_pgpu_nvd_component.incparms, ','); } pmix_mca_pgpu_nvd_component.excparms = NULL; (void) pmix_mca_base_component_var_register( component, "exclude_envars", "Comma-delimited list of envars to exclude (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, NULL, 0, 0, PMIX_INFO_LVL_2, PMIX_MCA_BASE_VAR_SCOPE_LOCAL, &pmix_mca_pgpu_nvd_component.excparms); if (NULL != pmix_mca_pgpu_nvd_component.excparms) { pmix_mca_pgpu_nvd_component.exclude = PMIx_Argv_split(pmix_mca_pgpu_nvd_component.excparms, ','); } return PMIX_SUCCESS; } static pmix_status_t component_open(void) { pmix_status_t rc; // under NVIDIA rc = pmix_hwloc_check_vendor(&pmix_globals.topology, 0x10de, 0x302); return rc; } static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 10; *module = (pmix_mca_base_module_t *) &pmix_pgpu_nvd_module; return PMIX_SUCCESS; } static pmix_status_t component_close(void) { return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pgpu/intel/0000775000175000017500000000000015203536752017112 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pgpu/intel/pgpu_intel.h0000664000175000017500000000166015203536752021434 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PGPU_INTEL_H #define PMIX_PGPU_INTEL_H #include "src/include/pmix_config.h" #include "src/mca/pgpu/pgpu.h" BEGIN_C_DECLS typedef struct { pmix_pgpu_base_component_t super; char *incparms; char *excparms; char **include; char **exclude; } pmix_pgpu_intel_component_t; /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_pgpu_intel_component_t pmix_mca_pgpu_intel_component; extern pmix_pgpu_module_t pmix_pgpu_intel_module; /* define a key for any blob we need to send in a launch msg */ #define PMIX_PGPU_INTEL_BLOB "pmix.pgpu.intel.blob" /* define an inventory key */ #define PMIX_PGPU_INTEL_INVENTORY_KEY "pmix.pgpu.intel.inventory" END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pgpu/intel/configure.m40000664000175000017500000000240315203536752021334 0ustar alastairalastair# -*- shell-script -*- # # Copyright (C) 2015-2017 Mellanox Technologies, Inc. # All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2016 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_pmix_pgpu_intel_CONFIG(prefix, [action-if-found], [action-if-not-found]) # -------------------------------------------------------- # check if L0 support can be found. runs action-if-found if there is # support, otherwise executes action-if-not-found AC_DEFUN([MCA_pmix_pgpu_intel_CONFIG],[ AC_CONFIG_FILES([src/mca/pgpu/intel/Makefile]) # eventually need to check for L0 library AS_IF([test "yes" = "no"], [$1 pmix_pgpu_intel_happy=yes], [$2 pmix_pgpu_intel_happy=no]) PMIX_SUMMARY_ADD([GPUs], [Intel], [], [$pmix_pgpu_intel_happy]) ]) pmix-6.1.1~rc2/src/mca/pgpu/intel/pgpu_intel_component.c0000664000175000017500000001041315203536752023505 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/hwloc/pmix_hwloc.h" #include "src/mca/pgpu/base/base.h" #include "src/util/pmix_argv.h" #include "pgpu_intel.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t component_register(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_pgpu_intel_component_t pmix_mca_pgpu_intel_component = { .super = { PMIX_PGPU_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "intel", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_register_component_params = component_register, .pmix_mca_query_component = component_query, }, .include = NULL, .exclude = NULL }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pgpu, intel) static pmix_status_t component_register(void) { pmix_mca_base_component_t *component = &pmix_mca_pgpu_intel_component.super.base; pmix_mca_pgpu_intel_component.incparms = NULL; (void) pmix_mca_base_component_var_register( component, "include_envars", "Comma-delimited list of envars to harvest (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, NULL, 0, 0, PMIX_INFO_LVL_2, PMIX_MCA_BASE_VAR_SCOPE_LOCAL, &pmix_mca_pgpu_intel_component.incparms); if (NULL != pmix_mca_pgpu_intel_component.incparms) { pmix_mca_pgpu_intel_component.include = PMIx_Argv_split(pmix_mca_pgpu_intel_component.incparms, ','); } pmix_mca_pgpu_intel_component.excparms = NULL; (void) pmix_mca_base_component_var_register( component, "exclude_envars", "Comma-delimited list of envars to exclude (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, NULL, 0, 0, PMIX_INFO_LVL_2, PMIX_MCA_BASE_VAR_SCOPE_LOCAL, &pmix_mca_pgpu_intel_component.excparms); if (NULL != pmix_mca_pgpu_intel_component.excparms) { pmix_mca_pgpu_intel_component.exclude = PMIx_Argv_split(pmix_mca_pgpu_intel_component.excparms, ','); } return PMIX_SUCCESS; } static pmix_status_t component_open(void) { pmix_status_t rc; rc = pmix_hwloc_check_vendor(&pmix_globals.topology, 0x8086, 0x0380); return rc; } static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 20; *module = (pmix_mca_base_module_t *) &pmix_pgpu_intel_module; return PMIX_SUCCESS; } static pmix_status_t component_close(void) { return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pgpu/intel/Makefile.am0000664000175000017500000000366315203536752021156 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = pgpu_intel.h sources = \ pgpu_intel_component.c \ pgpu_intel.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pgpu_intel_DSO lib = lib_sources = component = pmix_mca_pgpu_intel.la component_sources = $(headers) $(sources) else lib = libpmix_mca_pgpu_intel.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_pgpu_intel_la_SOURCES = $(component_sources) pmix_mca_pgpu_intel_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_pgpu_intel_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_pgpu_intel_la_SOURCES = $(lib_sources) libpmix_mca_pgpu_intel_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/pgpu/intel/pgpu_intel.c0000664000175000017500000002056415203536752021433 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/pcompress/pcompress.h" #include "src/mca/preg/preg.h" #include "src/util/alfg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "pgpu_intel.h" #include "src/mca/pgpu/base/base.h" #include "src/mca/pgpu/pgpu.h" static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); static pmix_status_t setup_local(pmix_nspace_env_cache_t *ns, pmix_info_t info[], size_t ninfo); static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory); static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs); pmix_pgpu_module_t pmix_pgpu_intel_module = { .name = "intel", .allocate = allocate, .setup_local = setup_local, .collect_inventory = collect_inventory, .deliver_inventory = deliver_inventory }; /* NOTE: if there is any binary data to be transferred, then * this function MUST pack it for transport as the host will * not know how to do so */ static pmix_status_t allocate(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist) { pmix_buffer_t mydata; // Buffer used to store information to be transmitted (scratch storage) pmix_kval_t *kv; pmix_byte_object_t bo; bool envars = false; pmix_status_t rc; pmix_list_t cache; size_t n; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu:intel:allocate for nspace %s", nptr->nspace); if (NULL == info) { return PMIX_ERR_TAKE_NEXT_OPTION; } for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ENVARS)) { envars = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ALL)) { envars = PMIX_INFO_TRUE(&info[n]); } } /* setup a buffer - we will pack the info into it for transmission to * the backend compute node daemons */ PMIX_CONSTRUCT(&mydata, pmix_buffer_t); if (envars) { pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu: intel harvesting envars %s excluding %s", (NULL == pmix_mca_pgpu_intel_component.incparms) ? "NONE" : pmix_mca_pgpu_intel_component.incparms, (NULL == pmix_mca_pgpu_intel_component.excparms) ? "NONE" : pmix_mca_pgpu_intel_component.excparms); /* harvest envars to pass along */ PMIX_CONSTRUCT(&cache, pmix_list_t); if (NULL != pmix_mca_pgpu_intel_component.include) { rc = pmix_util_harvest_envars(pmix_mca_pgpu_intel_component.include, pmix_mca_pgpu_intel_component.exclude, &cache); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&cache); PMIX_DESTRUCT(&mydata); return rc; } /* pack anything that was found */ PMIX_LIST_FOREACH (kv, &cache, pmix_kval_t) { PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &mydata, &kv->value->data.envar, 1, PMIX_ENVAR); } PMIX_LIST_DESTRUCT(&cache); } } /* load all our results into a buffer for xmission to the backend */ PMIX_KVAL_NEW(kv, PMIX_PGPU_INTEL_BLOB); if (NULL == kv || NULL == kv->value) { PMIX_DESTRUCT(&mydata); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_BYTE_OBJECT; PMIX_UNLOAD_BUFFER(&mydata, bo.bytes, bo.size); /* to help scalability, compress this blob */ if (pmix_compress.compress((uint8_t *) bo.bytes, bo.size, (uint8_t **) &kv->value->data.bo.bytes, &kv->value->data.bo.size)) { kv->value->type = PMIX_COMPRESSED_BYTE_OBJECT; } else { kv->value->data.bo.bytes = bo.bytes; kv->value->data.bo.size = bo.size; } PMIX_DESTRUCT(&mydata); pmix_list_append(ilist, &kv->super); return PMIX_SUCCESS; } /* PMIx_server_setup_local_support calls the "setup_local" function. * The Standard requires that this come _after_ the host calls the * PMIx_server_register_nspace function to ensure that any required information * is available to the components. Thus, we have the PMIX_NODE_MAP and * PMIX_PROC_MAP available to us and can use them here. * * When the host calls "setup_local", it passes down an array * containing the information the "lead" server (e.g., "mpirun") collected * from PMIx_server_setup_application. In this case, we search for a blob * that our "allocate" function may have included in that info. */ static pmix_status_t setup_local(pmix_nspace_env_cache_t *ns, pmix_info_t info[], size_t ninfo) { size_t n; pmix_buffer_t bkt; int32_t cnt; pmix_status_t rc = PMIX_SUCCESS; uint8_t *data; size_t size; bool release = false; pmix_envar_list_item_t *ev; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu:intel:setup_local with %lu info", (unsigned long) ninfo); /* prep the unpack buffer */ PMIX_CONSTRUCT(&bkt, pmix_buffer_t); for (n = 0; n < ninfo; n++) { /* look for my key */ if (PMIX_CHECK_KEY(&info[n], PMIX_PGPU_INTEL_BLOB)) { pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu:intel:setup_local found my blob"); /* if this is a compressed byte object, decompress it */ if (PMIX_COMPRESSED_BYTE_OBJECT == info[n].value.type) { pmix_compress.decompress(&data, &size, (uint8_t *) info[n].value.data.bo.bytes, info[n].value.data.bo.size); release = true; } else { data = (uint8_t *) info[n].value.data.bo.bytes; size = info[n].value.data.bo.size; } PMIX_LOAD_BUFFER_NON_DESTRUCT(pmix_globals.mypeer, &bkt, data, size); /* all we packed was envars, so just cycle thru */ ev = PMIX_NEW(pmix_envar_list_item_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &ev->envar, &cnt, PMIX_ENVAR); while (PMIX_SUCCESS == rc) { pmix_list_append(&ns->envars, &ev->super); /* get the next envar */ ev = PMIX_NEW(pmix_envar_list_item_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, &bkt, &ev->envar, &cnt, PMIX_ENVAR); } // we will have created one more envar than we want PMIX_RELEASE(ev); /* we are done */ break; } } if (release) { free(data); } return rc; } static pmix_status_t collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory) { /* search the topology for intel GPUs */ PMIX_HIDE_UNUSED_PARAMS(directives, ndirs, inventory); return PMIX_SUCCESS; } static pmix_status_t deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs) { /* look for our inventory blob */ PMIX_HIDE_UNUSED_PARAMS(info, ninfo, directives, ndirs); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pgpu/base/0000775000175000017500000000000015203536752016711 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pgpu/base/pgpu_base_frame.c0000664000175000017500000000705415203536752022202 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2009 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pgpu/base/base.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public mca_base_component_t struct. */ #include "src/mca/pgpu/base/static-components.h" /* Instantiate the global vars */ pmix_pgpu_globals_t pmix_pgpu_globals = { .actives = PMIX_LIST_STATIC_INIT, .nspaces = PMIX_LIST_STATIC_INIT }; pmix_pgpu_API_module_t pmix_pgpu = { .allocate = pmix_pgpu_base_allocate, .setup_local = pmix_pgpu_base_setup_local, .setup_fork = pmix_pgpu_base_setup_fork, .child_finalized = pmix_pgpu_base_child_finalized, .local_app_finalized = pmix_pgpu_base_local_app_finalized, .deregister_nspace = pmix_pgpu_base_deregister_nspace, .collect_inventory = pmix_pgpu_base_collect_inventory, .deliver_inventory = pmix_pgpu_base_deliver_inventory }; static pmix_status_t pmix_pgpu_close(void) { pmix_pgpu_base_active_module_t *active, *prev; pmix_pgpu_globals.selected = false; PMIX_LIST_FOREACH_SAFE (active, prev, &pmix_pgpu_globals.actives, pmix_pgpu_base_active_module_t) { pmix_list_remove_item(&pmix_pgpu_globals.actives, &active->super); if (NULL != active->module->finalize) { active->module->finalize(); } PMIX_RELEASE(active); } PMIX_LIST_DESTRUCT(&pmix_pgpu_globals.actives); PMIX_LIST_DESTRUCT(&pmix_pgpu_globals.nspaces); return pmix_mca_base_framework_components_close(&pmix_pgpu_base_framework, NULL); } static pmix_status_t pmix_pgpu_open(pmix_mca_base_open_flag_t flags) { /* initialize globals */ PMIX_CONSTRUCT(&pmix_pgpu_globals.actives, pmix_list_t); PMIX_CONSTRUCT(&pmix_pgpu_globals.nspaces, pmix_list_t); /* Open up all available components */ return pmix_mca_base_framework_components_open(&pmix_pgpu_base_framework, flags); } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, pgpu, "PMIx GPU Operations", NULL, pmix_pgpu_open, pmix_pgpu_close, pmix_mca_pgpu_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); PMIX_CLASS_INSTANCE(pmix_pgpu_base_active_module_t, pmix_list_item_t, NULL, NULL); pmix-6.1.1~rc2/src/mca/pgpu/base/pgpu_base_fns.c0000664000175000017500000002235715203536752021701 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/class/pmix_list.h" #include "src/mca/preg/preg.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_environ.h" #include "src/mca/pgpu/base/base.h" /* NOTE: a tool (e.g., prun) may call this function to * harvest local envars for inclusion in a call to * PMIx_Spawn, or it might be called in response to * a call to PMIx_Allocate_resources */ pmix_status_t pmix_pgpu_base_allocate(char *nspace, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist) { pmix_pgpu_base_active_module_t *active; pmix_status_t rc; pmix_namespace_t *nptr, *ns; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu:allocate called"); /* protect against bozo inputs */ if (NULL == nspace || NULL == ilist) { return PMIX_ERR_BAD_PARAM; } if (0 == pmix_list_get_size(&pmix_pgpu_globals.actives)) { return PMIX_SUCCESS; } /* find this proc's nspace object */ nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(ns->nspace, nspace)) { nptr = ns; break; } } if (NULL == nptr) { /* add it */ nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { return PMIX_ERR_NOMEM; } nptr->nspace = strdup(nspace); pmix_list_append(&pmix_globals.nspaces, &nptr->super); } if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { /* process the allocation request */ PMIX_LIST_FOREACH (active, &pmix_pgpu_globals.actives, pmix_pgpu_base_active_module_t) { if (NULL != active->module->allocate) { rc = active->module->allocate(nptr, info, ninfo, ilist); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_AVAILABLE != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { /* true error */ return rc; } } } } return PMIX_SUCCESS; } /* can only be called by a server from within an event! */ pmix_status_t pmix_pgpu_base_setup_local(char *nspace, pmix_info_t info[], size_t ninfo) { pmix_pgpu_base_active_module_t *active; pmix_status_t rc; pmix_nspace_env_cache_t *ns, *ns2; pmix_namespace_t *nsp, *nsp2; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu: setup_local_network called"); /* protect against bozo inputs */ if (NULL == nspace) { return PMIX_ERR_BAD_PARAM; } if (0 == pmix_list_get_size(&pmix_pgpu_globals.actives)) { return PMIX_SUCCESS; } /* find this proc's nspace object */ ns = NULL; PMIX_LIST_FOREACH (ns2, &pmix_pgpu_globals.nspaces, pmix_nspace_env_cache_t) { if (PMIX_CHECK_NSPACE(ns2->ns->nspace, nspace)) { ns = ns2; break; } } if (NULL == ns) { /* find the namespace object for this nspace */ nsp = NULL; PMIX_LIST_FOREACH (nsp2, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(nsp2->nspace, nspace)) { nsp = nsp2; break; } } if (NULL == nsp) { /* add it */ nsp = PMIX_NEW(pmix_namespace_t); if (NULL == nsp) { return PMIX_ERR_NOMEM; } nsp->nspace = strdup(nspace); pmix_list_append(&pmix_globals.nspaces, &nsp->super); } ns = PMIX_NEW(pmix_nspace_env_cache_t); PMIX_RETAIN(nsp); ns->ns = nsp; pmix_list_append(&pmix_pgpu_globals.nspaces, &ns->super); } PMIX_LIST_FOREACH (active, &pmix_pgpu_globals.actives, pmix_pgpu_base_active_module_t) { if (NULL != active->module->setup_local) { rc = active->module->setup_local(ns, info, ninfo); if (PMIX_SUCCESS != rc && PMIX_ERR_NOT_AVAILABLE != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { return rc; } } } return PMIX_SUCCESS; } /* can only be called by a server from within an event! */ pmix_status_t pmix_pgpu_base_setup_fork(const pmix_proc_t *proc, char ***env) { pmix_nspace_env_cache_t *ns, *ns2; pmix_envar_list_item_t *ev; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu: setup_fork called"); /* protect against bozo inputs */ if (NULL == proc || NULL == env) { return PMIX_ERR_BAD_PARAM; } /* see if we have this nspace */ ns = NULL; PMIX_LIST_FOREACH (ns2, &pmix_pgpu_globals.nspaces, pmix_nspace_env_cache_t) { if (PMIX_CHECK_NSPACE(ns2->ns->nspace, proc->nspace)) { ns = ns2; break; } } if (NULL != ns) { PMIX_LIST_FOREACH (ev, &ns->envars, pmix_envar_list_item_t) { PMIx_Setenv(ev->envar.envar, ev->envar.value, true, env); } } return PMIX_SUCCESS; } void pmix_pgpu_base_child_finalized(pmix_proc_t *peer) { pmix_pgpu_base_active_module_t *active; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu: child_finalized called"); /* protect against bozo inputs */ if (NULL == peer) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return; } if (0 == pmix_list_get_size(&pmix_pgpu_globals.actives)) { return; } PMIX_LIST_FOREACH (active, &pmix_pgpu_globals.actives, pmix_pgpu_base_active_module_t) { if (NULL != active->module->child_finalized) { active->module->child_finalized(peer); } } return; } void pmix_pgpu_base_local_app_finalized(pmix_namespace_t *nptr) { pmix_pgpu_base_active_module_t *active; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu: local_app_finalized called"); /* protect against bozo inputs */ if (NULL == nptr) { return; } if (0 == pmix_list_get_size(&pmix_pgpu_globals.actives)) { return; } PMIX_LIST_FOREACH (active, &pmix_pgpu_globals.actives, pmix_pgpu_base_active_module_t) { if (NULL != active->module->local_app_finalized) { active->module->local_app_finalized(nptr); } } return; } void pmix_pgpu_base_deregister_nspace(char *nspace) { pmix_pgpu_base_active_module_t *active; pmix_nspace_env_cache_t *ns, *ns2; pmix_output_verbose(2, pmix_pgpu_base_framework.framework_output, "pgpu: deregister_nspace called"); /* protect against bozo inputs */ if (NULL == nspace) { return; } /* find this nspace object */ ns = NULL; PMIX_LIST_FOREACH (ns2, &pmix_pgpu_globals.nspaces, pmix_nspace_env_cache_t) { if (PMIX_CHECK_NSPACE(ns2->ns->nspace, nspace)) { ns = ns2; pmix_list_remove_item(&pmix_pgpu_globals.nspaces, &ns->super); break; } } if (NULL == ns) { return; } PMIX_LIST_FOREACH (active, &pmix_pgpu_globals.actives, pmix_pgpu_base_active_module_t) { if (NULL != active->module->deregister_nspace) { active->module->deregister_nspace(ns->ns); } } PMIX_RELEASE(ns); } pmix_status_t pmix_pgpu_base_collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory) { pmix_pgpu_base_active_module_t *active; pmix_status_t rc; PMIX_LIST_FOREACH (active, &pmix_pgpu_globals.actives, pmix_pgpu_base_active_module_t) { if (NULL != active->module->collect_inventory) { pmix_output_verbose(5, pmix_pgpu_base_framework.framework_output, "COLLECTING %s", active->module->name); rc = active->module->collect_inventory(directives, ndirs, inventory); if (PMIX_SUCCESS != rc) { return rc; } } } return PMIX_SUCCESS; } pmix_status_t pmix_pgpu_base_deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs) { pmix_pgpu_base_active_module_t *active; pmix_status_t rc; PMIX_LIST_FOREACH (active, &pmix_pgpu_globals.actives, pmix_pgpu_base_active_module_t) { if (NULL != active->module->deliver_inventory) { pmix_output_verbose(5, pmix_pgpu_base_framework.framework_output, "DELIVERING TO %s", active->module->name); rc = active->module->deliver_inventory(info, ninfo, directives, ndirs); if (PMIX_SUCCESS != rc) { return rc; } } } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pgpu/base/base.h0000664000175000017500000000704215203536752017777 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PGPU_BASE_H_ #define PMIX_PGPU_BASE_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/class/pmix_pointer_array.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/mca.h" #include "src/mca/pgpu/pgpu.h" BEGIN_C_DECLS /* * MCA Framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_pgpu_base_framework; /** * pgpu select function * * Cycle across available components and construct the list * of active modules */ PMIX_EXPORT pmix_status_t pmix_pgpu_base_select(void); /** * Track an active component / module */ struct pmix_pgpu_base_active_module_t { pmix_list_item_t super; int pri; pmix_pgpu_module_t *module; pmix_pgpu_base_component_t *component; }; typedef struct pmix_pgpu_base_active_module_t pmix_pgpu_base_active_module_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_pgpu_base_active_module_t); /* framework globals */ struct pmix_pgpu_globals_t { pmix_list_t actives; pmix_list_t nspaces; bool selected; }; typedef struct pmix_pgpu_globals_t pmix_pgpu_globals_t; PMIX_EXPORT extern pmix_pgpu_globals_t pmix_pgpu_globals; PMIX_EXPORT pmix_status_t pmix_pgpu_base_allocate(char *nspace, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); PMIX_EXPORT pmix_status_t pmix_pgpu_base_setup_local(char *nspace, pmix_info_t info[], size_t ninfo); PMIX_EXPORT pmix_status_t pmix_pgpu_base_setup_fork(const pmix_proc_t *peer, char ***env); PMIX_EXPORT void pmix_pgpu_base_child_finalized(pmix_proc_t *peer); PMIX_EXPORT void pmix_pgpu_base_local_app_finalized(pmix_namespace_t *nptr); PMIX_EXPORT void pmix_pgpu_base_deregister_nspace(char *nspace); PMIX_EXPORT pmix_status_t pmix_pgpu_base_collect_inventory(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory); PMIX_EXPORT pmix_status_t pmix_pgpu_base_deliver_inventory(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs); PMIX_EXPORT pmix_status_t pmix_pgpu_base_harvest_envars(char **incvars, char **excvars, pmix_list_t *ilist); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pgpu/base/Makefile.include0000664000175000017500000000232015203536752021770 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2016 Intel, Inc. All rights reserved # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2021 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from # src/Makefile.am headers += \ base/base.h sources += \ base/pgpu_base_frame.c \ base/pgpu_base_select.c \ base/pgpu_base_fns.c pmix-6.1.1~rc2/src/mca/pgpu/base/pgpu_base_select.c0000664000175000017500000001142115203536752022360 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/mca/pgpu/base/base.h" /* Function for selecting a prioritized list of components * from all those that are available. */ int pmix_pgpu_base_select(void) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_mca_base_component_t *component = NULL; pmix_mca_base_module_t *module = NULL; pmix_pgpu_module_t *nmodule; pmix_pgpu_base_active_module_t *newmodule, *mod; int rc, priority; bool inserted; if (pmix_pgpu_globals.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_pgpu_globals.selected = true; /* Query all available components and ask if they have a module */ PMIX_LIST_FOREACH (cli, &pmix_pgpu_base_framework.framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_mca_base_component_t *) cli->cli_component; pmix_output_verbose(5, pmix_pgpu_base_framework.framework_output, "mca:pgpu:select: checking available component %s", component->pmix_mca_component_name); /* If there's no query function, skip it */ if (NULL == component->pmix_mca_query_component) { pmix_output_verbose( 5, pmix_pgpu_base_framework.framework_output, "mca:pgpu:select: Skipping component [%s]. It does not implement a query function", component->pmix_mca_component_name); continue; } /* Query the component */ pmix_output_verbose(5, pmix_pgpu_base_framework.framework_output, "mca:pgpu:select: Querying component [%s]", component->pmix_mca_component_name); rc = component->pmix_mca_query_component(&module, &priority); /* If no module was returned, then skip component */ if (PMIX_SUCCESS != rc || NULL == module) { pmix_output_verbose( 5, pmix_pgpu_base_framework.framework_output, "mca:pgpu:select: Skipping component [%s]. Query failed to return a module", component->pmix_mca_component_name); continue; } /* If we got a module, keep it */ nmodule = (pmix_pgpu_module_t *) module; /* let it initialize */ if (NULL != nmodule->init && PMIX_SUCCESS != nmodule->init()) { continue; } /* add to the list of selected modules */ newmodule = PMIX_NEW(pmix_pgpu_base_active_module_t); newmodule->pri = priority; newmodule->module = nmodule; newmodule->component = (pmix_pgpu_base_component_t *) cli->cli_component; /* maintain priority order */ inserted = false; PMIX_LIST_FOREACH (mod, &pmix_pgpu_globals.actives, pmix_pgpu_base_active_module_t) { if (priority > mod->pri) { pmix_list_insert_pos(&pmix_pgpu_globals.actives, (pmix_list_item_t *) mod, &newmodule->super); inserted = true; break; } } if (!inserted) { /* must be lowest priority - add to end */ pmix_list_append(&pmix_pgpu_globals.actives, &newmodule->super); } } if (4 < pmix_output_get_verbosity(pmix_pgpu_base_framework.framework_output)) { pmix_output(0, "Final pgpu priorities"); /* show the prioritized list */ PMIX_LIST_FOREACH (mod, &pmix_pgpu_globals.actives, pmix_pgpu_base_active_module_t) { pmix_output(0, "\tpgpu: %s Priority: %d", mod->component->pmix_mca_component_name, mod->pri); } } return PMIX_SUCCESS; ; } pmix-6.1.1~rc2/src/mca/pgpu/Makefile.am0000664000175000017500000000254615203536752020042 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2016 Intel, Inc. All rights reserved # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(LTDLINCL) # main library setup noinst_LTLIBRARIES = libmca_pgpu.la libmca_pgpu_la_SOURCES = # local files headers = pgpu.h sources = # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.include libmca_pgpu_la_SOURCES += $(headers) $(sources) distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/pgpu/pgpu.h0000664000175000017500000001646015203536752017132 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved. * * Copyright (c) 2015-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * This interface is for use by PMIx servers to obtain GPU-related info * and to setup GPU support for applications prior to launch * * Available plugins may be defined at runtime via the typical MCA parameter * syntax. */ #ifndef PMIX_PGPU_H #define PMIX_PGPU_H #include "src/include/pmix_config.h" #include "include/pmix.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/mca.h" #include "src/server/pmix_server_ops.h" BEGIN_C_DECLS /****** MODULE DEFINITION ******/ /** * Initialize the module. Returns an error if the module cannot * run, success if it can and wants to be used. */ typedef pmix_status_t (*pmix_pgpu_base_module_init_fn_t)(void); /** * Finalize the module. Tear down any allocated storage, disconnect * from any system support (e.g., LDAP server) */ typedef void (*pmix_pgpu_base_module_fini_fn_t)(void); /** * Provide an entry point for the PMIx_server_setup_application function */ typedef pmix_status_t (*pmix_pgpu_base_module_allocate_fn_t)(pmix_namespace_t *nptr, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); /** * Provide an entry point for the PMIx_server_setup_local_support function */ typedef pmix_status_t (*pmix_pgpu_base_module_setup_local_fn_t)(pmix_nspace_env_cache_t *ns, pmix_info_t info[], size_t ninfo); /** * Provide an opportunity to cleanup when a * local application process terminates */ typedef void (*pmix_pgpu_base_module_child_finalized_fn_t)(pmix_proc_t *peer); /** * Provide an opportunity to cleanup after * all local clients for a given application have terminated */ typedef void (*pmix_pgpu_base_module_local_app_finalized_fn_t)(pmix_namespace_t *nptr); /** * Provide an opportunity for the components to cleanup any * resource allocations they may have assigned */ typedef void (*pmix_pgpu_base_module_dregister_nspace_fn_t)(pmix_namespace_t *nptr); /** * Request that the module report local inventory * * If the operation can be performed immediately, then the module should just * add the inventory (as pmix_kval_t's) to the provided object's list and * return PMIX_SUCCESS. * * If the module needs to perform some non-atomic operation * then it should shift to its own internal * thread, return PMIX_OPERATION_IN_PROGRESS, and execute the provided * callback function when the operation is completed. * * If there is no inventory to report, then just return PMIX_SUCCESS. * * If the module should be providing inventory but encounters an error, * then immediately return an error code if the error is immediately detected, * or execute the callback function with an error code if it is detected later. */ typedef pmix_status_t (*pmix_pgpu_base_module_collect_inventory_fn_t)(pmix_info_t directives[], size_t ndirs, pmix_list_t *inventory); /** * Deliver inventory for archiving by corresponding modules * * Modules are to search the provided inventory to identify * entries provided by their remote peers, and then store that * information in a manner that can be queried/retrieved by * the host RM and/or scheduler. If the operation can be * performed immediately (e.g., storing the information in * the local hash table), then the module should just perform * that operation and return the appropriate status. * * If the module needs to perform some non-atomic operation * (e.g., storing the information in a non-local DHT), then * it should shift to its own internal thread, return * PMIX_OPERATION_IN_PROGRESS, and execute the provided * callback function when the operation is completed. * * If there is no relevant inventory to archive, then the module * should just return PMIX_SUCCESS; */ typedef pmix_status_t (*pmix_pgpu_base_module_deliver_inventory_fn_t)(pmix_info_t info[], size_t ninfo, pmix_info_t directives[], size_t ndirs); /** * Base structure for a pgpu module. Each component should malloc a * copy of the module structure for each fabric plane they support. */ typedef struct { char *name; /* provide a pointer to plane-specific metadata */ void *plane; /* init/finalize */ pmix_pgpu_base_module_init_fn_t init; pmix_pgpu_base_module_fini_fn_t finalize; pmix_pgpu_base_module_allocate_fn_t allocate; pmix_pgpu_base_module_setup_local_fn_t setup_local; pmix_pgpu_base_module_child_finalized_fn_t child_finalized; pmix_pgpu_base_module_local_app_finalized_fn_t local_app_finalized; pmix_pgpu_base_module_dregister_nspace_fn_t deregister_nspace; pmix_pgpu_base_module_collect_inventory_fn_t collect_inventory; pmix_pgpu_base_module_deliver_inventory_fn_t deliver_inventory; } pmix_pgpu_module_t; /* define a few API versions of the functions - main difference is the * string nspace parameter instead of a pointer to pmix_namespace_t. This * is done as an optimization to avoid having every component look for * that pointer */ typedef pmix_status_t (*pmix_pgpu_base_API_allocate_fn_t)(char *nspace, pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); typedef pmix_status_t (*pmix_pgpu_base_API_setup_local_fn_t)(char *nspace, pmix_info_t info[], size_t ninfo); typedef pmix_status_t (*pmix_pgpu_base_API_setup_fork_fn_t)(const pmix_proc_t *peer, char ***env); typedef void (*pmix_pgpu_base_API_deregister_nspace_fn_t)(char *nspace); /** * Base structure for a pgpu API */ typedef struct { char *name; /* init/finalize */ pmix_pgpu_base_module_init_fn_t init; pmix_pgpu_base_module_fini_fn_t finalize; pmix_pgpu_base_API_allocate_fn_t allocate; pmix_pgpu_base_API_setup_local_fn_t setup_local; pmix_pgpu_base_API_setup_fork_fn_t setup_fork; pmix_pgpu_base_module_child_finalized_fn_t child_finalized; pmix_pgpu_base_module_local_app_finalized_fn_t local_app_finalized; pmix_pgpu_base_API_deregister_nspace_fn_t deregister_nspace; pmix_pgpu_base_module_collect_inventory_fn_t collect_inventory; pmix_pgpu_base_module_deliver_inventory_fn_t deliver_inventory; } pmix_pgpu_API_module_t; /* declare the global APIs */ PMIX_EXPORT extern pmix_pgpu_API_module_t pmix_pgpu; /* * the standard component data structure */ typedef pmix_mca_base_component_t pmix_pgpu_base_component_t; /* * Macro for use in components that are of type pgpu */ #define PMIX_PGPU_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("pgpu", 1, 0, 0) END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/psec/0000775000175000017500000000000015203536752015756 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/psec/native/0000775000175000017500000000000015203536752017244 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/psec/native/psec_native_component.c0000664000175000017500000000557215203536752024003 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "psec_native.h" #include "src/mca/psec/psec.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_psec_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_psec_base_component_t pmix_mca_psec_native_component = { .base = { PMIX_PSEC_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "native", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, psec, native) static int component_open(void) { return PMIX_SUCCESS; } static int component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 10; *module = (pmix_mca_base_module_t *) &pmix_native_module; return PMIX_SUCCESS; } static int component_close(void) { return PMIX_SUCCESS; } static pmix_psec_module_t *assign_module(void) { return &pmix_native_module; } pmix-6.1.1~rc2/src/mca/psec/native/Makefile.am0000664000175000017500000000346015203536752021303 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = psec_native.h sources = \ psec_native_component.c \ psec_native.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_psec_native_DSO lib = lib_sources = component = pmix_mca_psec_native.la component_sources = $(headers) $(sources) else lib = libpmix_mca_psec_native.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_psec_native_la_SOURCES = $(component_sources) pmix_mca_psec_native_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_psec_native_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_psec_native_la_SOURCES = $(lib_sources) libpmix_mca_psec_native_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/psec/native/psec_native.h0000664000175000017500000000104715203536752021717 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_NATIVE_H #define PMIX_NATIVE_H #include "src/include/pmix_config.h" #include "src/mca/psec/psec.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_psec_base_component_t pmix_mca_psec_native_component; extern pmix_psec_module_t pmix_native_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/psec/native/psec_native.c0000664000175000017500000002360215203536752021713 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_SYS_TYPES_H # include #endif #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "psec_native.h" #include "src/mca/psec/base/base.h" static pmix_status_t native_init(void); static void native_finalize(void); static pmix_status_t create_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, pmix_byte_object_t *cred); static pmix_status_t validate_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, const pmix_byte_object_t *cred); pmix_psec_module_t pmix_native_module = {.name = "native", .init = native_init, .finalize = native_finalize, .create_cred = create_cred, .validate_cred = validate_cred}; static pmix_status_t native_init(void) { pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: native init"); return PMIX_SUCCESS; } static void native_finalize(void) { pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: native finalize"); } static pmix_status_t create_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, pmix_byte_object_t *cred) { pmix_peer_t *pr = (pmix_peer_t *) peer; char **types; size_t n, m; bool takeus; uid_t euid; gid_t egid; char *tmp, *ptr; /* ensure initialization */ PMIX_BYTE_OBJECT_CONSTRUCT(cred); /* we may be responding to a local request for a credential, so * see if they specified a mechanism */ if (NULL != directives && 0 < ndirs) { /* cycle across the provided info and see if they specified * any desired credential types */ takeus = true; for (n = 0; n < ndirs; n++) { if (0 == strncmp(directives[n].key, PMIX_CRED_TYPE, PMIX_MAX_KEYLEN)) { /* see if we are included */ types = PMIx_Argv_split(directives[n].value.data.string, ','); /* start by assuming they don't want us */ takeus = false; for (m = 0; NULL != types[m]; m++) { if (0 == strcmp(types[m], "native")) { /* it's us! */ takeus = true; break; } } PMIx_Argv_free(types); break; } } if (!takeus) { PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_SUPPORTED; } } if (PMIX_PROTOCOL_V1 == pr->protocol) { /* usock protocol - nothing to do */ goto complete; } else if (PMIX_PROTOCOL_V2 == pr->protocol) { /* tcp protocol - need to provide our effective * uid and gid for validation on remote end */ tmp = (char *) malloc(sizeof(uid_t) + sizeof(gid_t)); if (NULL == tmp) { return PMIX_ERR_NOMEM; } euid = geteuid(); memcpy(tmp, &euid, sizeof(uid_t)); ptr = tmp + sizeof(uid_t); egid = getegid(); memcpy(ptr, &egid, sizeof(gid_t)); cred->bytes = tmp; cred->size = sizeof(uid_t) + sizeof(gid_t); goto complete; } else { /* unrecognized protocol */ PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_SUPPORTED; } complete: if (NULL != info) { /* mark that this came from us */ PMIX_INFO_CREATE(*info, 1); if (NULL == *info) { return PMIX_ERR_NOMEM; } *ninfo = 1; PMIX_INFO_LOAD(info[0], PMIX_CRED_TYPE, "native", PMIX_STRING); } return PMIX_SUCCESS; } static pmix_status_t validate_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, const pmix_byte_object_t *cred) { pmix_peer_t *pr = (pmix_peer_t *) peer; #if defined(SO_PEERCRED) # ifdef HAVE_STRUCT_SOCKPEERCRED_UID # define HAVE_STRUCT_UCRED_UID struct sockpeercred ucred; # else struct ucred ucred; # endif socklen_t crlen = sizeof(ucred); #endif uid_t euid = (uid_t) -1; gid_t egid = (gid_t) -1; char *ptr; size_t ln; bool takeus; char **types; size_t n, m; uint32_t u32; pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: native validate_cred %s", (NULL == cred) ? "NULL" : "NON-NULL"); if (PMIX_PROTOCOL_V1 == pr->protocol) { /* usock protocol - get the remote side's uid/gid */ #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID)) /* Ignore received 'cred' and validate ucred for socket instead. */ pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec:native checking getsockopt on socket %d for peer credentials", pr->sd); if (getsockopt(pr->sd, SOL_SOCKET, SO_PEERCRED, &ucred, &crlen) < 0) { pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: getsockopt SO_PEERCRED failed: %s", strerror(pmix_socket_errno)); return PMIX_ERR_INVALID_CRED; } # if defined(HAVE_STRUCT_UCRED_UID) euid = ucred.uid; egid = ucred.gid; # else euid = ucred.cr_uid; egid = ucred.cr_gid; # endif #elif defined(HAVE_GETPEEREID) pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec:native checking getpeereid on socket %d for peer credentials", pr->sd); if (0 != getpeereid(pr->sd, &euid, &egid)) { pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: getsockopt getpeereid failed: %s", strerror(pmix_socket_errno)); return PMIX_ERR_INVALID_CRED; } #else return PMIX_ERR_NOT_SUPPORTED; #endif } else if (PMIX_PROTOCOL_V2 == pr->protocol) { /* this is a tcp protocol, so the cred is actually the uid/gid * passed upwards from the client */ if (NULL == cred) { /* not allowed */ return PMIX_ERR_INVALID_CRED; } ln = cred->size; euid = 0; egid = 0; if (sizeof(uid_t) <= ln) { memcpy(&euid, cred->bytes, sizeof(uid_t)); ln -= sizeof(uid_t); ptr = cred->bytes + sizeof(uid_t); } else { return PMIX_ERR_INVALID_CRED; } if (sizeof(gid_t) <= ln) { memcpy(&egid, ptr, sizeof(gid_t)); } else { return PMIX_ERR_INVALID_CRED; } } else if (PMIX_PROTOCOL_UNDEF != pr->protocol) { /* don't recognize the protocol */ return PMIX_ERR_NOT_SUPPORTED; } /* if we are responding to a local request to validate a credential, * then see if they specified a mechanism */ if (NULL != directives && 0 < ndirs) { for (n = 0; n < ndirs; n++) { if (0 == strncmp(directives[n].key, PMIX_CRED_TYPE, PMIX_MAX_KEYLEN)) { /* split the specified string */ types = PMIx_Argv_split(directives[n].value.data.string, ','); takeus = false; for (m = 0; NULL != types[m]; m++) { if (0 == strcmp(types[m], "native")) { /* it's us! */ takeus = true; break; } } PMIx_Argv_free(types); if (!takeus) { return PMIX_ERR_NOT_SUPPORTED; } } } } /* check uid */ if (euid != pr->info->uid) { pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: socket cred contains invalid uid %u - required uid %u", euid, pr->info->uid); return PMIX_ERR_INVALID_CRED; } /* check gid */ if (egid != pr->info->gid) { pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: socket cred contains invalid gid %u - required gid %u", egid, pr->info->gid); return PMIX_ERR_INVALID_CRED; } /* validated - mark that we did it */ if (NULL != info) { PMIX_INFO_CREATE(*info, 3); if (NULL == *info) { return PMIX_ERR_NOMEM; } *ninfo = 3; /* mark that this came from us */ PMIX_INFO_LOAD(info[0], PMIX_CRED_TYPE, "native", PMIX_STRING); /* provide the uid it contained */ u32 = euid; PMIX_INFO_LOAD(info[1], PMIX_USERID, &u32, PMIX_UINT32); /* provide the gid it contained */ u32 = egid; PMIX_INFO_LOAD(info[2], PMIX_GRPID, &u32, PMIX_UINT32); } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/psec/psec.h0000664000175000017500000002314015203536752017061 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * This interface is for psecurity support. PMIx doesn't need much in * this regard, but we do need a mechanism for authenticating connections. * * Only *one* plugin will be active in a client, but multiple plugins may * be active in a server. Thus, this is a multi-select framework. * * Available plugins may be defined at runtime via the typical MCA parameter * syntax. */ #ifndef PMIX_PSEC_H #define PMIX_PSEC_H #include "src/include/pmix_config.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/mca.h" #include "src/mca/ptl/ptl_types.h" BEGIN_C_DECLS /* forward declaration */ struct pmix_peer_t; /****** MODULE DEFINITION ******/ /** * Initialize the module. Returns an error if the module cannot * run, success if it can and wants to be used. */ typedef pmix_status_t (*pmix_psec_base_module_init_fn_t)(void); /** * Finalize the module. Tear down any allocated storage, disconnect * from any system support (e.g., LDAP server) */ typedef void (*pmix_psec_base_module_fini_fn_t)(void); /**** CLIENT-SIDE FUNCTIONS ****/ /** * Create and return a credential for this client - this * could be a string or a byte array, which is why we must * also return the length. The directives contain info on * desired credential type, or other directives used by * the credential agent. The returned info array typically * contains the name of the agent issuing the credential, * plus any other info the agent chooses to return. */ typedef pmix_status_t (*pmix_psec_base_module_create_cred_fn_t)(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, pmix_byte_object_t *cred); /** * Perform the client-side handshake. Note that it is not required * (and indeed, would be rare) for a protocol to use both the * credential and handshake interfaces. It is acceptable, therefore, * for one of them to be NULL */ typedef pmix_status_t (*pmix_psec_base_module_client_hndshk_fn_t)(int sd); /**** SERVER-SIDE FUNCTIONS ****/ /** * Validate a client's credential - the credential could be a string * or an array of bytes, which is why we include the length. The directives * contain information provided by the requestor to aid in the validation * process - e.g., the uid/gid of the process seeking validation, or * the name of the agent being asked to perform the validation. The * returned info array typically contains the name of the agent that * actually performed the validation, plus any other info the agent * chooses to return (e.g., the uid/gid contained in the credential) */ typedef pmix_status_t (*pmix_psec_base_module_validate_cred_fn_t)(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, const pmix_byte_object_t *cred); /** * Perform the server-side handshake. Note that it is not required * (and indeed, would be rare) for a protocol to use both the * credential and handshake interfaces. It is acceptable, therefore, * for one of them to be NULL */ typedef pmix_status_t (*pmix_psec_base_module_server_hndshk_fn_t)(int sd); /** * Base structure for a PSEC module */ typedef struct { char *name; /* init/finalize */ pmix_psec_base_module_init_fn_t init; pmix_psec_base_module_fini_fn_t finalize; /** Client-side */ pmix_psec_base_module_create_cred_fn_t create_cred; pmix_psec_base_module_client_hndshk_fn_t client_handshake; /** Server-side */ pmix_psec_base_module_validate_cred_fn_t validate_cred; pmix_psec_base_module_server_hndshk_fn_t server_handshake; } pmix_psec_module_t; /* define an API module */ /* get a list of available options - caller must free results * when done */ PMIX_EXPORT char *pmix_psec_base_get_available_modules(void); /* Select a psec module for a given peer */ PMIX_EXPORT pmix_psec_module_t *pmix_psec_base_assign_module(const char *options); /* MACROS FOR EXECUTING PSEC FUNCTIONS */ #define PMIX_PSEC_CREATE_CRED(r, p, d, nd, in, nin, c) \ (r) = (p)->nptr->compat.psec->create_cred((struct pmix_peer_t *) (p), (d), (nd), (in), (nin), c) #define PMIX_PSEC_CLIENT_HANDSHAKE(r, p, sd) (r) = (p)->nptr->compat.psec->client_handshake(sd) #define PMIX_PSEC_VALIDATE_CRED(r, p, d, nd, in, nin, c) \ (r) = (p)->nptr->compat.psec->validate_cred((struct pmix_peer_t *) (p), (d), (nd), (in), \ (nin), c) #define PMIX_PSEC_VALIDATE_CONNECTION(r, p, d, nd, in, nin, c) \ do { \ int _r; \ /* if a credential is available, then check it */ \ if (NULL != (p)->nptr->compat.psec->validate_cred) { \ _r = (p)->nptr->compat.psec->validate_cred((struct pmix_peer_t *) (p), (d), (nd), \ (in), (nin), c); \ if (PMIX_SUCCESS != _r) { \ pmix_output_verbose(2, pmix_globals.debug_output, \ "validation of credential failed: %s", PMIx_Error_string(_r)); \ } else { \ pmix_output_verbose(2, pmix_globals.debug_output, "credential validated"); \ } \ (r) = _r; \ } else if (NULL != (p)->nptr->compat.psec->server_handshake) { \ /* request the handshake if the security mode calls for it */ \ pmix_output_verbose(2, pmix_globals.debug_output, "requesting handshake"); \ _r = PMIX_ERR_READY_FOR_HANDSHAKE; \ (r) = _r; \ } else { \ /* this is not allowed */ \ (r) = PMIX_ERR_NOT_SUPPORTED; \ } \ } while (0) #define PMIX_PSEC_SERVER_HANDSHAKE_IFNEED(r, p) \ if (PMIX_ERR_READY_FOR_HANDSHAKE == r) { \ int _r; \ /* execute the handshake if the security mode calls for it */ \ pmix_output_verbose(2, pmix_globals.debug_output, "executing handshake"); \ if (PMIX_SUCCESS != (_r = p->nptr->compat.psec->server_handshake((p)->sd))) { \ PMIX_ERROR_LOG(_r); \ } \ /* Update the reply status */ \ (r) = _r; \ } /**** COMPONENT STRUCTURE DEFINITION ****/ /* define a component-level API for initializing the component */ typedef pmix_status_t (*pmix_psec_base_component_init_fn_t)(void); /* define a component-level API for finalizing the component */ typedef void (*pmix_psec_base_component_finalize_fn_t)(void); /* define a component-level API for getting a module */ typedef pmix_psec_module_t *(*pmix_psec_base_component_assign_module_fn_t)(void); /* * the standard component data structure */ struct pmix_psec_base_component_t { pmix_mca_base_component_t base; int priority; pmix_psec_base_component_init_fn_t init; pmix_psec_base_component_finalize_fn_t finalize; pmix_psec_base_component_assign_module_fn_t assign_module; }; typedef struct pmix_psec_base_component_t pmix_psec_base_component_t; /* * Macro for use in components that are of type psec */ #define PMIX_PSEC_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("psec", 1, 0, 0) END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/psec/dummy_handshake/0000775000175000017500000000000015203536752021117 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/psec/dummy_handshake/psec_dummy_handshake.h0000664000175000017500000000133415203536752025444 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_SIMPLE_H #define PMIX_SIMPLE_H #include "src/include/pmix_config.h" #include "src/mca/psec/psec.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_psec_base_component_t pmix_mca_psec_dummy_handshake_component; extern pmix_psec_module_t pmix_dummy_handshake_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/psec/dummy_handshake/psec_dummy_handshake.c0000664000175000017500000001201315203536752025433 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_SYS_TYPES_H # include #endif #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "psec_dummy_handshake.h" #include "src/mca/psec/base/base.h" #include "src/mca/ptl/base/base.h" #define PMIX_PSEC_DUMMY_HNDSHK_STR "PMIX_PSEC_DUMMY_HANDSHAKE_STRING" static pmix_status_t simple_init(void); static void simple_finalize(void); static pmix_status_t create_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, pmix_byte_object_t *cred); static pmix_status_t client_hndshk(int sd); static pmix_status_t server_hndshk(int sd); pmix_psec_module_t pmix_dummy_handshake_module = {.name = "dummy_handshake", /** init/finalize */ .init = simple_init, .finalize = simple_finalize, /** Client-side */ .create_cred = create_cred, .client_handshake = client_hndshk, /** Server-side */ .validate_cred = NULL, .server_handshake = server_hndshk}; static pmix_status_t simple_init(void) { pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: simple init"); return PMIX_SUCCESS; } static void simple_finalize(void) { pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: simple finalize"); } static pmix_status_t create_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, pmix_byte_object_t *cred) { char mycred[] = "dymmy_cred"; pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: simple create_cred"); /* ensure initialization */ PMIX_BYTE_OBJECT_CONSTRUCT(cred); cred->bytes = strdup(mycred); cred->size = strlen(mycred) + 1; return PMIX_SUCCESS; } static pmix_status_t server_hndshk(int sd) { pmix_status_t rc, status = PMIX_SUCCESS; char *hndshk_msg = NULL; size_t size; pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: simple server_hndshk"); pmix_asprintf(&hndshk_msg, "%s", PMIX_PSEC_DUMMY_HNDSHK_STR); size = strlen(hndshk_msg); /* send size of handshake message */ if (PMIX_SUCCESS != (rc = pmix_ptl_base_send_blocking(sd, (char *) &size, sizeof(size)))) { goto exit; } /* send handshake message */ if (PMIX_SUCCESS != (rc = pmix_ptl_base_send_blocking(sd, hndshk_msg, size))) { goto exit; } /* recv hadshake status from client */ if (PMIX_SUCCESS != (rc = pmix_ptl_base_recv_blocking(sd, (char *) &status, sizeof(status)))) { goto exit; } rc = status; pmix_output(0, "[%s:%d] psec handshake status %d recv from client", __FILE__, __LINE__, status); exit: if (NULL != hndshk_msg) { free(hndshk_msg); } return rc; } static pmix_status_t client_hndshk(int sd) { char *hndshk_msg = NULL; size_t size; pmix_status_t rc, status = PMIX_SUCCESS; pmix_output_verbose(2, pmix_psec_base_framework.framework_output, "psec: simple client_hndshk"); /* recv size of handshake message */ if (PMIX_SUCCESS != (rc = pmix_ptl_base_recv_blocking(sd, (char *) &size, sizeof(size_t)))) { return rc; } hndshk_msg = (char *) malloc(size); /* recv handshake message */ if (PMIX_SUCCESS != (rc = pmix_ptl_base_recv_blocking(sd, (char *) hndshk_msg, size))) { free(hndshk_msg); return rc; } /* verifying handshake data */ if (size != strlen(PMIX_PSEC_DUMMY_HNDSHK_STR)) { rc = PMIX_ERR_HANDSHAKE_FAILED; goto exit; } if (0 != strncmp(hndshk_msg, PMIX_PSEC_DUMMY_HNDSHK_STR, size)) { rc = PMIX_ERR_HANDSHAKE_FAILED; goto exit; } /* send hadshake status to the server */ status = PMIX_SUCCESS; if (PMIX_SUCCESS != (rc = pmix_ptl_base_send_blocking(sd, (char *) &status, sizeof(status)))) { goto exit; } pmix_output(0, "[%s:%d] psec handshake status %d sent to server", __FILE__, __LINE__, status); exit: if (NULL != hndshk_msg) { free(hndshk_msg); } return rc; } pmix-6.1.1~rc2/src/mca/psec/dummy_handshake/psec_dummy_handshake_component.c0000664000175000017500000000377515203536752027534 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "psec_dummy_handshake.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/psec/psec.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_psec_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_psec_base_component_t pmix_mca_psec_dummy_handshake_component = { .base = { PMIX_PSEC_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "dummy_handshake", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, psec, dummy_handshake) static int component_open(void) { return PMIX_SUCCESS; } static int component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 100; *module = (pmix_mca_base_module_t *) &pmix_dummy_handshake_module; return PMIX_SUCCESS; } static int component_close(void) { return PMIX_SUCCESS; } static pmix_psec_module_t *assign_module(void) { return &pmix_dummy_handshake_module; } pmix-6.1.1~rc2/src/mca/psec/dummy_handshake/Makefile.am0000664000175000017500000000404215203536752023153 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2019 Mellanox Technologies, Inc. # All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # if MCA_BUILD_PSEC_DUMMY_HANDSHAKE headers = psec_dummy_handshake.h sources = \ psec_dummy_handshake_component.c \ psec_dummy_handshake.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_psec_dummy_handshake_DSO lib = lib_sources = component = pmix_mca_psec_dummy_handshake.la component_sources = $(headers) $(sources) else lib = libpmix_mca_psec_dummy_handshake.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_psec_dummy_handshake_la_SOURCES = $(component_sources) pmix_mca_psec_dummy_handshake_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_psec_dummy_handshake_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_psec_dummy_handshake_la_SOURCES = $(lib_sources) libpmix_mca_psec_dummy_handshake_la_LDFLAGS = -module -avoid-version endif pmix-6.1.1~rc2/src/mca/psec/munge/0000775000175000017500000000000015203536752017071 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/psec/munge/psec_munge.h0000664000175000017500000000104215203536752021364 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_MUNGE_H #define PMIX_MUNGE_H BEGIN_C_DECLS #include "src/include/pmix_config.h" #include "src/mca/psec/psec.h" /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_psec_base_component_t pmix_mca_psec_munge_component; extern pmix_psec_module_t pmix_munge_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/psec/munge/psec_munge.c0000664000175000017500000002034415203536752021365 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * NOTE: THE MUNGE CLIENT LIBRARY (libmunge) IS LICENSED AS LGPL * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include #ifdef HAVE_SYS_TYPES_H # include #endif // define abstractions to test compile this component #if 0 typedef int32_t munge_err_t; typedef struct { int32_t idx; } munge_ctx_t; #define EMUNGE_SUCCESS 0 static inline munge_err_t munge_encode (char **cred, munge_ctx_t *ctx, const void *buf, int len) { PMIX_HIDE_UNUSED_PARAMS(cred, ctx, buf, len); return EMUNGE_SUCCESS; } static inline munge_err_t munge_decode (const char *cred, munge_ctx_t *ctx, void **buf, int *len, uid_t *uid, gid_t *gid) { PMIX_HIDE_UNUSED_PARAMS(cred, ctx, buf, len, uid, gid); return EMUNGE_SUCCESS; } static inline const char * munge_strerror (munge_err_t e) { PMIX_HIDE_UNUSED_PARAMS(e); return "FOO"; } #else #include #endif #include "psec_munge.h" #include "src/mca/psec/psec.h" #include "src/threads/pmix_threads.h" static pmix_status_t munge_init(void); static void munge_finalize(void); static pmix_status_t create_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, pmix_byte_object_t *cred); static pmix_status_t validate_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, const pmix_byte_object_t *cred); pmix_psec_module_t pmix_munge_module = {.name = "munge", .init = munge_init, .finalize = munge_finalize, .create_cred = create_cred, .validate_cred = validate_cred}; static char *mycred = NULL; static bool initialized = false; static bool refresh = false; static pmix_status_t munge_init(void) { int rc; pmix_output_verbose(2, pmix_globals.debug_output, "psec: munge init"); /* attempt to get a credential as a way of checking that * the munge server is available - cache the credential * for later use */ if (EMUNGE_SUCCESS != (rc = munge_encode(&mycred, NULL, NULL, 0))) { pmix_output_verbose(2, pmix_globals.debug_output, "psec: munge failed to create credential: %s", munge_strerror(rc)); return PMIX_ERR_SERVER_NOT_AVAIL; } initialized = true; return PMIX_SUCCESS; } static void munge_finalize(void) { pmix_output_verbose(2, pmix_globals.debug_output, "psec: munge finalize"); if (initialized) { if (NULL != mycred) { free(mycred); mycred = NULL; } } } static pmix_status_t create_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, pmix_byte_object_t *cred) { int rc; bool takeus; char **types; size_t n, m; PMIX_HIDE_UNUSED_PARAMS(peer); pmix_output_verbose(2, pmix_globals.debug_output, "psec: munge create_cred"); /* ensure initialization */ PMIX_BYTE_OBJECT_CONSTRUCT(cred); /* if we are responding to a local request to create a credential, * then see if they specified a mechanism */ if (NULL != directives && 0 < ndirs) { for (n = 0; n < ndirs; n++) { if (0 == strncmp(directives[n].key, PMIX_CRED_TYPE, PMIX_MAX_KEYLEN)) { /* split the specified string */ types = PMIx_Argv_split(directives[n].value.data.string, ','); takeus = false; for (m = 0; NULL != types[m]; m++) { if (0 == strcmp(types[m], "munge")) { /* it's us! */ takeus = true; break; } } PMIx_Argv_free(types); if (!takeus) { return PMIX_ERR_NOT_SUPPORTED; } } } } if (initialized) { if (!refresh) { refresh = true; cred->bytes = strdup(mycred); cred->size = strlen(mycred) + 1; } else { /* munge does not allow reuse of a credential, so we have to * refresh it for every use */ if (NULL != mycred) { free(mycred); } if (EMUNGE_SUCCESS != (rc = munge_encode(&mycred, NULL, NULL, 0))) { pmix_output_verbose(2, pmix_globals.debug_output, "psec: munge failed to create credential: %s", munge_strerror(rc)); return PMIX_ERR_NOT_SUPPORTED; } cred->bytes = strdup(mycred); cred->size = strlen(mycred) + 1; } } if (NULL != info) { /* mark that this came from us */ PMIX_INFO_CREATE(*info, 1); if (NULL == *info) { return PMIX_ERR_NOMEM; } *ninfo = 1; PMIX_INFO_LOAD(info[0], PMIX_CRED_TYPE, "munge", PMIX_STRING); } return PMIX_SUCCESS; } static pmix_status_t validate_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, const pmix_byte_object_t *cred) { pmix_peer_t *pr = (pmix_peer_t *) peer; uid_t euid; gid_t egid; munge_err_t rc; bool takeus; char **types; size_t n, m; uint32_t u32; pmix_output_verbose(2, pmix_globals.debug_output, "psec: munge validate_cred %s", (NULL == cred) ? "NULL" : "NON-NULL"); /* if we are responding to a local request to validate a credential, * then see if they specified a mechanism */ if (NULL != directives && 0 < ndirs) { for (n = 0; n < ndirs; n++) { if (0 == strncmp(directives[n].key, PMIX_CRED_TYPE, PMIX_MAX_KEYLEN)) { /* split the specified string */ types = PMIx_Argv_split(directives[n].value.data.string, ','); takeus = false; for (m = 0; NULL != types[m]; m++) { if (0 == strcmp(types[m], "munge")) { /* it's us! */ takeus = true; break; } } PMIx_Argv_free(types); if (!takeus) { return PMIX_ERR_NOT_SUPPORTED; } } } } /* parse the inbound string */ if (EMUNGE_SUCCESS != (rc = munge_decode(cred->bytes, NULL, NULL, NULL, &euid, &egid))) { pmix_output_verbose(2, pmix_globals.debug_output, "psec: munge failed to decode credential: %s", munge_strerror(rc)); return PMIX_ERR_INVALID_CRED; } /* check uid */ if (euid != pr->info->uid) { return PMIX_ERR_INVALID_CRED; } /* check guid */ if (egid != pr->info->gid) { return PMIX_ERR_INVALID_CRED; } pmix_output_verbose(2, pmix_globals.debug_output, "psec: munge credential valid"); if (NULL != info) { PMIX_INFO_CREATE(*info, 3); if (NULL == *info) { return PMIX_ERR_NOMEM; } *ninfo = 3; /* mark that this came from us */ PMIX_INFO_LOAD(info[0], PMIX_CRED_TYPE, "munge", PMIX_STRING); /* provide the uid it contained */ u32 = euid; PMIX_INFO_LOAD(info[1], PMIX_USERID, &u32, PMIX_UINT32); /* provide the gid it contained */ u32 = egid; PMIX_INFO_LOAD(info[2], PMIX_GRPID, &u32, PMIX_UINT32); } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/psec/munge/configure.m40000664000175000017500000000341715203536752021321 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2015-2016 Intel, Inc. All rights reserved # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_psec_munge_CONFIG([action-if-found], [action-if-not-found]) # -------------------------------------------------------------------- AC_DEFUN([MCA_pmix_psec_munge_CONFIG],[ AC_CONFIG_FILES([src/mca/psec/munge/Makefile]) AC_ARG_WITH([munge], [AS_HELP_STRING([--with-munge=DIR], [Search for munge headers and libraries in DIR ])]) AC_ARG_WITH([munge-libdir], [AS_HELP_STRING([--with-munge-libdir=DIR], [Search for munge libraries in DIR ])]) OAC_CHECK_PACKAGE([munge], [psec_munge], [munge.h], [munge], [munge_encode], [psec_munge_support=1], [psec_munge_support=0]) if test -n "$with_munge" && test "$with_munge" != "no" && test "$psec_munge_support" != "1"; then AC_MSG_WARN([MUNGE SUPPORT REQUESTED AND NOT FOUND.]) AC_MSG_ERROR([CANNOT CONTINUE]) fi AS_IF([test "$psec_munge_support" != "1"], [$2], [$1]) PMIX_SUMMARY_ADD([External Packages], [munge], [], [${psec_munge_SUMMARY}]) # set build flags to use in makefile AC_SUBST([psec_munge_CPPFLAGS]) AC_SUBST([psec_munge_LDFLAGS]) AC_SUBST([psec_munge_LIBS]) ])dnl pmix-6.1.1~rc2/src/mca/psec/munge/psec_munge_component.c0000664000175000017500000000556415203536752023456 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "psec_munge.h" #include "src/mca/psec/psec.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_psec_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_psec_base_component_t pmix_mca_psec_munge_component = { .base = { PMIX_PSEC_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "munge", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, psec, munge) static int component_open(void) { return PMIX_SUCCESS; } static int component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 80; *module = (pmix_mca_base_module_t *) &pmix_munge_module; return PMIX_SUCCESS; } static int component_close(void) { return PMIX_SUCCESS; } static pmix_psec_module_t *assign_module(void) { return &pmix_munge_module; } pmix-6.1.1~rc2/src/mca/psec/munge/Makefile.am0000664000175000017500000000374115203536752021132 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(psec_munge_CPPFLAGS) headers = psec_munge.h sources = \ psec_munge_component.c \ psec_munge.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_psec_munge_DSO lib = lib_sources = component = pmix_mca_psec_munge.la component_sources = $(headers) $(sources) else lib = libpmix_mca_psec_munge.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_psec_munge_la_SOURCES = $(component_sources) pmix_mca_psec_munge_la_LDFLAGS = -module -avoid-version $(psec_munge_LDFLAGS) pmix_mca_psec_munge_la_LIBADD = $(psec_munge_LIBS) if NEED_LIBPMIX pmix_mca_psec_munge_la_LIBADD += $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_psec_munge_la_SOURCES = $(lib_sources) libpmix_mca_psec_munge_la_LDFLAGS = -module -avoid-version $(psec_munge_LDFLAGS) libpmix_mca_psec_munge_la_LIBADD = $(psec_munge_LIBS) pmix-6.1.1~rc2/src/mca/psec/none/0000775000175000017500000000000015203536752016715 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/psec/none/psec_none.c0000664000175000017500000000760115203536752021036 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include #ifdef HAVE_SYS_TYPES_H # include #endif #include "psec_none.h" #include "src/mca/psec/psec.h" static pmix_status_t none_init(void); static void none_finalize(void); static pmix_status_t create_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, pmix_byte_object_t *cred); static pmix_status_t validate_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, const pmix_byte_object_t *cred); pmix_psec_module_t pmix_none_module = {.name = "none", .init = none_init, .finalize = none_finalize, .create_cred = create_cred, .validate_cred = validate_cred}; static pmix_status_t none_init(void) { pmix_output_verbose(2, pmix_globals.debug_output, "psec: none init"); return PMIX_SUCCESS; } static void none_finalize(void) { pmix_output_verbose(2, pmix_globals.debug_output, "psec: none finalize"); } static pmix_status_t create_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, pmix_byte_object_t *cred) { PMIX_HIDE_UNUSED_PARAMS(peer, directives, ndirs, info, ninfo); /* ensure initialization */ PMIX_BYTE_OBJECT_CONSTRUCT(cred); return PMIX_SUCCESS; } static pmix_status_t validate_cred(struct pmix_peer_t *peer, const pmix_info_t directives[], size_t ndirs, pmix_info_t **info, size_t *ninfo, const pmix_byte_object_t *cred) { size_t n, m; char **types; bool takeus; pmix_output_verbose(2, pmix_globals.debug_output, "psec: none always reports valid"); PMIX_HIDE_UNUSED_PARAMS(peer, cred); /* if we are responding to a local request to validate a credential, * then see if they specified a mechanism */ if (NULL != directives && 0 < ndirs) { for (n = 0; n < ndirs; n++) { if (0 == strncmp(directives[n].key, PMIX_CRED_TYPE, PMIX_MAX_KEYLEN)) { /* split the specified string */ types = PMIx_Argv_split(directives[n].value.data.string, ','); takeus = false; for (m = 0; NULL != types[m]; m++) { if (0 == strcmp(types[m], "none")) { /* it's us! */ takeus = true; break; } } PMIx_Argv_free(types); if (!takeus) { return PMIX_ERR_NOT_SUPPORTED; } } } } /* mark that this came from us */ if (NULL != info) { /* mark that this came from us */ PMIX_INFO_CREATE(*info, 1); if (NULL == *info) { return PMIX_ERR_NOMEM; } *ninfo = 1; PMIX_INFO_LOAD(info[0], PMIX_CRED_TYPE, "none", PMIX_STRING); } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/psec/none/psec_none.h0000664000175000017500000000104315203536752021035 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_NATIVE_H #define PMIX_NATIVE_H #include "src/include/pmix_config.h" #include "src/mca/psec/psec.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_psec_base_component_t pmix_mca_psec_none_component; extern pmix_psec_module_t pmix_none_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/psec/none/Makefile.am0000664000175000017500000000343215203536752020753 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = psec_none.h sources = \ psec_none_component.c \ psec_none.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_psec_none_DSO lib = lib_sources = component = pmix_mca_psec_none.la component_sources = $(headers) $(sources) else lib = libpmix_mca_psec_none.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_psec_none_la_SOURCES = $(component_sources) pmix_mca_psec_none_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_psec_none_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_psec_none_la_SOURCES = $(lib_sources) libpmix_mca_psec_none_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/psec/none/psec_none_component.c0000664000175000017500000000664215203536752023124 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "psec_none.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/psec/psec.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_psec_module_t *assign_module(void); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_psec_base_component_t pmix_mca_psec_none_component = { .base = { PMIX_PSEC_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "none", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }, .assign_module = assign_module }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, psec, none) static int component_open(void) { int index; const pmix_mca_base_var_storage_t *value = NULL; /* we only allow ourselves to be considered IF the user * specifically requested so */ if (0 > (index = pmix_mca_base_var_find("pmix", "psec", NULL, NULL))) { return PMIX_ERROR; } pmix_mca_base_var_get_value(index, &value, NULL, NULL); if (NULL != value && NULL != value->stringval && '\0' != value->stringval[0]) { if (NULL != strstr(value->stringval, "none")) { return PMIX_SUCCESS; } } return PMIX_ERROR; } static int component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 0; *module = (pmix_mca_base_module_t *) &pmix_none_module; return PMIX_SUCCESS; } static int component_close(void) { return PMIX_SUCCESS; } static pmix_psec_module_t *assign_module(void) { return &pmix_none_module; } pmix-6.1.1~rc2/src/mca/psec/base/0000775000175000017500000000000015203536752016670 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/psec/base/psec_base_select.c0000664000175000017500000001261615203536752022325 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/util/pmix_error.h" #include "src/util/pmix_show_help.h" #include "src/mca/psec/base/base.h" /* Function for selecting a prioritized list of components * from all those that are available. */ int pmix_psec_base_select(void) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_mca_base_component_t *component = NULL; pmix_mca_base_module_t *module = NULL; pmix_psec_module_t *nmodule; pmix_psec_base_active_module_t *newmodule, *mod; int rc, priority; bool inserted; if (pmix_psec_globals.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_psec_globals.selected = true; /* Query all available components and ask if they have a module */ PMIX_LIST_FOREACH (cli, &pmix_psec_base_framework.framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_mca_base_component_t *) cli->cli_component; pmix_output_verbose(5, pmix_psec_base_framework.framework_output, "mca:psec:select: checking available component %s", component->pmix_mca_component_name); /* If there's no query function, skip it */ if (NULL == component->pmix_mca_query_component) { pmix_output_verbose( 5, pmix_psec_base_framework.framework_output, "mca:psec:select: Skipping component [%s]. It does not implement a query function", component->pmix_mca_component_name); continue; } /* Query the component */ pmix_output_verbose(5, pmix_psec_base_framework.framework_output, "mca:psec:select: Querying component [%s]", component->pmix_mca_component_name); rc = component->pmix_mca_query_component(&module, &priority); /* If no module was returned, then skip component */ if (PMIX_SUCCESS != rc || NULL == module) { pmix_output_verbose( 5, pmix_psec_base_framework.framework_output, "mca:psec:select: Skipping component [%s]. Query failed to return a module", component->pmix_mca_component_name); continue; } nmodule = (pmix_psec_module_t *) module; /* give the module a chance to init */ if (NULL != nmodule->init && PMIX_SUCCESS != nmodule->init()) { /* failed to init, so skip it */ pmix_output_verbose(5, pmix_psec_base_framework.framework_output, "mca:psec:select: Skipping component [%s]. Failed to init", component->pmix_mca_component_name); continue; } /* If we got a module, keep it */ /* add to the list of selected modules */ newmodule = PMIX_NEW(pmix_psec_base_active_module_t); newmodule->pri = priority; newmodule->module = nmodule; newmodule->component = (pmix_psec_base_component_t *) cli->cli_component; /* maintain priority order */ inserted = false; PMIX_LIST_FOREACH (mod, &pmix_psec_globals.actives, pmix_psec_base_active_module_t) { if (priority > mod->pri) { pmix_list_insert_pos(&pmix_psec_globals.actives, (pmix_list_item_t *) mod, &newmodule->super); inserted = true; break; } } if (!inserted) { /* must be lowest priority - add to end */ pmix_list_append(&pmix_psec_globals.actives, &newmodule->super); } } /* if no modules were found, then that's an error as we require at least one */ if (0 == pmix_list_get_size(&pmix_psec_globals.actives)) { pmix_show_help("help-pmix-runtime.txt", "no-plugins", true, "PSEC"); return PMIX_ERR_SILENT; } if (4 < pmix_output_get_verbosity(pmix_psec_base_framework.framework_output)) { pmix_output(0, "Final psec priorities"); /* show the prioritized list */ PMIX_LIST_FOREACH (mod, &pmix_psec_globals.actives, pmix_psec_base_active_module_t) { pmix_output(0, "\tpsec: %s Priority: %d", mod->component->base.pmix_mca_component_name, mod->pri); } } return PMIX_SUCCESS; ; } pmix-6.1.1~rc2/src/mca/psec/base/psec_base_fns.c0000664000175000017500000000433215203536752021630 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/class/pmix_list.h" #include "src/mca/ptl/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/mca/psec/base/base.h" char *pmix_psec_base_get_available_modules(void) { pmix_psec_base_active_module_t *active; char **tmp = NULL, *reply = NULL; if (!pmix_psec_globals.initialized) { return NULL; } PMIX_LIST_FOREACH (active, &pmix_psec_globals.actives, pmix_psec_base_active_module_t) { PMIx_Argv_append_nosize(&tmp, active->component->base.pmix_mca_component_name); } if (NULL != tmp) { reply = PMIx_Argv_join(tmp, ','); PMIx_Argv_free(tmp); } return reply; } pmix_psec_module_t *pmix_psec_base_assign_module(const char *options) { pmix_psec_base_active_module_t *active; pmix_psec_module_t *mod; char **tmp = NULL; int i; if (!pmix_psec_globals.initialized) { return NULL; } if (NULL != options) { tmp = PMIx_Argv_split(options, ','); } PMIX_LIST_FOREACH (active, &pmix_psec_globals.actives, pmix_psec_base_active_module_t) { if (NULL == tmp) { if (NULL != (mod = active->component->assign_module())) { return mod; } } else { for (i = 0; NULL != tmp[i]; i++) { if (0 == strcmp(tmp[i], active->component->base.pmix_mca_component_name)) { if (NULL != (mod = active->component->assign_module())) { PMIx_Argv_free(tmp); return mod; } } } } } /* we only get here if nothing was found */ if (NULL != tmp) { PMIx_Argv_free(tmp); } return NULL; } pmix-6.1.1~rc2/src/mca/psec/base/base.h0000664000175000017500000000470315203536752017757 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PSEC_BASE_H_ #define PMIX_PSEC_BASE_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_pointer_array.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/mca.h" #include "src/mca/psec/psec.h" BEGIN_C_DECLS /* * MCA Framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_psec_base_framework; /** * PSEC select function * * Cycle across available components and construct the list * of active modules */ PMIX_EXPORT pmix_status_t pmix_psec_base_select(void); /** * Track an active component / module */ struct pmix_psec_base_active_module_t { pmix_list_item_t super; int pri; pmix_psec_module_t *module; pmix_psec_base_component_t *component; }; typedef struct pmix_psec_base_active_module_t pmix_psec_base_active_module_t; PMIX_CLASS_DECLARATION(pmix_psec_base_active_module_t); /* framework globals */ struct pmix_psec_globals_t { pmix_list_t actives; bool initialized; bool selected; }; typedef struct pmix_psec_globals_t pmix_psec_globals_t; PMIX_EXPORT extern pmix_psec_globals_t pmix_psec_globals; PMIX_EXPORT char *pmix_psec_base_get_available_modules(void); PMIX_EXPORT pmix_psec_module_t *pmix_psec_base_assign_module(const char *options); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/psec/base/Makefile.include0000664000175000017500000000221515203536752021752 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2016 Intel, Inc. All rights reserved # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from # src/Makefile.am headers += \ base/base.h sources += \ base/psec_base_frame.c \ base/psec_base_select.c \ base/psec_base_fns.c pmix-6.1.1~rc2/src/mca/psec/base/psec_base_frame.c0000664000175000017500000000616315203536752022140 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2009 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/psec/base/base.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public mca_base_component_t struct. */ #include "src/mca/psec/base/static-components.h" /* Instantiate the global vars */ pmix_psec_globals_t pmix_psec_globals = { .actives = PMIX_LIST_STATIC_INIT, .initialized = false, .selected = false }; static pmix_status_t pmix_psec_close(void) { pmix_psec_base_active_module_t *active, *prev; if (!pmix_psec_globals.initialized) { return PMIX_SUCCESS; } pmix_psec_globals.initialized = false; pmix_psec_globals.selected = false; PMIX_LIST_FOREACH_SAFE (active, prev, &pmix_psec_globals.actives, pmix_psec_base_active_module_t) { pmix_list_remove_item(&pmix_psec_globals.actives, &active->super); if (NULL != active->component->finalize) { active->component->finalize(); } PMIX_RELEASE(active); } PMIX_DESTRUCT(&pmix_psec_globals.actives); return pmix_mca_base_framework_components_close(&pmix_psec_base_framework, NULL); } static pmix_status_t pmix_psec_open(pmix_mca_base_open_flag_t flags) { /* initialize globals */ pmix_psec_globals.initialized = true; PMIX_CONSTRUCT(&pmix_psec_globals.actives, pmix_list_t); /* Open up all available components */ return pmix_mca_base_framework_components_open(&pmix_psec_base_framework, flags); } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, psec, "PMIx Security Operations", NULL, pmix_psec_open, pmix_psec_close, pmix_mca_psec_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); PMIX_CLASS_INSTANCE(pmix_psec_base_active_module_t, pmix_list_item_t, NULL, NULL); pmix-6.1.1~rc2/src/mca/psec/Makefile.am0000664000175000017500000000255015203536752020014 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(LTDLINCL) # main library setup noinst_LTLIBRARIES = libmca_psec.la libmca_psec_la_SOURCES = # local files headers = psec.h sources = # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.include libmca_psec_la_SOURCES += $(headers) $(sources) distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/Makefile.include0000664000175000017500000000172015203536752020106 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from src/Makefile.am # Source code files headers += \ mca/mca.h pmix-6.1.1~rc2/src/mca/plog/0000775000175000017500000000000015203536752015765 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/plog/plog.h0000664000175000017500000000501015203536752017073 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * This interface is for use by PMIx servers to obtain network-related info * such as security keys that need to be shared across applications, and to * setup network support for applications prior to launch * * Available plugins may be defined at runtime via the typical MCA parameter * syntax. */ #ifndef PMIX_PLOG_H #define PMIX_PLOG_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/mca.h" BEGIN_C_DECLS /****** MODULE DEFINITION ******/ /** * Initialize the module. Returns an error if the module cannot * run, success if it can and wants to be used. */ typedef pmix_status_t (*pmix_plog_base_module_init_fn_t)(void); /** * Finalize the module */ typedef void (*pmix_plog_base_module_fini_fn_t)(void); /** * Log data to channel, if possible */ typedef pmix_status_t (*pmix_plog_base_module_log_fn_t)(const pmix_proc_t *source, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs); /** * Base structure for a PLOG module */ typedef struct { char *name; char **channels; /* init/finalize */ pmix_plog_base_module_init_fn_t init; pmix_plog_base_module_fini_fn_t finalize; pmix_plog_base_module_log_fn_t log; } pmix_plog_module_t; /** * Base structure for a PLOG API */ typedef struct { pmix_plog_base_module_log_fn_t log; } pmix_plog_API_module_t; /* declare the global APIs */ PMIX_EXPORT extern pmix_plog_API_module_t pmix_plog; /* * the standard component data structure */ typedef pmix_mca_base_component_t pmix_plog_base_component_t; /* * Macro for use in components that are of type plog */ #define PMIX_PLOG_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("plog", 1, 0, 0) END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/plog/base/0000775000175000017500000000000015203536752016677 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/plog/base/plog_base_select.c0000664000175000017500000002076415203536752022346 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/util/pmix_show_help.h" #include "src/mca/plog/base/base.h" /* Function for selecting a prioritized array of components * from all those that are available. */ int pmix_plog_base_select(void) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_mca_base_component_t *component = NULL; pmix_mca_base_module_t *module = NULL; pmix_plog_module_t *nmodule; pmix_plog_base_active_module_t *newmodule, *mod, *default_mod = NULL; int rc, priority, n; bool inserted, default_added, reqd; pmix_list_t actives; char *ptr; size_t len; if (pmix_plog_globals.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_plog_globals.selected = true; PMIX_CONSTRUCT(&actives, pmix_list_t); /* Query all available components and ask if they have a module */ PMIX_LIST_FOREACH (cli, &pmix_plog_base_framework.framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_mca_base_component_t *) cli->cli_component; pmix_output_verbose(5, pmix_plog_base_framework.framework_output, "mca:plog:select: checking available component %s", component->pmix_mca_component_name); /* If there's no query function, skip it */ if (NULL == component->pmix_mca_query_component) { pmix_output_verbose( 5, pmix_plog_base_framework.framework_output, "mca:plog:select: Skipping component [%s]. It does not implement a query function", component->pmix_mca_component_name); continue; } /* Query the component */ pmix_output_verbose(5, pmix_plog_base_framework.framework_output, "mca:plog:select: Querying component [%s]", component->pmix_mca_component_name); rc = component->pmix_mca_query_component(&module, &priority); /* If no module was returned, then skip component */ if (PMIX_SUCCESS != rc || NULL == module) { pmix_output_verbose( 5, pmix_plog_base_framework.framework_output, "mca:plog:select: Skipping component [%s]. Query failed to return a module", component->pmix_mca_component_name); continue; } /* If we got a module, keep it */ nmodule = (pmix_plog_module_t *) module; /* let it initialize */ if (NULL != nmodule->init && PMIX_SUCCESS != nmodule->init()) { continue; } /* add to the list of selected modules */ newmodule = PMIX_NEW(pmix_plog_base_active_module_t); newmodule->pri = priority; newmodule->module = nmodule; newmodule->component = (pmix_plog_base_component_t *) cli->cli_component; /* maintain priority order */ inserted = false; PMIX_LIST_FOREACH (mod, &actives, pmix_plog_base_active_module_t) { if (priority > mod->pri) { pmix_list_insert_pos(&actives, (pmix_list_item_t *) mod, &newmodule->super); inserted = true; break; } } if (!inserted) { /* must be lowest priority - add to end */ pmix_list_append(&actives, &newmodule->super); } /* if this is the default module, track it */ if (0 == strcmp(newmodule->module->name, "default")) { default_mod = newmodule; } } /* if they gave us a desired ordering, then impose it here */ if (NULL != pmix_plog_globals.channels) { default_added = false; for (n = 0; NULL != pmix_plog_globals.channels[n]; n++) { len = strlen(pmix_plog_globals.channels[n]); /* check for the "req" modifier */ reqd = false; ptr = strrchr(pmix_plog_globals.channels[n], ':'); if (NULL != ptr) { /* get the length of the remaining string so we * can constrain our comparison of the channel * name itself */ len = len - strlen(ptr); /* move over the ':' */ ++ptr; /* we accept anything that starts with "req" */ if (0 == strncasecmp(ptr, "req", 3)) { reqd = true; } } /* now search for this channel in our list of actives */ inserted = false; PMIX_LIST_FOREACH (mod, &actives, pmix_plog_base_active_module_t) { if (0 == strncasecmp(pmix_plog_globals.channels[n], mod->module->name, len)) { pmix_list_remove_item(&actives, &mod->super); pmix_pointer_array_add(&pmix_plog_globals.actives, mod); mod->reqd = reqd; inserted = true; break; } } if (!inserted) { /* we didn't find a supporting module - this * still might be okay because it could be something * the RM itself supports, so just insert the default * module here if it hasn't already been inserted */ if (!default_added) { /* if the default module isn't available and this * channel isn't optional, then there is nothing * we can do except report an error */ if (NULL == default_mod && reqd) { pmix_show_help("help-pmix-plog.txt", "reqd-not-found", true, pmix_plog_globals.channels[n]); PMIX_LIST_DESTRUCT(&actives); return PMIX_ERR_NOT_FOUND; } else if (NULL != default_mod) { pmix_pointer_array_add(&pmix_plog_globals.actives, default_mod); default_added = true; default_mod->reqd = reqd; } } else if (reqd) { /* if we already added it, we still have to check the * reqd status - if any citation requires that the * default be used, then we set it, but be sure we * don't overwrite it with a "not required" if it * was already set as "required" */ default_mod->reqd = reqd; } } } /* if there are any modules left over, we need to discard them */ PMIX_LIST_DESTRUCT(&actives); } else { /* insert the modules into the global array in priority order */ while (NULL != (mod = (pmix_plog_base_active_module_t *) pmix_list_remove_first(&actives))) { pmix_pointer_array_add(&pmix_plog_globals.actives, mod); } PMIX_DESTRUCT(&actives); } if (4 < pmix_output_get_verbosity(pmix_plog_base_framework.framework_output)) { pmix_output(0, "Final plog order"); /* show the prioritized order */ for (n = 0; n < pmix_plog_globals.actives.size; n++) { if (NULL != (mod = (pmix_plog_base_active_module_t *) pmix_pointer_array_get_item(&pmix_plog_globals.actives, n))) { pmix_output(0, "\tplog[%d]: %s", n, mod->component->pmix_mca_component_name); } } } return PMIX_SUCCESS; ; } pmix-6.1.1~rc2/src/mca/plog/base/plog_base_stubs.c0000664000175000017500000001355515203536752022227 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/class/pmix_list.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_error.h" #include "src/util/pmix_show_help.h" #include "src/mca/plog/base/base.h" /* this takes place in a progress event */ pmix_status_t pmix_plog_base_log(const pmix_proc_t *source, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs) { pmix_plog_base_active_module_t *active; pmix_status_t rc = PMIX_ERR_NOT_AVAILABLE; size_t n, k; int m; bool logonce = false; pmix_list_t channels; char *key = NULL, *val = NULL; bool agg = true; // default to aggregating show_help messages pmix_info_t *dt = (pmix_info_t*)data; if (!pmix_plog_globals.initialized) { return PMIX_ERR_INIT; } /* if there is no data to output, then nothing to do */ if (NULL == data) { return PMIX_OPERATION_SUCCEEDED; } pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "plog:log called"); /* initialize the list of channels */ PMIX_CONSTRUCT(&channels, pmix_list_t); if (NULL != directives) { /* scan the directives for the PMIX_LOG_ONCE attribute * which indicates we should stop with the first log * channel that can successfully handle this request, * and any channel directives */ for (n = 0; n < ndirs; n++) { if (PMIX_CHECK_KEY(&directives[n], PMIX_LOG_ONCE)) { logonce = PMIX_INFO_TRUE(&directives[n]); } else if (PMIX_CHECK_KEY(&directives[n], PMIX_LOG_AGG)) { agg = PMIX_INFO_TRUE(&directives[n]); } else if (PMIX_CHECK_KEY(&directives[n], PMIX_LOG_KEY)) { key = directives[n].value.data.string; } else if (PMIX_CHECK_KEY(&directives[n], PMIX_LOG_VAL)) { val = directives[n].value.data.string; } } if (agg && NULL != key && NULL != val) { if (PMIX_SUCCESS == pmix_help_check_dups(key, val)) { for (k = 0; k < ndata; k++) { // This is a dup and has been tracked as such, // mark this as complete so we don't log it again. PMIX_INFO_OP_COMPLETED(&dt[k]); } } } } /* scan the incoming logging requests and assemble the modules in * the corresponding order - this will ensure that the one they * requested first gets first shot at "log once" */ for (n = 0; n < ndata; n++) { if (PMIX_INFO_OP_IS_COMPLETE(&data[n])) { continue; } for (m = 0; m < pmix_plog_globals.actives.size; m++) { active = (pmix_plog_base_active_module_t *) pmix_pointer_array_get_item(&pmix_plog_globals.actives, m); if (NULL == active) { continue; } /* if this channel is included in the ones serviced by this * module, then include the module */ if (NULL == active->module->channels) { if (!active->added) { /* add this channel to the list */ pmix_list_append(&channels, &active->super); /* mark it as added */ active->added = true; } } else { for (k = 0; NULL != active->module->channels[k]; k++) { if (NULL != strstr(data[n].key, active->module->channels[k])) { if (!active->added) { /* add this channel to the list */ pmix_list_append(&channels, &active->super); /* mark it as added */ active->added = true; break; } } } } } } // do we have anything we need to do? if (0 == pmix_list_get_size(&channels)) { /* nothing we need do - clear the channels list but don't * release the members */ while (NULL != pmix_list_remove_first(&channels)); PMIX_DESTRUCT(&channels); // Don't return PMIX_SUCCESS here, or else the called // will expect the cbfunc to be executed (which it won't be.). return PMIX_OPERATION_SUCCEEDED; } /* reset the added marker for the next time we are called */ PMIX_LIST_FOREACH (active, &channels, pmix_plog_base_active_module_t) { active->added = false; } // cycle through the channels and let them log PMIX_LIST_FOREACH (active, &channels, pmix_plog_base_active_module_t) { if (NULL != active->module->log) { rc = active->module->log(source, data, ndata, directives, ndirs); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { // if we are only logging once, then we are done if (logonce) { break; } } else if (PMIX_ERR_NOT_AVAILABLE == rc || PMIX_ERR_TAKE_NEXT_OPTION == rc) { // ignore this module continue; } else { // hit a real error - abort break; } } } /* cannot release the modules - just remove everything from the list */ while (NULL != pmix_list_remove_first(&channels)); PMIX_DESTRUCT(&channels); return rc; } pmix-6.1.1~rc2/src/mca/plog/base/plog_base_frame.c0000664000175000017500000000664015203536752022156 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/plog/base/base.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public mca_base_component_t struct. */ #include "src/mca/plog/base/static-components.h" /* Instantiate the global vars */ pmix_plog_globals_t pmix_plog_globals = { .actives = PMIX_POINTER_ARRAY_STATIC_INIT, .initialized = false, .selected = false, .channels = NULL }; pmix_plog_API_module_t pmix_plog = { .log = pmix_plog_base_log }; static char *order = NULL; static int pmix_plog_register(pmix_mca_base_register_flag_t flags) { (void) flags; pmix_mca_base_var_register("pmix", "plog", "base", "order", "Comma-delimited, prioritized list of logging channels", PMIX_MCA_BASE_VAR_TYPE_STRING, &order); if (NULL != order) { pmix_plog_globals.channels = PMIx_Argv_split(order, ','); } return PMIX_SUCCESS; } static pmix_status_t pmix_plog_close(void) { pmix_plog_base_active_module_t *active; int n; if (!pmix_plog_globals.initialized) { return PMIX_SUCCESS; } pmix_plog_globals.initialized = false; pmix_plog_globals.selected = false; for (n = 0; n < pmix_plog_globals.actives.size; n++) { if (NULL == (active = (pmix_plog_base_active_module_t *) pmix_pointer_array_get_item(&pmix_plog_globals.actives, n))) { continue; } if (NULL != active->module->finalize) { active->module->finalize(); } PMIX_RELEASE(active); pmix_pointer_array_set_item(&pmix_plog_globals.actives, n, NULL); } PMIX_DESTRUCT(&pmix_plog_globals.actives); return pmix_mca_base_framework_components_close(&pmix_plog_base_framework, NULL); } static pmix_status_t pmix_plog_open(pmix_mca_base_open_flag_t flags) { /* initialize globals */ pmix_plog_globals.initialized = true; pmix_plog_globals.channels = NULL; PMIX_CONSTRUCT(&pmix_plog_globals.actives, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_plog_globals.actives, 1, INT_MAX, 1); /* Open up all available components */ return pmix_mca_base_framework_components_open(&pmix_plog_base_framework, flags); } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, plog, "PMIx Logging Operations", pmix_plog_register, pmix_plog_open, pmix_plog_close, pmix_mca_plog_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); static void acon(pmix_plog_base_active_module_t *p) { p->reqd = false; p->added = false; } PMIX_CLASS_INSTANCE(pmix_plog_base_active_module_t, pmix_list_item_t, acon, NULL); pmix-6.1.1~rc2/src/mca/plog/base/base.h0000664000175000017500000000525715203536752017773 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PLOG_BASE_H_ #define PMIX_PLOG_BASE_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/class/pmix_pointer_array.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/mca.h" #include "src/threads/pmix_threads.h" #include "src/mca/plog/plog.h" BEGIN_C_DECLS /* * MCA Framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_plog_base_framework; /** * PLOG select function * * Cycle across available components and construct the array * of active modules */ PMIX_EXPORT pmix_status_t pmix_plog_base_select(void); /** * Track an active component / module */ struct pmix_plog_base_active_module_t { pmix_list_item_t super; bool reqd; bool added; int pri; pmix_plog_module_t *module; pmix_plog_base_component_t *component; }; typedef struct pmix_plog_base_active_module_t pmix_plog_base_active_module_t; PMIX_CLASS_DECLARATION(pmix_plog_base_active_module_t); /* framework globals */ struct pmix_plog_globals_t { pmix_pointer_array_t actives; bool initialized; bool selected; char **channels; }; typedef struct pmix_plog_globals_t pmix_plog_globals_t; PMIX_EXPORT extern pmix_plog_globals_t pmix_plog_globals; PMIX_EXPORT pmix_status_t pmix_plog_base_log(const pmix_proc_t *source, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/plog/base/Makefile.include0000664000175000017500000000237015203536752021763 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2018 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from # src/Makefile.am EXTRA_DIST = base/help-pmix-plog.txt headers += \ base/base.h sources += \ base/plog_base_frame.c \ base/plog_base_select.c \ base/plog_base_stubs.c pmix-6.1.1~rc2/src/mca/plog/base/help-pmix-plog.txt0000664000175000017500000000302415203536752022301 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2018 Intel, Inc. All rights reserved. # Copyright (c) 2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is a US/English help file # [reqd-not-found] The plog_base_order MCA parameter included a required logging channel that is not available: Channel: %s Please update the parameter and try again. # [syslog:unrec-level] An unrecognized syslog level was given: Level: %s Please see "man syslog" for a list of defined levels. Input parameter strings and their corresponding syslog levels recognized by PMIx include: Parameter Level err LOG_ERR (default) alert LOG_ALERT crit LOG_CRIT emerg LOG_EMERG warn LOG_WARNING not LOG_NOTICE info LOG_INFO debug LOG_DEBUG Please redefine the MCA parameter and try again. # [syslog:unrec-facility] An unsupported or unrecognized value was given for the syslog facility (i.e., the type of program calling syslog): Value: %s Please see "man syslog" for a list of defined facility values. PMIx currently supports only the following designations: Parameter Level auth LOG_AUTH priv LOG_AUTHPRIV daemon LOG_DAEMON user LOG_USER (default) Please redefine the MCA parameter and try again. # [smtp:send_email failed] The PMIx smtp log component was unable to send an email: Failure: %s Issue: %s Error: %s (%d) Message: %s pmix-6.1.1~rc2/src/mca/plog/syslog/0000775000175000017500000000000015203536752017305 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/plog/syslog/plog_syslog.c0000664000175000017500000001513615203536752022020 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include #ifdef HAVE_TIME_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif /* HAVE_SYS_TIME_H */ #ifdef HAVE_SYSLOG_H # include #endif #include #include "src/mca/bfrops/bfrops.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_show_help.h" #include "plog_syslog.h" #include "src/mca/plog/base/base.h" /* Static API's */ static pmix_status_t init(void); static void finalize(void); static pmix_status_t mylog(const pmix_proc_t *source, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs); /* Module def */ pmix_plog_module_t pmix_plog_syslog_module = { .name = "syslog", .init = init, .finalize = finalize, .log = mylog }; static pmix_status_t init(void) { int opts; char *mychannels = "lsys,gsys,syslog,local_syslog,global_syslog"; pmix_plog_syslog_module.channels = PMIx_Argv_split(mychannels, ','); opts = LOG_CONS | LOG_PID; openlog("PMIx Log Report:", opts, LOG_USER); return PMIX_SUCCESS; } static void finalize(void) { closelog(); PMIx_Argv_free(pmix_plog_syslog_module.channels); } static pmix_status_t write_local(const pmix_proc_t *source, time_t timestamp, int severity, char *msg); static pmix_status_t mylog(const pmix_proc_t *source, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs) { size_t n; int pri = pmix_mca_plog_syslog_component.level; pmix_status_t rc; time_t timestamp = 0; /* if there is no data, then we don't handle it */ if (NULL == data || 0 == ndata) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "%s: plog:syslog called", PMIX_NAME_PRINT(&pmix_globals.myid)); /* check directives */ if (NULL != directives) { for (n = 0; n < ndirs; n++) { if (0 == strncmp(directives[n].key, PMIX_LOG_SYSLOG_PRI, PMIX_MAX_KEYLEN)) { pri = directives[n].value.data.integer; } else if (0 == strncmp(directives[n].key, PMIX_LOG_TIMESTAMP, PMIX_MAX_KEYLEN)) { timestamp = directives[n].value.data.time; } } } /* check to see if there are any syslog entries */ for (n = 0; n < ndata; n++) { if (PMIX_CHECK_KEY(&data[n], PMIX_LOG_SYSLOG)) { pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "%s: plog:syslog delivering to local syslog", PMIX_NAME_PRINT(&pmix_globals.myid)); /* we default to using the local syslog */ rc = write_local(source, timestamp, pri, data[n].value.data.string); if (PMIX_SUCCESS != rc) { return rc; } } else if (PMIX_CHECK_KEY(&data[n], PMIX_LOG_LOCAL_SYSLOG)) { pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "%s: plog:syslog delivering to local syslog", PMIX_NAME_PRINT(&pmix_globals.myid)); rc = write_local(source, timestamp, pri, data[n].value.data.string); if (PMIX_SUCCESS != rc) { return rc; } } else if (PMIX_CHECK_KEY(&data[n], PMIX_LOG_GLOBAL_SYSLOG)) { /* only do this if we are a gateway server */ if (PMIX_PEER_IS_GATEWAY(pmix_globals.mypeer)) { pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "%s: plog:syslog delivering to global syslog", PMIX_NAME_PRINT(&pmix_globals.myid)); rc = write_local(source, timestamp, pri, data[n].value.data.string); if (PMIX_SUCCESS != rc) { return rc; } } else { pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "%s: plog:syslog global syslog, but not gateway", PMIX_NAME_PRINT(&pmix_globals.myid)); } } } return PMIX_SUCCESS; } static char *sev2str(int severity) { switch (severity) { case LOG_EMERG: return "EMERGENCY"; case LOG_ALERT: return "ALERT"; case LOG_CRIT: return "CRITICAL"; case LOG_ERR: return "ERROR"; case LOG_WARNING: return "WARNING"; case LOG_NOTICE: return "NOTICE"; case LOG_INFO: return "INFO"; case LOG_DEBUG: return "DEBUG"; default: return "UNKNOWN SEVERITY"; } } static pmix_status_t write_local(const pmix_proc_t *source, time_t timestamp, int severity, char *msg) { char tod[48]; pmix_output_verbose(5, pmix_plog_base_framework.framework_output, "plog:syslog:mylog function called with severity %d", severity); if (0 < timestamp) { /* If there was a message, output it */ (void) ctime_r(×tamp, tod); /* trim the newline */ tod[strlen(tod)-1] = '\0'; } else { strcpy(tod, "N/A"); } syslog(severity, "%s %s:%s PROC %s REPORTS: %s", tod, PMIX_NAME_PRINT(&pmix_globals.myid), sev2str(severity), PMIX_NAME_PRINT(source), (NULL == msg) ? "" : msg); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/plog/syslog/configure.m40000664000175000017500000000141015203536752021524 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2017 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017-2018 Intel, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_plog_syslog_CONFIG([action-if-found], [action-if-not-found]) # ----------------------------------------------------------- AC_DEFUN([MCA_pmix_plog_syslog_CONFIG], [ AC_CONFIG_FILES([src/mca/plog/syslog/Makefile]) PMIX_VAR_SCOPE_PUSH([pmix_plog_syslog_happy]) # if syslog.h is not compilable, # disable this component. AC_CHECK_HEADER([syslog.h], [pmix_plog_syslog_happy=1], [pmix_plog_syslog_happy=0]) AS_IF([test $pmix_plog_syslog_happy -eq 1], [$1], [$2]) PMIX_VAR_SCOPE_POP ])dnl pmix-6.1.1~rc2/src/mca/plog/syslog/plog_syslog_component.c0000664000175000017500000001017315203536752024076 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* * includes */ #include "pmix_config.h" #include "pmix_common.h" #ifdef HAVE_SYSLOG_H # include #endif #include "plog_syslog.h" #include "src/util/pmix_show_help.h" static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t syslog_register(void); /* * Struct of function pointers that need to be initialized */ pmix_plog_syslog_component_t pmix_mca_plog_syslog_component = { .super = { PMIX_PLOG_BASE_VERSION_1_0_0, .pmix_mca_component_name = "syslog", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), .pmix_mca_query_component = component_query, .pmix_mca_register_component_params = syslog_register, }, .console = false, .level = LOG_ERR, .facility = LOG_USER }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, plog, syslog) static char *level = "info"; static char *facility = "user"; static pmix_status_t syslog_register(void) { pmix_status_t rc = PMIX_SUCCESS; (void) pmix_mca_base_component_var_register( &pmix_mca_plog_syslog_component.super, "console", "Write directly to system console if there is an error while sending to system logger", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_mca_plog_syslog_component.console); level = "info"; (void) pmix_mca_base_component_var_register(&pmix_mca_plog_syslog_component.super, "level", "Default syslog logging level (err, alert, crit, " "emerg, warning, notice, info[default], or debug)", PMIX_MCA_BASE_VAR_TYPE_STRING, &level); if (0 == strncasecmp(level, "err", 3)) { pmix_mca_plog_syslog_component.level = LOG_ERR; } else if (0 == strcasecmp(level, "alert")) { pmix_mca_plog_syslog_component.level = LOG_ALERT; } else if (0 == strncasecmp(level, "crit", 4)) { pmix_mca_plog_syslog_component.level = LOG_CRIT; } else if (0 == strncasecmp(level, "emerg", 5)) { pmix_mca_plog_syslog_component.level = LOG_EMERG; } else if (0 == strncasecmp(level, "warn", 4)) { pmix_mca_plog_syslog_component.level = LOG_WARNING; } else if (0 == strncasecmp(level, "not", 3)) { pmix_mca_plog_syslog_component.level = LOG_NOTICE; } else if (0 == strcasecmp(level, "info")) { pmix_mca_plog_syslog_component.level = LOG_INFO; } else if (0 == strcasecmp(level, "debug") || 0 == strcasecmp(level, "dbg")) { pmix_mca_plog_syslog_component.level = LOG_DEBUG; } else { pmix_show_help("help-pmix-plog.txt", "syslog:unrec-level", true, level); rc = PMIX_ERR_NOT_SUPPORTED; } facility = "user"; (void) pmix_mca_base_component_var_register( &pmix_mca_plog_syslog_component.super, "facility", "Specify what type of program is logging the message " "(only \"auth\", \"priv\", \"daemon\", and \"user\" are supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, &facility); if (0 == strncasecmp(facility, "auth", 4)) { pmix_mca_plog_syslog_component.facility = LOG_AUTH; } else if (0 == strncasecmp(facility, "priv", 4)) { pmix_mca_plog_syslog_component.facility = LOG_AUTHPRIV; } else if (0 == strcasecmp(facility, "daemon")) { pmix_mca_plog_syslog_component.facility = LOG_DAEMON; } else if (0 == strcasecmp(facility, "user")) { pmix_mca_plog_syslog_component.facility = LOG_USER; } else { pmix_show_help("help-pmix-plog.txt", "syslog:unrec-facility", true, facility); rc = PMIX_ERR_NOT_SUPPORTED; } return rc; } static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 10; *module = (pmix_mca_base_module_t *) &pmix_plog_syslog_module; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/plog/syslog/Makefile.am0000664000175000017500000000341715203536752021346 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2014-2019 Intel, Inc. All rights reserved. # Copyright (c) 2017 IBM Corporation. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # sources = \ plog_syslog.h \ plog_syslog.c \ plog_syslog_component.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_plog_syslog_DSO component_noinst = component_install = pmix_mca_plog_syslog.la else component_noinst = libpmix_mca_plog_syslog.la component_install = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component_install) pmix_mca_plog_syslog_la_SOURCES = $(sources) pmix_mca_plog_syslog_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_plog_syslog_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(component_noinst) libpmix_mca_plog_syslog_la_SOURCES =$(sources) libpmix_mca_plog_syslog_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/plog/syslog/plog_syslog.h0000664000175000017500000000253415203536752022023 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2018 Intel, Inc. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PLOG_SYSLOG_H #define PLOG_SYSLOG_H #include "pmix_config.h" #include "src/mca/plog/plog.h" BEGIN_C_DECLS /* * Plog interfaces */ typedef struct { pmix_plog_base_component_t super; int console; int level; int facility; } pmix_plog_syslog_component_t; PMIX_EXPORT extern pmix_plog_syslog_component_t pmix_mca_plog_syslog_component; extern pmix_plog_module_t pmix_plog_syslog_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/plog/stdfd/0000775000175000017500000000000015203536752017071 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/plog/stdfd/plog_stdfd.c0000664000175000017500000001363215203536752021367 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include "pmix_server.h" #include #ifdef HAVE_SYS_TIME_H # include #endif /* HAVE_SYS_TIME_H */ #include #include "src/common/pmix_iof.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_show_help.h" #include "plog_stdfd.h" #include "src/mca/plog/base/base.h" /* Static API's */ static int init(void); static void finalize(void); static pmix_status_t mylog(const pmix_proc_t *source, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs); /* Module def */ pmix_plog_module_t pmix_plog_stdfd_module = { .name = "stdfd", .init = init, .finalize = finalize, .log = mylog }; static int init(void) { char *mychannels = "stdout,stderr"; pmix_plog_stdfd_module.channels = PMIx_Argv_split(mychannels, ','); return PMIX_SUCCESS; } static void finalize(void) { PMIx_Argv_free(pmix_plog_stdfd_module.channels); } typedef struct{ pmix_object_t super; pmix_proc_t source; pmix_byte_object_t bo; } pmix_iof_deliver_t; static void pdcon(pmix_iof_deliver_t *p) { p->bo.bytes = NULL; p->bo.size = 0; } static void pddes(pmix_iof_deliver_t *p) { if (NULL != p->bo.bytes) { free(p->bo.bytes); } } static PMIX_CLASS_INSTANCE(pmix_iof_deliver_t, pmix_object_t, pdcon, pddes); static void lkcbfunc(pmix_status_t status, void *cbdata) { pmix_iof_deliver_t *p = (pmix_iof_deliver_t*)cbdata; /* nothing to do here - we use this solely to * ensure that IOF_deliver doesn't block */ if (PMIX_SUCCESS != status) { PMIX_ERROR_LOG(status); } PMIX_RELEASE(p); } static pmix_status_t mylog(const pmix_proc_t *source, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs) { size_t n; pmix_status_t rc; pmix_iof_deliver_t *p; PMIX_HIDE_UNUSED_PARAMS(directives, ndirs); /* if there is no data, then we don't handle it */ if (NULL == data || 0 == ndata) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "%s: plog:stdfd called", PMIX_NAME_PRINT(&pmix_globals.myid)); #if 0 /* check to see if there are any relevant directives */ for (n = 0; n < ndirs; n++) { if (0 == strncmp(directives[n].key, PMIX_LOG_TIMESTAMP, PMIX_MAX_KEYLEN)) { flags.timestamp = directives[n].value.data.time; } else if (0 == strncmp(directives[n].key, PMIX_LOG_XML_OUTPUT, PMIX_MAX_KEYLEN)) { flags.xml = PMIX_INFO_TRUE(&directives[n]); } else if (0 == strncmp(directives[n].key, PMIX_LOG_TAG_OUTPUT, PMIX_MAX_KEYLEN)) { flags.tag = PMIX_INFO_TRUE(&directives[n]); } } #endif /* check to see if there are any stdfd entries */ rc = PMIX_ERR_TAKE_NEXT_OPTION; for (n = 0; n < ndata; n++) { if (PMIX_INFO_OP_IS_COMPLETE(&data[n])) { continue; } if (0 == strncmp(data[n].key, PMIX_LOG_STDERR, PMIX_MAX_KEYLEN)) { pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "%s: plog:stdfd delivering to stderr for source %s", PMIX_NAME_PRINT(&pmix_globals.myid), (NULL == source) ? "NULL" : PMIX_NAME_PRINT(source)); p = PMIX_NEW(pmix_iof_deliver_t); PMIX_XFER_PROCID(&p->source, source); p->bo.size = strlen(data[n].value.data.string) + 1; // include NULL terminator p->bo.bytes = (char*)malloc(p->bo.size); memcpy(p->bo.bytes, data[n].value.data.string, p->bo.size); rc = PMIx_server_IOF_deliver(&p->source, PMIX_FWD_STDERR_CHANNEL, &p->bo, NULL, 0, lkcbfunc, (void*)p); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(p); } } else if (0 == strncmp(data[n].key, PMIX_LOG_STDOUT, PMIX_MAX_KEYLEN)) { pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "%s: plog:stdfd delivering to stdout for source %s", PMIX_NAME_PRINT(&pmix_globals.myid), (NULL == source) ? "NULL" : PMIX_NAME_PRINT(source)); p = PMIX_NEW(pmix_iof_deliver_t); PMIX_XFER_PROCID(&p->source, source); p->bo.size = strlen(data[n].value.data.string) + 1; // include NULL terminator p->bo.bytes = (char*)malloc(p->bo.size); memcpy(p->bo.bytes, data[n].value.data.string, p->bo.size); rc = PMIx_server_IOF_deliver(&p->source, PMIX_FWD_STDOUT_CHANNEL, &p->bo, NULL, 0, lkcbfunc, (void*)p); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(p); } } } return rc; } pmix-6.1.1~rc2/src/mca/plog/stdfd/plog_stdfd_component.c0000664000175000017500000000207315203536752023446 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* * includes */ #include "pmix_config.h" #include "pmix_common.h" #include "plog_stdfd.h" static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); /* * Struct of function pointers that need to be initialized */ pmix_plog_base_component_t pmix_mca_plog_stdfd_component = { PMIX_PLOG_BASE_VERSION_1_0_0, .pmix_mca_component_name = "stdfd", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), .pmix_mca_query_component = component_query, }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, plog, stdfd) static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 5; *module = (pmix_mca_base_module_t *) &pmix_plog_stdfd_module; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/plog/stdfd/plog_stdfd.h0000664000175000017500000000231415203536752021367 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2018 Intel, Inc. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PLOG_STDFD_H #define PLOG_STDFD_H #include "pmix_config.h" #include "src/mca/plog/plog.h" BEGIN_C_DECLS /* * Plog interfaces */ PMIX_EXPORT extern pmix_plog_base_component_t pmix_mca_plog_stdfd_component; extern pmix_plog_module_t pmix_plog_stdfd_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/plog/stdfd/Makefile.am0000664000175000017500000000340415203536752021126 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2014-2019 Intel, Inc. All rights reserved. # Copyright (c) 2017 IBM Corporation. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # sources = \ plog_stdfd.h \ plog_stdfd.c \ plog_stdfd_component.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_plog_stdfd_DSO component_noinst = component_install = pmix_mca_plog_stdfd.la else component_noinst = libpmix_mca_plog_stdfd.la component_install = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component_install) pmix_mca_plog_stdfd_la_SOURCES = $(sources) pmix_mca_plog_stdfd_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_plog_stdfd_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(component_noinst) libpmix_mca_plog_stdfd_la_SOURCES =$(sources) libpmix_mca_plog_stdfd_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/plog/Makefile.am0000664000175000017500000000254715203536752020031 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2018 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(LTDLINCL) # main library setup noinst_LTLIBRARIES = libmca_plog.la libmca_plog_la_SOURCES = # local files headers = plog.h sources = # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.include libmca_plog_la_SOURCES += $(headers) $(sources) distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/plog/smtp/0000775000175000017500000000000015203536752016750 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/plog/smtp/plog_smtp.h0000664000175000017500000000335715203536752021135 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2018 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PLOG_SMTP_H #define PLOG_SMTP_H #include "pmix_config.h" #include #include "libesmtp.h" #include "src/mca/plog/plog.h" BEGIN_C_DECLS typedef struct { pmix_plog_base_component_t super; /* libesmtp version */ char *version; /* SMTP server name and port */ char *server; int port; /* To, From, Subject */ char *to, **to_argv, *from_name, *from_addr, *subject; /* Mail body prefix and suffix */ char *body_prefix, *body_suffix; /* struct hostent from resolved SMTP server name */ struct hostent *server_hostent; /* Priority of this component */ int priority; } pmix_plog_smtp_component_t; /* * Plog interfaces */ PMIX_EXPORT extern pmix_plog_smtp_component_t pmix_mca_plog_smtp_component; extern pmix_plog_module_t pmix_plog_smtp_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/plog/smtp/configure.m40000664000175000017500000000506015203536752021174 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2014-2018 Intel, Inc. All rights reserved. # Copyright (c) 2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # MCA_plog_smtp_CONFIG([action-if-found], [action-if-not-found]) # ----------------------------------------------------------- AC_DEFUN([MCA_pmix_plog_smtp_CONFIG], [ AC_CONFIG_FILES([src/mca/plog/smtp/Makefile]) AC_ARG_WITH([smtp], [AS_HELP_STRING([--with-smtp=DIR], [Search for esmtp headers and libraries in DIR ])]) AC_ARG_WITH([smtp-libdir], [AS_HELP_STRING([--with-smtp-libdir=DIR], [Search for esmtp libraries in DIR ])]) pmix_smtp_support=0 OAC_CHECK_PACKAGE([smtp], [plog_smtp], [libesmtp.h], [esmtp], [smtp_create_session], [pmix_smtp_support=1], [pmix_smtp_support=0]) if test ! -z "$with_smtp" && test "$with_smtp" != "no" && test "$pmix_smtp_support" != "1"; then AC_MSG_WARN([SMTP SUPPORT REQUESTED AND NOT FOUND]) AC_MSG_ERROR([CANNOT CONTINUE]) fi AC_MSG_CHECKING([will smtp support be built]) AS_IF([test "$pmix_smtp_support" = "1"], [$1 AC_MSG_RESULT([yes])], [$2 AC_MSG_RESULT([no])]) PMIX_SUMMARY_ADD([External Packages], [ESMTP], [], [${plog_smtp_SUMMARY}]) # substitute in the things needed to build pcompress/zlib AC_SUBST([plog_smtp_CPPFLAGS]) AC_SUBST([plog_smtp_LDFLAGS]) AC_SUBST([plog_smtp_LIBS]) PMIX_EMBEDDED_LIBS="$PMIX_EMBEDDED_LIBS $plog_smtp_LIBS" PMIX_EMBEDDED_LDFLAGS="$PMIX_EMBEDDED_LDFLAGS $plog_smtp_LDFLAGS" PMIX_EMBEDDED_CPPFLAGS="$PMIX_EMBEDDED_CPPFLAGS $plog_smtp_CPPFLAGS" ])dnl pmix-6.1.1~rc2/src/mca/plog/smtp/Makefile.am0000664000175000017500000000365515203536752021015 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2014-2019 Intel, Inc. All rights reserved. # Copyright (c) 2017 IBM Corporation. All rights reserved. # Copyright (c) 2022-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(plog_smtp_CPPFLAGS) sources = \ plog_smtp.h \ plog_smtp.c \ plog_smtp_component.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_plog_smtp_DSO component_noinst = component_install = pmix_mca_plog_smtp.la else component_noinst = libpmix_mca_plog_smtp.la component_install = endif mcacomponentdir = $(pmnixlibdir) mcacomponent_LTLIBRARIES = $(component_install) pmix_mca_plog_smtp_la_SOURCES = $(sources) pmix_mca_plog_smtp_la_LDFLAGS = -module -avoid-version $(plog_smtp_LDFLAGS) pmix_mca_plog_smtp_la_LIBADD = $(plog_smtp_LIBS) if NEED_LIBPMIX pmix_mca_plog_smtp_la_LIBADD += $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(component_noinst) libpmix_mca_plog_smtp_la_SOURCES =$(sources) libpmix_mca_plog_smtp_la_LDFLAGS = -module -avoid-version $(plog_smtp_LDFLAGS) libpmix_mca_plog_smtp_la_LIBADD = $(plog_smtp_LIBS) pmix-6.1.1~rc2/src/mca/plog/smtp/plog_smtp_component.c0000664000175000017500000002025715203536752023210 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* * Simple smtp plog (using libesmtp) */ #include "pmix_config.h" #include "src/mca/base/pmix_mca_base_var.h" #include "pmix_common.h" #include "src/util/pmix_show_help.h" #include "src/mca/plog/base/base.h" #include "plog_smtp.h" static pmix_status_t smtp_component_query(pmix_mca_base_module_t **module, int *priority); static pmix_status_t smtp_close(void); static pmix_status_t smtp_register(void); /* * Struct of function pointers that need to be initialized */ pmix_plog_smtp_component_t pmix_mca_plog_smtp_component = { .super = { PMIX_PLOG_BASE_VERSION_1_0_0, .pmix_mca_component_name = "smtp", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), .pmix_mca_close_component = smtp_close, .pmix_mca_query_component = smtp_component_query, .pmix_mca_register_component_params = smtp_register, }, .version = NULL, .server = NULL, .to = NULL, .from_name = NULL, .subject = NULL, .body_prefix = NULL, .body_suffix = NULL }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, plog, smtp) static char *server = NULL; static char *myfrom = NULL; static char *subject = NULL; static char *suffix = NULL; static char *prefix = NULL; static pmix_status_t smtp_register(void) { char version[256]; /* Server stuff */ (void) pmix_mca_base_component_var_register(&pmix_mca_plog_smtp_component.super, "server", "SMTP server name or IP address", PMIX_MCA_BASE_VAR_TYPE_STRING, &server); if (NULL != server) { pmix_mca_plog_smtp_component.server = strdup(server); } else { pmix_mca_plog_smtp_component.server = strdup("localhost"); } pmix_mca_plog_smtp_component.port = 25; (void) pmix_mca_base_component_var_register(&pmix_mca_plog_smtp_component.super, "port", "SMTP server port", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_mca_plog_smtp_component.port); /* Email stuff */ (void) pmix_mca_base_component_var_register(&pmix_mca_plog_smtp_component.super, "to", "Comma-delimited list of default email addresses to send to", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_plog_smtp_component.to); (void) pmix_mca_base_component_var_register(&pmix_mca_plog_smtp_component.super, "from_addr", "Email address that messages will be from", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_plog_smtp_component.from_addr); (void) pmix_mca_base_component_var_register(&pmix_mca_plog_smtp_component.super, "from_name", "Email name that messages will be from", PMIX_MCA_BASE_VAR_TYPE_STRING, &myfrom); if (NULL != myfrom) { pmix_mca_plog_smtp_component.from_name = strdup(myfrom); } else { pmix_mca_plog_smtp_component.from_name = strdup("PMIx Plog"); } (void) pmix_mca_base_component_var_register(&pmix_mca_plog_smtp_component.super, "subject", "Default email subject", PMIX_MCA_BASE_VAR_TYPE_STRING, &subject); if (NULL != subject) { pmix_mca_plog_smtp_component.subject = strdup(subject); } else { pmix_mca_plog_smtp_component.subject = strdup("PMIx Plog"); } /* Mail body prefix and suffix */ (void) pmix_mca_base_component_var_register(&pmix_mca_plog_smtp_component.super, "body_prefix", "Text to put at the beginning of the mail message", PMIX_MCA_BASE_VAR_TYPE_STRING, &prefix); if (NULL != prefix) { pmix_mca_plog_smtp_component.body_prefix = strdup(prefix); } else { pmix_mca_plog_smtp_component.body_prefix = strdup( "The PMIx SMTP plog wishes to inform you of the following message:\n\n"); } (void) pmix_mca_base_component_var_register(&pmix_mca_plog_smtp_component.super, "body_prefix", "Text to put at the end of the mail message", PMIX_MCA_BASE_VAR_TYPE_STRING, &suffix); if (NULL != suffix) { pmix_mca_plog_smtp_component.body_suffix = strdup(suffix); } else { pmix_mca_plog_smtp_component.body_suffix = strdup("\n\nSincerely,\nOscar the PMIx Owl"); } /* Priority */ pmix_mca_plog_smtp_component.priority = 10; (void) pmix_mca_base_component_var_register(&pmix_mca_plog_smtp_component.super, "priority", "Priority of this component", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_mca_plog_smtp_component.priority); /* Libesmtp version */ smtp_version(version, sizeof(version), 0); version[sizeof(version) - 1] = '\0'; pmix_mca_plog_smtp_component.version = strdup(version); return PMIX_SUCCESS; } static pmix_status_t smtp_close(void) { if (NULL != pmix_mca_plog_smtp_component.version) { free(pmix_mca_plog_smtp_component.version); } if (NULL != pmix_mca_plog_smtp_component.server) { free(pmix_mca_plog_smtp_component.server); } if (NULL != pmix_mca_plog_smtp_component.body_prefix) { free(pmix_mca_plog_smtp_component.body_prefix); } if (NULL != pmix_mca_plog_smtp_component.body_suffix) { free(pmix_mca_plog_smtp_component.body_suffix); } if (NULL != pmix_mca_plog_smtp_component.from_name) { free(pmix_mca_plog_smtp_component.from_name); } if (NULL != pmix_mca_plog_smtp_component.subject) { free(pmix_mca_plog_smtp_component.subject); } return PMIX_SUCCESS; } static pmix_status_t smtp_component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 0; *module = NULL; /* Since we have to open a socket later, try to resolve the IP address of the server now. Save the result, or abort if we can't resolve it. */ pmix_mca_plog_smtp_component.server_hostent = gethostbyname(pmix_mca_plog_smtp_component.server); if (NULL == pmix_mca_plog_smtp_component.server_hostent) { pmix_output_verbose(5, pmix_plog_base_framework.framework_output, "SMTP: unable to resolve server %s; disabled", pmix_mca_plog_smtp_component.server); return PMIX_ERR_NOT_FOUND; } *priority = 10; *module = (pmix_mca_base_module_t *) &pmix_plog_smtp_module; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/plog/smtp/plog_smtp.c0000664000175000017500000003031315203536752021120 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* * Send an email upon plog events. */ #include "pmix_config.h" #include "pmix_common.h" #include #include #include #ifdef HAVE_UNISTD_H # include #endif #include #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "plog_smtp.h" #include "src/mca/plog/base/base.h" /* Static API's */ static pmix_status_t init(void); static void finalize(void); static pmix_status_t mylog(const pmix_proc_t *source, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs); /* Module */ pmix_plog_module_t pmix_plog_smtp_module = { .name = "smtp", .channels = NULL, .init = init, .finalize = finalize, .log = mylog }; typedef enum { SENT_NONE, SENT_HEADER, SENT_BODY_PREFIX, SENT_BODY, SENT_BODY_SUFFIX, SENT_ALL } sent_flag_t; typedef struct { sent_flag_t sent_flag; char *msg; char *prev_string; } message_status_t; static pmix_status_t init(void) { char *mychannels = "email"; pmix_plog_smtp_module.channels = PMIx_Argv_split(mychannels, ','); return PMIX_SUCCESS; } static void finalize(void) { PMIx_Argv_free(pmix_plog_smtp_module.channels); } /* * Convert lone \n's to \r\n */ static char *crnl(char *orig) { int i, j, max, count; char *str; /* Count how much space we need */ count = max = strlen(orig); for (i = 0; i < max; ++i) { if (orig[i] == '\n' && i > 0 && orig[i - 1] != '\r') { ++count; } } /* Copy, changing \n to \r\n */ str = malloc(count + 1); for (j = i = 0; i < max; ++i) { if (orig[i] == '\n' && i > 0 && orig[i - 1] != '\r') { str[j++] = '\n'; } str[j++] = orig[i]; } str[j] = '\0'; return str; } /* * Callback function invoked via smtp_start_session() */ static const char *message_cb(void **buf, int *len, void *arg) { message_status_t *ms = (message_status_t *) arg; if (NULL == *buf) { *buf = malloc(8192); } if (NULL == len) { ms->sent_flag = SENT_NONE; return NULL; } /* Free the previous string */ if (NULL != ms->prev_string) { free(ms->prev_string); ms->prev_string = NULL; } switch (ms->sent_flag) { case SENT_NONE: /* Send a blank line to signify the end of the header */ ms->sent_flag = SENT_HEADER; ms->prev_string = NULL; *len = 2; return "\r\n"; case SENT_HEADER: if (NULL != pmix_mca_plog_smtp_component.body_prefix) { ms->sent_flag = SENT_BODY_PREFIX; ms->prev_string = crnl(pmix_mca_plog_smtp_component.body_prefix); *len = strlen(ms->prev_string); return ms->prev_string; } else { *len = 0; return NULL; } case SENT_BODY_PREFIX: ms->sent_flag = SENT_BODY; ms->prev_string = crnl(ms->msg); *len = strlen(ms->prev_string); return ms->prev_string; case SENT_BODY: if (NULL != pmix_mca_plog_smtp_component.body_suffix) { ms->sent_flag = SENT_BODY_SUFFIX; ms->prev_string = crnl(pmix_mca_plog_smtp_component.body_suffix); *len = strlen(ms->prev_string); return ms->prev_string; } else { *len = 0; return NULL; } case SENT_BODY_SUFFIX: case SENT_ALL: default: ms->sent_flag = SENT_ALL; *len = 0; return NULL; } } /* * Back-end function to actually send the email */ static pmix_status_t send_email(char *msg, char *from, char *addrs, char *subject, time_t timestamp) { int i, err = PMIX_SUCCESS; char *str = NULL; char **myaddrs = NULL; char *myfrom; char *errmsg = NULL; struct sigaction sig, oldsig; bool set_oldsig = false; smtp_session_t session = NULL; smtp_message_t message = NULL; message_status_t ms; pmix_plog_smtp_component_t *c = &pmix_mca_plog_smtp_component; // check that we have recipients if (NULL == addrs) { if (NULL == c->to) { // nope - nobody to send to return PMIX_ERR_BAD_PARAM; } else { myaddrs = PMIx_Argv_split(c->to, ','); } } else { myaddrs = PMIx_Argv_split(addrs, ','); } if (NULL == from) { if (NULL == c->from_addr) { // nope - nobody to send from return PMIX_ERR_BAD_PARAM; } else { myfrom = c->from_addr; } } else { myfrom = from; } /* Temporarily disable SIGPIPE so that if remote servers timeout or hang up on us, it doesn't kill this application. We'll restore the original SIGPIPE handler when we're done. */ sig.sa_handler = SIG_IGN; sigemptyset(&sig.sa_mask); sig.sa_flags = 0; sigaction(SIGPIPE, &sig, &oldsig); set_oldsig = true; /* Try to get a libesmtp session. If so, assume that libesmtp is happy and proceed */ session = smtp_create_session(); if (NULL == session) { err = PMIX_ERR_NOT_SUPPORTED; errmsg = "stmp_create_session"; goto error; } /* Create the message */ message = smtp_add_message(session); if (NULL == message) { err = PMIX_ERROR; errmsg = "stmp_add_message"; goto error; } /* Set the SMTP server (yes, it's a weird return status!) */ pmix_asprintf(&str, "%s:%d", c->server, c->port); if (0 == smtp_set_server(session, str)) { err = PMIX_ERROR; errmsg = "stmp_set_server"; goto error; } free(str); str = NULL; /* Add the sender */ if (0 == smtp_set_reverse_path(message, c->from_addr)) { err = PMIX_ERROR; errmsg = "stmp_set_reverse_path"; goto error; } // set the "To" header if (0 == smtp_set_header(message, "To", NULL, NULL)) { err = PMIX_ERROR; errmsg = "stmp_set_header TO"; goto error; } /* Add the recipients */ for (i = 0; NULL != myaddrs[i]; ++i) { if (NULL == smtp_add_recipient(message, myaddrs[i])) { err = PMIX_ERR_OUT_OF_RESOURCE; errmsg = "stmp_add_recipient"; goto error; } } // set the subject header if (NULL == subject) { str = c->subject; } else { str = subject; } if (0 == smtp_set_header(message, "Subject", str)) { err = PMIX_ERROR; errmsg = "smtp_set_header SUBJECT"; str = NULL; goto error; } /* set the X-Mailer */ asprintf(&str, "PMIx SMTP Plog v%d.%d.%d", c->super.pmix_mca_component_major_version, c->super.pmix_mca_component_minor_version, c->super.pmix_mca_component_release_version); if (0 == smtp_set_header(message, "X-Mailer", str)) { err = PMIX_ERROR; errmsg = "smtp_set_header XMAILER"; goto error; } if (0 == smtp_set_header(message, "From", (NULL != c->from_name ? c->from_name : myfrom), myfrom)) { err = PMIX_ERROR; errmsg = "smtp_set_header FROM"; goto error; } free(str); str = NULL; // provide the timestamp if (0 < timestamp) { struct tm *local; char *t; local = localtime(×tamp); t = asctime(local); t[strlen(t) - 1] = '\0'; // remove trailing newline if (0 == smtp_set_header(message, "Timestamp", t)) { err = PMIX_ERROR; errmsg = "smtp_set_header TIMESTAMP"; goto error; } } /* Set the callback to get the message */ if (0 == smtp_set_messagecb(message, message_cb, &ms)) { err = PMIX_ERROR; errmsg = "smtp_set_messagecb"; goto error; } /* Send it! */ if (0 == smtp_start_session(session)) { err = PMIX_ERROR; errmsg = "smtp_start_session"; goto error; } /* Fall through */ error: if (NULL != str) { free(str); } if (NULL != session) { smtp_destroy_session(session); } /* Restore the SIGPIPE handler */ if (set_oldsig) { sigaction(SIGPIPE, &oldsig, NULL); } if (PMIX_SUCCESS != err) { int e; char em[256]; memset(em, 0, 256); e = smtp_errno(); smtp_strerror(e, em, sizeof(em)); pmix_show_help("help-pmix-plog.txt", "smtp:send_email failed", true, "libesmtp library call failed", errmsg, em, e, msg); } return err; } static pmix_status_t mylog(const pmix_proc_t *source, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs) { char *addrs = NULL, *msg = NULL; char *subject = NULL, *from = NULL; size_t n; time_t timestamp = 0; pmix_info_t *input = NULL; size_t ninput; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(source); /* if there is no data, then we don't handle it */ if (NULL == data || 0 == ndata) { return PMIX_ERR_NOT_AVAILABLE; } /* check to see if there is an email request */ for (n = 0; n < ndata; n++) { if (PMIx_Check_key(data[n].key, PMIX_LOG_EMAIL)) { if (NULL != input) { // cannot have more than one email per call PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } input = (pmix_info_t*)data[n].value.data.darray->array; ninput = data[n].value.data.darray->size; } } // check for directives for (n = 0; n < ndirs; n++) { if (PMIx_Check_key(directives[n].key, PMIX_LOG_TIMESTAMP)) { timestamp = directives[n].value.data.time; } } // if no email was requested, then move on if (NULL == input) { return PMIX_ERR_TAKE_NEXT_OPTION; } // check the array for input for (n=0; n < ninput; n++) { if (PMIx_Check_key(input[n].key, PMIX_LOG_EMAIL_ADDR)) { addrs = input[n].value.data.string; continue; } if (PMIx_Check_key(input[n].key, PMIX_LOG_EMAIL_SENDER_ADDR)) { from = input[n].value.data.string; continue; } if (PMIx_Check_key(input[n].key, PMIX_LOG_EMAIL_SUBJECT)) { subject = input[n].value.data.string; continue; } if (PMIx_Check_key(input[n].key, PMIX_LOG_MSG)) { if (NULL != msg) { // multiple messages are not supported PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_SUPPORTED; } if (PMIX_STRING == input[n].value.type) { msg = input[n].value.data.string; } else if (PMIX_BYTE_OBJECT == input[n].value.type) { msg = input[n].value.data.bo.bytes; } else { return PMIX_ERR_BAD_PARAM; } continue; } } /* If there wasn't a message, then we are done */ if (NULL == msg) { return PMIX_ERR_TAKE_NEXT_OPTION; } rc = send_email(msg, from, addrs, subject, timestamp); return rc; } pmix-6.1.1~rc2/src/mca/preg/0000775000175000017500000000000015203536752015761 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/preg/native/0000775000175000017500000000000015203536752017247 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/preg/native/preg_native.c0000664000175000017500000007065415203536752021732 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2019 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "include/pmix.h" #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/gds.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "preg_native.h" #include "src/mca/preg/base/base.h" static pmix_status_t generate_node_regex(const char *input, char **regex); static pmix_status_t generate_ppn(const char *input, char **ppn); static pmix_status_t parse_nodes(const char *regexp, char ***names); static pmix_status_t parse_procs(const char *regexp, char ***procs); static pmix_status_t copy(char **dest, size_t *len, const char *input); static pmix_status_t pack(pmix_buffer_t *buffer, const char *input); static pmix_status_t unpack(pmix_buffer_t *buffer, char **regex); static pmix_status_t release(char *regexp); pmix_preg_module_t pmix_preg_native_module = { .name = "pmix", .generate_node_regex = generate_node_regex, .generate_ppn = generate_ppn, .parse_nodes = parse_nodes, .parse_procs = parse_procs, .copy = copy, .pack = pack, .unpack = unpack, .release = release }; static pmix_status_t regex_parse_value_ranges(char *base, char *ranges, int num_digits, char *suffix, char ***names); static pmix_status_t regex_parse_value_range(char *base, char *range, int num_digits, char *suffix, char ***names); static pmix_status_t pmix_regex_extract_nodes(char *regexp, char ***names); static pmix_status_t pmix_regex_extract_ppn(char *regexp, char ***procs); static pmix_status_t generate_node_regex(const char *input, char **regexp) { char *vptr, *vsave; char prefix[PMIX_MAX_NODE_PREFIX]; int i, j, len, startnum, vnum, numdigits; bool found, fullval; char *suffix, *sfx; pmix_regex_value_t *vreg; pmix_regex_range_t *range; pmix_list_t vids; char **regexargs = NULL, *tmp, *tmp2; char *cptr; pmix_status_t rc; /* define the default */ *regexp = NULL; /* setup the list of results */ PMIX_CONSTRUCT(&vids, pmix_list_t); /* cycle thru the array of input values - first copy * it so we don't overwrite what we were given*/ vsave = strdup(input); vptr = vsave; while (NULL != (cptr = strchr(vptr, ',')) || 0 < strlen(vptr)) { if (NULL != cptr) { *cptr = '\0'; } /* determine this node's prefix by looking for first non-alpha char */ fullval = false; len = strlen(vptr); startnum = -1; memset(prefix, 0, PMIX_MAX_NODE_PREFIX); for (i = 0, j = 0; i < len && j < (PMIX_MAX_NODE_PREFIX-1); i++) { if (!isalpha(vptr[i])) { /* found a non-alpha char */ if (!isdigit(vptr[i])) { /* if it is anything but a digit, we just use * the entire name */ fullval = true; break; } /* count the size of the numeric field - but don't * add the digits to the prefix */ if (startnum < 0) { /* okay, this defines end of the prefix */ startnum = i; } continue; } if (startnum < 0) { prefix[j++] = vptr[i]; } } if (fullval || startnum < 0) { /* can't compress this name - just add it to the list */ vreg = PMIX_NEW(pmix_regex_value_t); vreg->prefix = strdup(vptr); pmix_list_append(&vids, &vreg->super); /* move to the next posn */ if (NULL == cptr) { break; } vptr = cptr + 1; continue; } /* convert the digits and get any suffix */ vnum = strtol(&vptr[startnum], &sfx, 10); if (NULL != sfx) { suffix = strdup(sfx); numdigits = (int) (sfx - &vptr[startnum]); } else { suffix = NULL; numdigits = (int) strlen(&vptr[startnum]); } /* is this value already on our list? */ found = false; PMIX_LIST_FOREACH (vreg, &vids, pmix_regex_value_t) { // The regex must preserve ordering of the values. // If we disqualified this entry in a previous check then exclude it // from future checks as well. This will prevent a later entry from // being 'pulled forward' accidentally. For example, given: // "a28n01,a99n02,a28n02" // Without this 'skip' the loop would have 'a28n02' combine with // 'a28n01' jumping over the 'a99n02' entry, and thus not preserving // the order of the list when the regex is unpacked. if (vreg->skip) { continue; } if (0 < strlen(prefix) && NULL == vreg->prefix) { continue; } if (0 == strlen(prefix) && NULL != vreg->prefix) { continue; } if (0 < strlen(prefix) && NULL != vreg->prefix && 0 != strcmp(prefix, vreg->prefix)) { vreg->skip = true; continue; } if (NULL == suffix && NULL != vreg->suffix) { continue; } if (NULL != suffix && NULL == vreg->suffix) { continue; } if (NULL != suffix && NULL != vreg->suffix && 0 != strcmp(suffix, vreg->suffix)) { vreg->skip = true; continue; } if (numdigits != vreg->num_digits) { vreg->skip = true; continue; } /* found a match - flag it */ found = true; /* get the last range on this nodeid - we do this * to preserve order */ range = (pmix_regex_range_t *) pmix_list_get_last(&vreg->ranges); if (NULL == range) { /* first range for this value */ range = PMIX_NEW(pmix_regex_range_t); range->start = vnum; range->cnt = 1; pmix_list_append(&vreg->ranges, &range->super); break; } /* see if the value is out of sequence */ if (vnum != (range->start + range->cnt)) { /* start a new range */ range = PMIX_NEW(pmix_regex_range_t); range->start = vnum; range->cnt = 1; pmix_list_append(&vreg->ranges, &range->super); break; } /* everything matches - just increment the cnt */ range->cnt++; break; } if (!found) { /* need to add it */ vreg = PMIX_NEW(pmix_regex_value_t); if (0 < strlen(prefix)) { vreg->prefix = strdup(prefix); } if (NULL != suffix) { vreg->suffix = strdup(suffix); } vreg->num_digits = numdigits; pmix_list_append(&vids, &vreg->super); /* record the first range for this value - we took * care of values we can't compress above */ range = PMIX_NEW(pmix_regex_range_t); range->start = vnum; range->cnt = 1; pmix_list_append(&vreg->ranges, &range->super); } if (NULL != suffix) { free(suffix); } /* move to the next posn */ if (NULL == cptr) { break; } vptr = cptr + 1; } free(vsave); /* begin constructing the regular expression */ while (NULL != (vreg = (pmix_regex_value_t *) pmix_list_remove_first(&vids))) { /* if no ranges, then just add the name */ if (0 == pmix_list_get_size(&vreg->ranges)) { if (NULL != vreg->prefix) { PMIx_Argv_append_nosize(®exargs, vreg->prefix); } PMIX_RELEASE(vreg); continue; } /* start the regex for this value with the prefix */ if (NULL != vreg->prefix) { if (0 > asprintf(&tmp, "%s[%d:", vreg->prefix, vreg->num_digits)) { return PMIX_ERR_NOMEM; } } else { if (0 > asprintf(&tmp, "[%d:", vreg->num_digits)) { return PMIX_ERR_NOMEM; } } /* add the ranges */ while (NULL != (range = (pmix_regex_range_t *) pmix_list_remove_first(&vreg->ranges))) { if (1 == range->cnt) { if (0 > asprintf(&tmp2, "%s%d,", tmp, range->start)) { free(tmp); return PMIX_ERR_NOMEM; } } else { if (0 > asprintf(&tmp2, "%s%d-%d,", tmp, range->start, range->start + range->cnt - 1)) { free(tmp); return PMIX_ERR_NOMEM; } } free(tmp); tmp = tmp2; PMIX_RELEASE(range); } /* replace the final comma */ tmp[strlen(tmp) - 1] = ']'; if (NULL != vreg->suffix) { /* add in the suffix, if provided */ if (0 > asprintf(&tmp2, "%s%s", tmp, vreg->suffix)) { return PMIX_ERR_NOMEM; } free(tmp); tmp = tmp2; } PMIx_Argv_append_nosize(®exargs, tmp); free(tmp); PMIX_RELEASE(vreg); } /* assemble final result */ if (NULL != regexargs) { tmp = PMIx_Argv_join(regexargs, ','); if (0 > asprintf(regexp, "pmix[%s]", tmp)) { return PMIX_ERR_NOMEM; } free(tmp); /* cleanup */ PMIx_Argv_free(regexargs); rc = PMIX_SUCCESS; } else { rc = PMIX_ERR_TAKE_NEXT_OPTION; } PMIX_DESTRUCT(&vids); return rc; } static pmix_status_t generate_ppn(const char *input, char **regexp) { char **ppn, **npn; int i, j, start, end; pmix_regex_value_t *vreg; pmix_regex_range_t *rng; pmix_list_t nodes; char *tmp, *tmp2; char *cptr; /* define the default */ *regexp = NULL; /* setup the list of results */ PMIX_CONSTRUCT(&nodes, pmix_list_t); /* split the input by node */ ppn = PMIx_Argv_split(input, ';'); /* for each node, split the input by comma */ for (i = 0; NULL != ppn[i]; i++) { rng = NULL; /* create a record for this node */ vreg = PMIX_NEW(pmix_regex_value_t); pmix_list_append(&nodes, &vreg->super); /* split the input for this node */ npn = PMIx_Argv_split(ppn[i], ','); /* look at each element */ for (j = 0; NULL != npn[j]; j++) { /* is this a range? */ if (NULL != (cptr = strchr(npn[j], '-'))) { /* terminate the string */ *cptr = '\0'; ++cptr; start = strtol(npn[j], NULL, 10); end = strtol(cptr, NULL, 10); /* are we collecting a range? */ if (NULL == rng) { /* no - better start one */ rng = PMIX_NEW(pmix_regex_range_t); rng->start = start; rng->cnt = end - start + 1; pmix_list_append(&vreg->ranges, &rng->super); } else { /* is this a continuation of the current range? */ if (start == (rng->start + rng->cnt)) { /* just add it to the end of this range */ rng->cnt++; } else { /* nope, there is a break - create new range */ rng = PMIX_NEW(pmix_regex_range_t); rng->start = start; rng->cnt = end - start + 1; pmix_list_append(&vreg->ranges, &rng->super); } } } else { /* single rank given */ start = strtol(npn[j], NULL, 10); /* are we collecting a range? */ if (NULL == rng) { /* no - better start one */ rng = PMIX_NEW(pmix_regex_range_t); rng->start = start; rng->cnt = 1; pmix_list_append(&vreg->ranges, &rng->super); } else { /* is this a continuation of the current range? */ if (start == (rng->start + rng->cnt)) { /* just add it to the end of this range */ rng->cnt++; } else { /* nope, there is a break - create new range */ rng = PMIX_NEW(pmix_regex_range_t); rng->start = start; rng->cnt = 1; pmix_list_append(&vreg->ranges, &rng->super); } } } } PMIx_Argv_free(npn); } PMIx_Argv_free(ppn); /* begin constructing the regular expression */ tmp = strdup("pmix["); PMIX_LIST_FOREACH (vreg, &nodes, pmix_regex_value_t) { while (NULL != (rng = (pmix_regex_range_t *) pmix_list_remove_first(&vreg->ranges))) { if (1 == rng->cnt) { if (0 > asprintf(&tmp2, "%s%d,", tmp, rng->start)) { free(tmp); return PMIX_ERR_NOMEM; } } else { if (0 > asprintf(&tmp2, "%s%d-%d,", tmp, rng->start, rng->start + rng->cnt - 1)) { free(tmp); return PMIX_ERR_NOMEM; } } free(tmp); tmp = tmp2; PMIX_RELEASE(rng); } /* replace the final comma */ tmp[strlen(tmp) - 1] = ';'; } /* replace the final semi-colon */ tmp[strlen(tmp) - 1] = ']'; /* if this results in a longer answer, then don't do it */ if (strlen(tmp) > strlen(input)) { free(tmp); PMIX_LIST_DESTRUCT(&nodes); return PMIX_ERR_TAKE_NEXT_OPTION; } /* assemble final result */ *regexp = tmp; PMIX_LIST_DESTRUCT(&nodes); return PMIX_SUCCESS; } static pmix_status_t parse_nodes(const char *regexp, char ***names) { char *tmp, *ptr; pmix_status_t rc; /* set default */ *names = NULL; /* protect against bozo */ if (NULL == regexp) { return PMIX_SUCCESS; } /* protect the input string */ tmp = strdup(regexp); /* strip the trailing bracket */ tmp[strlen(tmp) - 1] = '\0'; /* the regex generator used to create this regex * is tagged at the beginning of the string */ if (NULL == (ptr = strchr(tmp, '['))) { free(tmp); return PMIX_ERR_BAD_PARAM; } *ptr = '\0'; ++ptr; /* if it was done by PMIx, use that parser */ if (0 == strcmp(tmp, "pmix")) { if (PMIX_SUCCESS != (rc = pmix_regex_extract_nodes(ptr, names))) { PMIX_ERROR_LOG(rc); } } else { /* this isn't an error - let someone else try */ rc = PMIX_ERR_TAKE_NEXT_OPTION; } free(tmp); return rc; } static pmix_status_t parse_procs(const char *regexp, char ***procs) { char *tmp, *ptr; pmix_status_t rc; /* set default */ *procs = NULL; /* protect against bozo */ if (NULL == regexp) { return PMIX_SUCCESS; } /* protect the input string */ tmp = strdup(regexp); /* strip the trailing bracket */ tmp[strlen(tmp) - 1] = '\0'; /* the regex generator used to create this regex * is tagged at the beginning of the string */ if (NULL == (ptr = strchr(tmp, '['))) { free(tmp); return PMIX_ERR_BAD_PARAM; } *ptr = '\0'; ++ptr; /* if it was done by PMIx, use that parser */ if (0 == strcmp(tmp, "pmix")) { if (PMIX_SUCCESS != (rc = pmix_regex_extract_ppn(ptr, procs))) { PMIX_ERROR_LOG(rc); } } else { /* this isn't an error - let someone else try */ rc = PMIX_ERR_TAKE_NEXT_OPTION; } free(tmp); return rc; } static pmix_status_t copy(char **dest, size_t *len, const char *input) { if (0 != strncmp(input, "pmix", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } *dest = strdup(input); *len = strlen(input) + 1; return PMIX_SUCCESS; } static pmix_status_t pack(pmix_buffer_t *buffer, const char *input) { size_t slen; char *ptr; if (0 != strncmp(input, "pmix", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* extract the size */ slen = strlen(input) + 1; // retain the NULL terminator /* ensure the buffer has enough space */ ptr = pmix_bfrop_buffer_extend(buffer, slen); if (NULL == ptr) { return PMIX_ERR_NOMEM; } /* xfer the data */ memcpy(ptr, input, slen); buffer->bytes_used += slen; buffer->pack_ptr += slen; return PMIX_SUCCESS; } static pmix_status_t unpack(pmix_buffer_t *buffer, char **regex) { char *ptr; ptr = buffer->unpack_ptr; if (0 != strncmp(ptr, "pmix", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } *regex = strdup(ptr); buffer->unpack_ptr += strlen(ptr) + 1; if (NULL == *regex) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } static pmix_status_t pmix_regex_extract_nodes(char *regexp, char ***names) { int i, j, k, len; pmix_status_t ret; char *base; char *orig, *suffix; bool found_range = false; bool more_to_come = false; int num_digits; /* set the default */ *names = NULL; if (NULL == regexp) { return PMIX_SUCCESS; } orig = base = strdup(regexp); if (NULL == base) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return PMIX_ERR_OUT_OF_RESOURCE; } pmix_output_verbose(1, pmix_preg_base_framework.framework_output, "pmix:extract:nodes: checking list: %s", regexp); do { /* Find the base */ len = strlen(base); for (i = 0; i <= len; ++i) { if (base[i] == '[') { /* we found a range. this gets dealt with below */ base[i] = '\0'; found_range = true; break; } if (base[i] == ',') { /* we found a singleton value, and there are more to come */ base[i] = '\0'; found_range = false; more_to_come = true; break; } if (base[i] == '\0') { /* we found a singleton value */ found_range = false; more_to_come = false; break; } } if (i == 0 && !found_range) { /* we found a special character at the beginning of the string */ free(orig); return PMIX_ERR_BAD_PARAM; } if (found_range) { /* If we found a range, get the number of digits in the numbers */ i++; /* step over the [ */ for (j = i; j < len; j++) { if (base[j] == ':') { base[j] = '\0'; break; } } if (j >= len) { /* we didn't find the number of digits */ free(orig); return PMIX_ERR_BAD_PARAM; } num_digits = strtol(&base[i], NULL, 10); i = j + 1; /* step over the : */ /* now find the end of the range */ for (j = i; j < len; ++j) { if (base[j] == ']') { base[j] = '\0'; break; } } if (j >= len) { /* we didn't find the end of the range */ free(orig); return PMIX_ERR_BAD_PARAM; } /* check for a suffix */ if (j + 1 < len && base[j + 1] != ',') { /* find the next comma, if present */ for (k = j + 1; k < len && base[k] != ','; k++) ; if (k < len) { base[k] = '\0'; } suffix = strdup(&base[j + 1]); if (k < len) { base[k] = ','; } j = k - 1; } else { suffix = NULL; } pmix_output_verbose(1, pmix_preg_base_framework.framework_output, "regex:extract:nodes: parsing range %s %s %s", base, base + i, suffix); ret = regex_parse_value_ranges(base, base + i, num_digits, suffix, names); if (NULL != suffix) { free(suffix); } if (PMIX_SUCCESS != ret) { free(orig); return ret; } if (j + 1 < len && base[j + 1] == ',') { more_to_come = true; base = &base[j + 2]; } else { more_to_come = false; } } else { /* If we didn't find a range, just add the value */ if (PMIX_SUCCESS != (ret = PMIx_Argv_append_nosize(names, base))) { PMIX_ERROR_LOG(ret); free(orig); return ret; } /* step over the comma */ i++; /* set base equal to the (possible) next base to look at */ base = &base[i]; } } while (more_to_come); free(orig); /* All done */ return ret; } /* * Parse one or more ranges in a set * * @param base The base text of the value name * @param *ranges A pointer to a range. This can contain multiple ranges * (i.e. "1-3,10" or "5" or "9,0100-0130,250") * @param ***names An argv array to add the newly discovered values to */ static pmix_status_t regex_parse_value_ranges(char *base, char *ranges, int num_digits, char *suffix, char ***names) { int i, len; pmix_status_t ret; char *start, *orig; /* Look for commas, the separator between ranges */ len = strlen(ranges); for (orig = start = ranges, i = 0; i < len; ++i) { if (',' == ranges[i]) { ranges[i] = '\0'; ret = regex_parse_value_range(base, start, num_digits, suffix, names); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } start = ranges + i + 1; } } /* Pick up the last range, if it exists */ if (start < orig + len) { pmix_output_verbose(1, pmix_preg_base_framework.framework_output, "regex:parse:ranges: parse range %s (2)", start); ret = regex_parse_value_range(base, start, num_digits, suffix, names); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); return ret; } } /* All done */ return PMIX_SUCCESS; } /* * Parse a single range in a set and add the full names of the values * found to the names argv * * @param base The base text of the value name * @param *ranges A pointer to a single range. (i.e. "1-3" or "5") * @param ***names An argv array to add the newly discovered values to */ static pmix_status_t regex_parse_value_range(char *base, char *range, int num_digits, char *suffix, char ***names) { char *str, tmp[132]; size_t i, k, start, end; size_t base_len, len; bool found; pmix_status_t ret; if (NULL == base || NULL == range) { return PMIX_ERROR; } len = strlen(range); base_len = strlen(base); /* Silence compiler warnings; start and end are always assigned properly, below */ start = end = 0; /* Look for the beginning of the first number */ for (found = false, i = 0; i < len; ++i) { if (isdigit((int) range[i])) { if (!found) { start = strtol(range + i, NULL, 10); found = true; break; } } } if (!found) { PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND); return PMIX_ERR_NOT_FOUND; } /* Look for the end of the first number */ for (found = false; i < len; ++i) { if (!isdigit(range[i])) { break; } } /* Was there no range, just a single number? */ if (i >= len) { end = start; found = true; } else { /* Nope, there was a range. Look for the beginning of the second * number */ for (; i < len; ++i) { if (isdigit(range[i])) { end = strtol(range + i, NULL, 10); found = true; break; } } } if (!found) { PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND); return PMIX_ERR_NOT_FOUND; } /* Make strings for all values in the range */ len = base_len + num_digits + 32; if (NULL != suffix) { len += strlen(suffix); } str = (char *) malloc(len); if (NULL == str) { PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); return PMIX_ERR_OUT_OF_RESOURCE; } for (i = start; i <= end; ++i) { memset(str, 0, len); strcpy(str, base); /* we need to zero-pad the digits */ for (k = 0; k < (size_t) num_digits; k++) { str[k + base_len] = '0'; } memset(tmp, 0, 132); pmix_snprintf(tmp, 132, "%lu", (unsigned long) i); for (k = 0; k < strlen(tmp); k++) { str[base_len + num_digits - k - 1] = tmp[strlen(tmp) - k - 1]; } /* if there is a suffix, add it */ if (NULL != suffix) { strcat(str, suffix); } ret = PMIx_Argv_append_nosize(names, str); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); free(str); return ret; } } free(str); /* All done */ return PMIX_SUCCESS; } static pmix_status_t pmix_regex_extract_ppn(char *regexp, char ***procs) { char **rngs, **nds, *t, **ps = NULL; int i, j, k, start, end; /* split on semi-colons for nodes */ nds = PMIx_Argv_split(regexp, ';'); for (j = 0; NULL != nds[j]; j++) { /* for each node, split it by comma */ rngs = PMIx_Argv_split(nds[j], ','); /* parse each element */ for (i = 0; NULL != rngs[i]; i++) { /* look for a range */ if (NULL == (t = strchr(rngs[i], '-'))) { /* just one value */ PMIx_Argv_append_nosize(&ps, rngs[i]); } else { /* handle the range */ *t = '\0'; start = strtol(rngs[i], NULL, 10); ++t; end = strtol(t, NULL, 10); for (k = start; k <= end; k++) { if (0 > asprintf(&t, "%d", k)) { PMIx_Argv_free(nds); PMIx_Argv_free(rngs); return PMIX_ERR_NOMEM; } PMIx_Argv_append_nosize(&ps, t); free(t); } } } PMIx_Argv_free(rngs); /* create the node entry */ t = PMIx_Argv_join(ps, ','); PMIx_Argv_append_nosize(procs, t); free(t); PMIx_Argv_free(ps); ps = NULL; } PMIx_Argv_free(nds); return PMIX_SUCCESS; } static pmix_status_t release(char *regexp) { if (NULL == regexp) { return PMIX_SUCCESS; } if (0 != strncmp(regexp, "pmix", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } free(regexp); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/preg/native/preg_native.h0000664000175000017500000000106515203536752021725 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PREG_NATIVE_H #define PMIX_PREG_NATIVE_H #include "src/include/pmix_config.h" #include "src/mca/preg/preg.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_mca_base_component_t pmix_mca_preg_native_component; extern pmix_preg_module_t pmix_preg_native_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/preg/native/preg_native_component.c0000664000175000017500000000513015203536752023777 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "preg_native.h" #include "src/mca/preg/preg.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_mca_base_component_t pmix_mca_preg_native_component = { PMIX_PREG_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "native", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, preg, native) static int component_open(void) { return PMIX_SUCCESS; } static int component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 30; *module = (pmix_mca_base_module_t *) &pmix_preg_native_module; return PMIX_SUCCESS; } static int component_close(void) { return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/preg/native/Makefile.am0000664000175000017500000000346015203536752021306 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = preg_native.h sources = \ preg_native_component.c \ preg_native.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_preg_native_DSO lib = lib_sources = component = pmix_mca_preg_native.la component_sources = $(headers) $(sources) else lib = libpmix_mca_preg_native.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_preg_native_la_SOURCES = $(component_sources) pmix_mca_preg_native_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_preg_native_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_preg_native_la_SOURCES = $(lib_sources) libpmix_mca_preg_native_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/preg/compress/0000775000175000017500000000000015203536752017614 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/preg/compress/preg_compress_component.c0000664000175000017500000000541615203536752024720 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "preg_compress.h" #include "src/mca/pcompress/pcompress.h" #include "src/mca/preg/preg.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_mca_base_component_t pmix_mca_preg_compress_component = { PMIX_PREG_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "compress", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, preg, compress) static int component_open(void) { return PMIX_SUCCESS; } static int component_query(pmix_mca_base_module_t **module, int *priority) { if (NULL == pmix_compress.compress_string) { return PMIX_ERROR; } /* we should always be first in priority */ *priority = 100; *module = (pmix_mca_base_module_t *) &pmix_preg_compress_module; return PMIX_SUCCESS; } static int component_close(void) { return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/preg/compress/preg_compress.c0000664000175000017500000002172315203536752022635 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2019 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "include/pmix.h" #include "pmix_common.h" #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/gds.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "preg_compress.h" #include "src/mca/pcompress/pcompress.h" #include "src/mca/preg/base/base.h" static pmix_status_t generate_node_regex(const char *input, char **regex); static pmix_status_t generate_ppn(const char *input, char **ppn); static pmix_status_t parse_nodes(const char *regexp, char ***names); static pmix_status_t parse_procs(const char *regexp, char ***procs); static pmix_status_t copy(char **dest, size_t *len, const char *input); static pmix_status_t pack(pmix_buffer_t *buffer, const char *input); static pmix_status_t unpack(pmix_buffer_t *buffer, char **regex); static pmix_status_t release(char *regexp); pmix_preg_module_t pmix_preg_compress_module = { .name = "compress", .generate_node_regex = generate_node_regex, .generate_ppn = generate_ppn, .parse_nodes = parse_nodes, .parse_procs = parse_procs, .copy = copy, .pack = pack, .unpack = unpack, .release = release }; #define PREG_COMPRESS_PREFIX "blob: component=zlib: size=" static pmix_status_t pack_blob(const uint8_t *tmp, size_t len, char **regexp) { char *result, *slen; int idx; /* convert the length to a string */ if (0 > asprintf(&slen, "%lu", (unsigned long) len)) { return PMIX_ERR_NOMEM; } /* create the result */ result = calloc(len + strlen(PREG_COMPRESS_PREFIX) + strlen(slen) + strlen(":") + 1, sizeof(char)); idx = 0; strcpy(result, "blob:"); idx += strlen("blob:") + 1; // step over NULL terminator strcpy(&result[idx], "component=zlib:"); idx += strlen("component=zlib:") + 1; // step over NULL terminator strcpy(&result[idx], "size="); idx += strlen("size="); strcpy(&result[idx], slen); idx += strlen(slen); strcpy(&result[idx], ":"); idx += strlen(":") + 1; // step over NULL terminator memcpy(&result[idx], tmp, len); free(slen); *regexp = result; return PMIX_SUCCESS; } static pmix_status_t generate_node_regex(const char *input, char **regexp) { size_t len; uint8_t *tmp; pmix_status_t rc; if (!pmix_compress.compress_string((char *) input, &tmp, &len)) { return PMIX_ERR_TAKE_NEXT_OPTION; } if (NULL == tmp) { return PMIX_ERR_NOMEM; } rc = pack_blob(tmp, len, regexp); free(tmp); return rc; } static pmix_status_t generate_ppn(const char *input, char **regexp) { size_t len; uint8_t *tmp; pmix_status_t rc; if (!pmix_compress.compress_string((char *) input, &tmp, &len)) { return PMIX_ERR_TAKE_NEXT_OPTION; } if (NULL == tmp) { return PMIX_ERR_NOMEM; } rc = pack_blob(tmp, len, regexp); free(tmp); return rc; } static pmix_status_t parse_nodes(const char *regexp, char ***names) { char *tmp, *ptr, **argv; size_t len; int idx; if (0 != strncmp(regexp, "blob", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx = strlen(regexp) + 1; // step over the NULL terminator /* ensure we were the one who generated this blob */ if (0 != strncmp(®exp[idx], "component=zlib:", strlen("component=zlib:"))) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx += strlen("component=zlib:") + 1; // step over the NULL terminator idx += strlen("size="); len = strtoul(®exp[idx], &ptr, 10); ptr += 2; // step over colon and NULL if (!pmix_compress.decompress_string(&tmp, (uint8_t *) ptr, len)) { free(tmp); return PMIX_ERR_TAKE_NEXT_OPTION; } /* tmp now contains the comma-delimited list of node names */ argv = PMIx_Argv_split(tmp, ','); free(tmp); *names = argv; return PMIX_SUCCESS; } static pmix_status_t parse_procs(const char *regexp, char ***procs) { char *tmp, *ptr, **argv; size_t len; int idx; if (0 != strncmp(regexp, "blob", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx = strlen(regexp) + 1; // step over the NULL terminator /* ensure we were the one who generated this blob */ if (0 != strncmp(®exp[idx], "component=zlib:", strlen("component=zlib:"))) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx += strlen("component=zlib:") + 1; // step over the NULL terminator idx += strlen("size="); len = strtoul(®exp[idx], &ptr, 10); ptr += 2; // step over colon and NULL if (!pmix_compress.decompress_string(&tmp, (uint8_t *) ptr, len)) { free(tmp); return PMIX_ERR_TAKE_NEXT_OPTION; } /* tmp now contains the semicolon-delimited list of procs */ argv = PMIx_Argv_split(tmp, ';'); free(tmp); *procs = argv; return PMIX_SUCCESS; } static pmix_status_t copy(char **dest, size_t *len, const char *input) { size_t slen; char *tmp; int idx; if (0 != strncmp(input, "blob", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx = strlen(input) + 1; // step over the NULL terminator /* ensure we were the one who generated this blob */ if (0 != strncmp(&input[idx], "component=zlib:", strlen("component=zlib:"))) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx += strlen("component=zlib:") + 1; // step over the NULL terminator /* extract the size */ idx += strlen("size="); slen = strtoul(&input[idx], NULL, 10) + strlen(PREG_COMPRESS_PREFIX) + strlen(&input[idx]) + 1; /* malloc the space */ tmp = calloc(slen, sizeof(char)); if (NULL == tmp) { return PMIX_ERR_NOMEM; } /* copy the data */ memcpy(tmp, input, slen); *dest = tmp; *len = slen; return PMIX_SUCCESS; } static pmix_status_t pack(pmix_buffer_t *buffer, const char *input) { size_t slen; char *ptr; int idx; if (0 != strncmp(input, "blob", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx = strlen(input) + 1; // step over the NULL terminator /* ensure we were the one who generated this blob */ if (0 != strncmp(&input[idx], "component=zlib:", strlen("component=zlib:"))) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx += strlen("component=zlib:") + 1; // step over the NULL terminator /* extract the size */ idx += strlen("size="); slen = strtoul(&input[idx], NULL, 10) + strlen(PREG_COMPRESS_PREFIX) + strlen(&input[idx]) + 1; /* ensure the buffer has enough space */ ptr = pmix_bfrop_buffer_extend(buffer, slen); if (NULL == ptr) { return PMIX_ERR_NOMEM; } /* xfer the data */ memcpy(ptr, input, slen); buffer->bytes_used += slen; buffer->pack_ptr += slen; return PMIX_SUCCESS; } static pmix_status_t unpack(pmix_buffer_t *buffer, char **regex) { size_t slen; char *ptr, *output; int idx; /* the value starts at the unpack_ptr */ ptr = buffer->unpack_ptr; if (0 != strncmp(ptr, "blob", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx = strlen(ptr) + 1; // step over the NULL terminator /* ensure we were the one who generated this blob */ if (0 != strncmp(&ptr[idx], "component=zlib:", strlen("component=zlib:"))) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx += strlen("component=zlib:") + 1; // step over the NULL terminator /* extract the size */ idx += strlen("size="); slen = strtoul(&ptr[idx], NULL, 10) + strlen(PREG_COMPRESS_PREFIX) + strlen(&ptr[idx]) + 1; /* get the space */ output = (char *) malloc(slen); if (NULL == output) { *regex = NULL; return PMIX_ERR_NOMEM; } /* xfer the data */ memcpy(output, ptr, slen); buffer->unpack_ptr += slen; *regex = output; return PMIX_SUCCESS; } static pmix_status_t release(char *regexp) { int idx; if (NULL == regexp) { return PMIX_SUCCESS; } if (0 != strncmp(regexp, "blob", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } idx = strlen(regexp) + 1; // step over the NULL terminator /* ensure we were the one who generated this blob */ if (0 != strncmp(®exp[idx], "component=zlib:", strlen("component=zlib:"))) { return PMIX_ERR_TAKE_NEXT_OPTION; } // just free it free(regexp); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/preg/compress/Makefile.am0000664000175000017500000000350615203536752021654 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = preg_compress.h sources = \ preg_compress_component.c \ preg_compress.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_preg_compress_DSO lib = lib_sources = component = pmix_mca_preg_compress.la component_sources = $(headers) $(sources) else lib = libpmix_mca_preg_compress.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_preg_compress_la_SOURCES = $(component_sources) pmix_mca_preg_compress_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_preg_compress_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_preg_compress_la_SOURCES = $(lib_sources) libpmix_mca_preg_compress_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/preg/compress/preg_compress.h0000664000175000017500000000107515203536752022640 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PREG_compress_H #define PMIX_PREG_compress_H #include "src/include/pmix_config.h" #include "src/mca/preg/preg.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_mca_base_component_t pmix_mca_preg_compress_component; extern pmix_preg_module_t pmix_preg_compress_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/preg/raw/0000775000175000017500000000000015203536752016552 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/preg/raw/preg_raw.c0000664000175000017500000001004515203536752020524 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016-2019 IBM Corporation. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "include/pmix.h" #include "pmix_common.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_printf.h" #include "preg_raw.h" #include "src/mca/preg/base/base.h" static pmix_status_t generate_node_regex(const char *input, char **regex); static pmix_status_t generate_ppn(const char *input, char **ppn); static pmix_status_t parse_nodes(const char *regexp, char ***names); static pmix_status_t parse_procs(const char *regexp, char ***procs); static pmix_status_t copy(char **dest, size_t *len, const char *input); static pmix_status_t pack(pmix_buffer_t *buffer, const char *input); static pmix_status_t unpack(pmix_buffer_t *buffer, char **regex); static pmix_status_t release(char *regexp); pmix_preg_module_t pmix_preg_raw_module = { .name = "raw", .generate_node_regex = generate_node_regex, .generate_ppn = generate_ppn, .parse_nodes = parse_nodes, .parse_procs = parse_procs, .copy = copy, .pack = pack, .unpack = unpack, .release = release }; static pmix_status_t generate_node_regex(const char *input, char **regexp) { if (0 == strncmp(input, "raw:", 4)) { *regexp = strdup(input); } else { pmix_asprintf(regexp, "raw:%s", input); } return PMIX_SUCCESS; } static pmix_status_t generate_ppn(const char *input, char **regexp) { if (0 == strncmp(input, "raw:", 4)) { *regexp = strdup(input); } else { pmix_asprintf(regexp, "raw:%s", input); } return PMIX_SUCCESS; } static pmix_status_t parse_nodes(const char *regexp, char ***names) { if (0 != strncmp(regexp, "raw:", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } *names = PMIx_Argv_split(®exp[4], ','); return PMIX_SUCCESS; } static pmix_status_t parse_procs(const char *regexp, char ***procs) { if (0 != strncmp(regexp, "raw:", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } *procs = PMIx_Argv_split(®exp[4], ';'); return PMIX_SUCCESS; } static pmix_status_t copy(char **dest, size_t *len, const char *input) { if (0 != strncmp(input, "raw:", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } *dest = strdup(input); *len = strlen(input) + 1; return PMIX_SUCCESS; } static pmix_status_t pack(pmix_buffer_t *buffer, const char *input) { size_t slen; char *ptr; if (0 != strncmp(input, "raw:", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* extract the size */ slen = strlen(input) + 1; // retain the NULL terminator /* ensure the buffer has enough space */ ptr = pmix_bfrop_buffer_extend(buffer, slen); if (NULL == ptr) { return PMIX_ERR_NOMEM; } /* xfer the data */ memcpy(ptr, input, slen); buffer->bytes_used += slen; buffer->pack_ptr += slen; return PMIX_SUCCESS; } static pmix_status_t unpack(pmix_buffer_t *buffer, char **regex) { char *ptr; ptr = buffer->unpack_ptr; if (0 != strncmp(ptr, "raw:", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } *regex = strdup(ptr); buffer->unpack_ptr += strlen(ptr) + 1; if (NULL == *regex) { return PMIX_ERR_NOMEM; } return PMIX_SUCCESS; } static pmix_status_t release(char *regexp) { if (NULL == regexp) { return PMIX_SUCCESS; } if (0 != strncmp(regexp, "raw:", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } free(regexp); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/preg/raw/preg_raw_component.c0000664000175000017500000000511115203536752022604 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "preg_raw.h" #include "src/mca/preg/preg.h" static pmix_status_t component_open(void); static pmix_status_t component_close(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_mca_base_component_t pmix_mca_preg_raw_component = { PMIX_PREG_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "raw", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_open_component = component_open, .pmix_mca_close_component = component_close, .pmix_mca_query_component = component_query, }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, preg, raw) static int component_open(void) { return PMIX_SUCCESS; } static int component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 50; *module = (pmix_mca_base_module_t *) &pmix_preg_raw_module; return PMIX_SUCCESS; } static int component_close(void) { return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/preg/raw/Makefile.am0000664000175000017500000000341715203536752020613 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = preg_raw.h sources = \ preg_raw_component.c \ preg_raw.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_preg_raw_DSO lib = lib_sources = component = pmix_mca_preg_raw.la component_sources = $(headers) $(sources) else lib = libpmix_mca_preg_raw.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_preg_raw_la_SOURCES = $(component_sources) pmix_mca_preg_raw_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_preg_raw_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_preg_raw_la_SOURCES = $(lib_sources) libpmix_mca_preg_raw_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/preg/raw/preg_raw.h0000664000175000017500000000105115203536752020526 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PREG_RAW_H #define PMIX_PREG_RAW_H #include "src/include/pmix_config.h" #include "src/mca/preg/preg.h" BEGIN_C_DECLS /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_mca_base_component_t pmix_mca_preg_raw_component; extern pmix_preg_module_t pmix_preg_raw_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/preg/preg_types.h0000664000175000017500000000341615203536752020317 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 IBM Corporation. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Buffer management types. */ #ifndef PMIX_MCA_PREG_TYPES_H_ #define PMIX_MCA_PREG_TYPES_H_ #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/class/pmix_object.h" BEGIN_C_DECLS /* these classes are required by the regex code */ typedef struct { pmix_list_item_t super; int start; int cnt; } pmix_regex_range_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_regex_range_t); typedef struct { /* list object */ pmix_list_item_t super; char *prefix; char *suffix; int num_digits; pmix_list_t ranges; bool skip; } pmix_regex_value_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_regex_value_t); END_C_DECLS #endif /* PMIX_PREG_TYPES_H */ pmix-6.1.1~rc2/src/mca/preg/base/0000775000175000017500000000000015203536752016673 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/preg/base/preg_base_stubs.c0000664000175000017500000001237715203536752022220 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/preg/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" pmix_status_t pmix_preg_base_generate_node_regex(const char *input, char **regex) { pmix_preg_base_active_module_t *active; PMIX_LIST_FOREACH (active, &pmix_preg_globals.actives, pmix_preg_base_active_module_t) { if (NULL != active->module->generate_node_regex) { if (PMIX_SUCCESS == active->module->generate_node_regex(input, regex)) { return PMIX_SUCCESS; } } } /* no regex could be generated */ *regex = strdup(input); return PMIX_SUCCESS; } pmix_status_t pmix_preg_base_generate_ppn(const char *input, char **ppn) { pmix_preg_base_active_module_t *active; PMIX_LIST_FOREACH (active, &pmix_preg_globals.actives, pmix_preg_base_active_module_t) { if (NULL != active->module->generate_ppn) { if (PMIX_SUCCESS == active->module->generate_ppn(input, ppn)) { return PMIX_SUCCESS; } } } /* no regex could be generated */ *ppn = strdup(input); return PMIX_SUCCESS; } pmix_status_t pmix_preg_base_parse_nodes(const char *regexp, char ***names) { pmix_preg_base_active_module_t *active; PMIX_LIST_FOREACH (active, &pmix_preg_globals.actives, pmix_preg_base_active_module_t) { if (NULL != active->module->parse_nodes) { if (PMIX_SUCCESS == active->module->parse_nodes(regexp, names)) { return PMIX_SUCCESS; } } } /* nobody could parse it, so just process it here */ *names = PMIx_Argv_split(regexp, ','); return PMIX_SUCCESS; } pmix_status_t pmix_preg_base_parse_procs(const char *regexp, char ***procs) { pmix_preg_base_active_module_t *active; PMIX_LIST_FOREACH (active, &pmix_preg_globals.actives, pmix_preg_base_active_module_t) { if (NULL != active->module->parse_procs) { if (PMIX_SUCCESS == active->module->parse_procs(regexp, procs)) { return PMIX_SUCCESS; } } } /* nobody could parse it, so just process it here */ *procs = PMIx_Argv_split(regexp, ';'); return PMIX_SUCCESS; } pmix_status_t pmix_preg_base_copy(char **dest, size_t *len, const char *input) { pmix_preg_base_active_module_t *active; PMIX_LIST_FOREACH (active, &pmix_preg_globals.actives, pmix_preg_base_active_module_t) { if (NULL != active->module->copy) { if (PMIX_SUCCESS == active->module->copy(dest, len, input)) { return PMIX_SUCCESS; } } } /* nobody could handle it, so it must just be a string */ *dest = strdup(input); *len = strlen(input) + 1; return PMIX_SUCCESS; } pmix_status_t pmix_preg_base_pack(pmix_buffer_t *buffer, const char *input) { pmix_preg_base_active_module_t *active; pmix_status_t rc; PMIX_LIST_FOREACH (active, &pmix_preg_globals.actives, pmix_preg_base_active_module_t) { if (NULL != active->module->pack) { if (PMIX_SUCCESS == active->module->pack(buffer, input)) { return PMIX_SUCCESS; } } } /* just pack it as a string */ PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, buffer, input, 1, PMIX_STRING); return rc; } pmix_status_t pmix_preg_base_unpack(pmix_buffer_t *buffer, char **regex) { pmix_preg_base_active_module_t *active; pmix_status_t rc; int32_t cnt = 1; PMIX_LIST_FOREACH (active, &pmix_preg_globals.actives, pmix_preg_base_active_module_t) { if (NULL != active->module->unpack) { if (PMIX_SUCCESS == active->module->unpack(buffer, regex)) { return PMIX_SUCCESS; } } } /* must just be a string */ PMIX_BFROPS_UNPACK(rc, pmix_globals.mypeer, buffer, regex, &cnt, PMIX_STRING); return rc; } pmix_status_t pmix_preg_base_release(char *regexp) { pmix_preg_base_active_module_t *active; PMIX_LIST_FOREACH (active, &pmix_preg_globals.actives, pmix_preg_base_active_module_t) { if (NULL != active->module->release) { if (PMIX_SUCCESS == active->module->release(regexp)) { return PMIX_SUCCESS; } } } return PMIX_ERR_BAD_PARAM; } pmix-6.1.1~rc2/src/mca/preg/base/preg_base_select.c0000664000175000017500000001172415203536752022332 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/util/pmix_error.h" #include "src/util/pmix_show_help.h" #include "src/mca/preg/base/base.h" /* Function for selecting a prioritized list of components * from all those that are available. */ int pmix_preg_base_select(void) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_mca_base_component_t *component = NULL; pmix_mca_base_module_t *module = NULL; pmix_preg_module_t *nmodule; pmix_preg_base_active_module_t *newmodule, *mod; int rc, priority; bool inserted; if (pmix_preg_globals.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_preg_globals.selected = true; /* Query all available components and ask if they have a module */ PMIX_LIST_FOREACH (cli, &pmix_preg_base_framework.framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_mca_base_component_t *) cli->cli_component; pmix_output_verbose(5, pmix_preg_base_framework.framework_output, "mca:preg:select: checking available component %s", component->pmix_mca_component_name); /* If there's no query function, skip it */ if (NULL == component->pmix_mca_query_component) { pmix_output_verbose( 5, pmix_preg_base_framework.framework_output, "mca:preg:select: Skipping component [%s]. It does not implement a query function", component->pmix_mca_component_name); continue; } /* Query the component */ pmix_output_verbose(5, pmix_preg_base_framework.framework_output, "mca:preg:select: Querying component [%s]", component->pmix_mca_component_name); rc = component->pmix_mca_query_component(&module, &priority); /* If no module was returned, then skip component */ if (PMIX_SUCCESS != rc || NULL == module) { pmix_output_verbose( 5, pmix_preg_base_framework.framework_output, "mca:preg:select: Skipping component [%s]. Query failed to return a module", component->pmix_mca_component_name); continue; } /* If we got a module, keep it */ nmodule = (pmix_preg_module_t *) module; /* add to the list of selected modules */ newmodule = PMIX_NEW(pmix_preg_base_active_module_t); newmodule->pri = priority; newmodule->module = nmodule; newmodule->component = (pmix_mca_base_component_t *) cli->cli_component; /* maintain priority order */ inserted = false; PMIX_LIST_FOREACH (mod, &pmix_preg_globals.actives, pmix_preg_base_active_module_t) { if (priority > mod->pri) { pmix_list_insert_pos(&pmix_preg_globals.actives, (pmix_list_item_t *) mod, &newmodule->super); inserted = true; break; } } if (!inserted) { /* must be lowest priority - add to end */ pmix_list_append(&pmix_preg_globals.actives, &newmodule->super); } } /* if no modules were found, then that's an error as we require at least one */ if (0 == pmix_list_get_size(&pmix_preg_globals.actives)) { pmix_show_help("help-pmix-runtime.txt", "no-plugins", true, "PREG"); return PMIX_ERR_SILENT; } if (4 < pmix_output_get_verbosity(pmix_preg_base_framework.framework_output)) { pmix_output(0, "Final preg priorities"); /* show the prioritized list */ PMIX_LIST_FOREACH (mod, &pmix_preg_globals.actives, pmix_preg_base_active_module_t) { pmix_output(0, "\tpreg: %s Priority: %d", mod->component->pmix_mca_component_name, mod->pri); } } return PMIX_SUCCESS; ; } pmix-6.1.1~rc2/src/mca/preg/base/base.h0000664000175000017500000000574615203536752017772 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PREG_BASE_H_ #define PMIX_PREG_BASE_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_pointer_array.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/mca.h" #include "src/mca/preg/preg.h" BEGIN_C_DECLS /* * MCA Framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_preg_base_framework; /** * PREG select function * * Cycle across available components and construct the list * of active modules */ PMIX_EXPORT pmix_status_t pmix_preg_base_select(void); /** * Track an active component / module */ struct pmix_preg_base_active_module_t { pmix_list_item_t super; int pri; pmix_preg_module_t *module; pmix_mca_base_component_t *component; }; typedef struct pmix_preg_base_active_module_t pmix_preg_base_active_module_t; PMIX_CLASS_DECLARATION(pmix_preg_base_active_module_t); /* framework globals */ struct pmix_preg_globals_t { pmix_list_t actives; bool initialized; bool selected; }; typedef struct pmix_preg_globals_t pmix_preg_globals_t; PMIX_EXPORT extern pmix_preg_globals_t pmix_preg_globals; PMIX_EXPORT pmix_status_t pmix_preg_base_generate_node_regex(const char *input, char **regex); PMIX_EXPORT pmix_status_t pmix_preg_base_generate_ppn(const char *input, char **ppn); PMIX_EXPORT pmix_status_t pmix_preg_base_parse_nodes(const char *regexp, char ***names); PMIX_EXPORT pmix_status_t pmix_preg_base_parse_procs(const char *regexp, char ***procs); PMIX_EXPORT pmix_status_t pmix_preg_base_copy(char **dest, size_t *len, const char *input); PMIX_EXPORT pmix_status_t pmix_preg_base_pack(pmix_buffer_t *buffer, const char *input); PMIX_EXPORT pmix_status_t pmix_preg_base_unpack(pmix_buffer_t *buffer, char **regex); PMIX_EXPORT pmix_status_t pmix_preg_base_release(char *regexp); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/preg/base/preg_base_frame.c0000664000175000017500000000740315203536752022144 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2009 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2019 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/preg/base/base.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public mca_base_component_t struct. */ #include "src/mca/preg/base/static-components.h" /* Instantiate the global vars */ pmix_preg_globals_t pmix_preg_globals = { .actives = PMIX_LIST_STATIC_INIT, .initialized = false, .selected = false }; pmix_preg_module_t pmix_preg = { .generate_node_regex = pmix_preg_base_generate_node_regex, .generate_ppn = pmix_preg_base_generate_ppn, .parse_nodes = pmix_preg_base_parse_nodes, .parse_procs = pmix_preg_base_parse_procs, .copy = pmix_preg_base_copy, .pack = pmix_preg_base_pack, .unpack = pmix_preg_base_unpack, .release = pmix_preg_base_release }; static pmix_status_t pmix_preg_close(void) { if (!pmix_preg_globals.initialized) { return PMIX_SUCCESS; } pmix_preg_globals.initialized = false; pmix_preg_globals.selected = false; PMIX_LIST_DESTRUCT(&pmix_preg_globals.actives); return pmix_mca_base_framework_components_close(&pmix_preg_base_framework, NULL); } static pmix_status_t pmix_preg_open(pmix_mca_base_open_flag_t flags) { /* initialize globals */ pmix_preg_globals.initialized = true; PMIX_CONSTRUCT(&pmix_preg_globals.actives, pmix_list_t); /* Open up all available components */ return pmix_mca_base_framework_components_open(&pmix_preg_base_framework, flags); } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, preg, "PMIx Regex Operations", NULL, pmix_preg_open, pmix_preg_close, pmix_mca_preg_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); PMIX_CLASS_INSTANCE(pmix_preg_base_active_module_t, pmix_list_item_t, NULL, NULL); static void rcon(pmix_regex_range_t *p) { p->start = 0; p->cnt = 0; } PMIX_CLASS_INSTANCE(pmix_regex_range_t, pmix_list_item_t, rcon, NULL); static void rvcon(pmix_regex_value_t *p) { p->prefix = NULL; p->suffix = NULL; p->num_digits = 0; p->skip = false; PMIX_CONSTRUCT(&p->ranges, pmix_list_t); } static void rvdes(pmix_regex_value_t *p) { if (NULL != p->prefix) { free(p->prefix); } if (NULL != p->suffix) { free(p->suffix); } PMIX_LIST_DESTRUCT(&p->ranges); } PMIX_CLASS_INSTANCE(pmix_regex_value_t, pmix_list_item_t, rvcon, rvdes); pmix-6.1.1~rc2/src/mca/preg/base/Makefile.include0000664000175000017500000000222015203536752021751 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2017 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from # src/Makefile.am headers += \ base/base.h sources += \ base/preg_base_frame.c \ base/preg_base_select.c \ base/preg_base_stubs.c pmix-6.1.1~rc2/src/mca/preg/Makefile.am0000664000175000017500000000255715203536752020026 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2017 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(LTDLINCL) # main library setup noinst_LTLIBRARIES = libmca_preg.la libmca_preg_la_SOURCES = # local files headers = preg.h preg_types.h sources = # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.include libmca_preg_la_SOURCES += $(headers) $(sources) distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/preg/preg.h0000664000175000017500000000717715203536752017103 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * This interface is for regex support. This is a multi-select framework. * * Available plugins may be defined at runtime via the typical MCA parameter * syntax. */ #ifndef PMIX_PREG_H #define PMIX_PREG_H #include "src/include/pmix_config.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/bfrops/bfrops_types.h" #include "src/mca/mca.h" #include "src/mca/preg/preg_types.h" BEGIN_C_DECLS /****** MODULE DEFINITION ******/ #define PMIX_MAX_NODE_PREFIX 8192 /* given a semicolon-separated list of input values, generate * a regex that can be passed down to a client for parsing. * The caller is responsible for free'ing the resulting * string * * If values have leading zero's, then that is preserved. * Example: * * Input: odin009;odin010;odin011;odin012;odin017;odin018;thor176 * * Output: * "foo:odin[009-012,017-018],thor176" * * Note that the "foo" at the beginning of the regex indicates * that the "foo" regex component is to be used to parse the * provided regex. */ typedef pmix_status_t (*pmix_preg_base_module_generate_node_regex_fn_t)(const char *input, char **regex); /* The input is expected to consist of a comma-separated list * of ranges. Thus, an input of: * "1-4;2-5;8,10,11,12;6,7,9" * would generate a regex of * "[pmix:2x(3);8,10-12;6-7,9]" * * Note that the "pmix" at the beginning of each regex indicates * that the PMIx native parser is to be used by the client for * parsing the provided regex. Other parsers may be supported - see * the pmix_client.h header for a list. */ typedef pmix_status_t (*pmix_preg_base_module_generate_ppn_fn_t)(const char *input, char **ppn); typedef pmix_status_t (*pmix_preg_base_module_parse_nodes_fn_t)(const char *regexp, char ***names); typedef pmix_status_t (*pmix_preg_base_module_parse_procs_fn_t)(const char *regexp, char ***procs); typedef pmix_status_t (*pmix_preg_base_module_copy_fn_t)(char **dest, size_t *len, const char *input); typedef pmix_status_t (*pmix_preg_base_module_pack_fn_t)(pmix_buffer_t *buffer, const char *regex); typedef pmix_status_t (*pmix_preg_base_module_unpack_fn_t)(pmix_buffer_t *buffer, char **regex); typedef pmix_status_t (*pmix_preg_base_module_release_fn_t)(char *regexp); /** * Base structure for a PREG module */ typedef struct { char *name; pmix_preg_base_module_generate_node_regex_fn_t generate_node_regex; pmix_preg_base_module_generate_ppn_fn_t generate_ppn; pmix_preg_base_module_parse_nodes_fn_t parse_nodes; pmix_preg_base_module_parse_procs_fn_t parse_procs; pmix_preg_base_module_copy_fn_t copy; pmix_preg_base_module_pack_fn_t pack; pmix_preg_base_module_unpack_fn_t unpack; pmix_preg_base_module_release_fn_t release; } pmix_preg_module_t; /* we just use the standard component definition */ PMIX_EXPORT extern pmix_preg_module_t pmix_preg; /* * Macro for use in components that are of type preg */ #define PMIX_PREG_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("preg", 1, 0, 0) END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/ptl/0000775000175000017500000000000015203536752015623 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/ptl/ptl.h0000664000175000017500000001633515203536752016603 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Data packing subsystem. */ #ifndef PMIX_PTL_H_ #define PMIX_PTL_H_ #include "src/include/pmix_config.h" #include "src/include/pmix_types.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/bfrops/bfrops_types.h" #include "src/mca/mca.h" #include "ptl_types.h" BEGIN_C_DECLS /* forward declaration */ struct pmix_peer_t; /* The overall objective of this framework is to provide transport * options by which a server can communicate with a client: * * (a) across different versions of the library - e.g., when the * connection handshake changes. * * (b) using different transports as necessitated by different * environments. * * This is a single-select framework - i.e., only one component * is selected and "active" at a time. The intent is * to have one component for each use-case, with the * expectation that the community will do its best not to revise * communications in manners that expand components to support (a). * Thus, new variations should be rare, and only a few components * will exist. */ /**** MODULE INTERFACE DEFINITION ****/ /* initialize the active plugin */ typedef pmix_status_t (*pmix_ptl_init_fn_t)(void); /* finalize the active plugin */ typedef void (*pmix_ptl_finalize_fn_t)(void); /* (ONE-WAY) register a persistent recv */ typedef pmix_status_t (*pmix_ptl_recv_fn_t)(struct pmix_peer_t *peer, pmix_ptl_cbfunc_t cbfunc, pmix_ptl_tag_t tag); /* Cancel a persistent recv */ typedef pmix_status_t (*pmix_ptl_cancel_fn_t)(struct pmix_peer_t *peer, pmix_ptl_tag_t tag); /* connect to a peer - this is a blocking function * to establish a connection to a peer*/ typedef pmix_status_t (*pmix_ptl_connect_to_peer_fn_t)(struct pmix_peer_t *peer, pmix_info_t info[], size_t ninfo, char **suri); /* query available servers on the local node */ typedef void (*pmix_ptl_query_servers_fn_t)(char *dirname, pmix_list_t *servers); /* define an API for establishing a * communication rendezvous point for local procs. The active component * is given an opportunity to register a listener with the * PTL base */ typedef pmix_status_t (*pmix_ptl_setup_listener_fn_t)(pmix_info_t info[], size_t ninfo); /* define an API for obtaining any envars that are to * be passed to client procs upon fork */ typedef pmix_status_t (*pmix_ptl_setup_fork_fn_t)(const pmix_proc_t *proc, char ***env); /** * Base structure for a PTL module */ struct pmix_ptl_module_t { char *name; pmix_ptl_init_fn_t init; pmix_ptl_finalize_fn_t finalize; pmix_ptl_recv_fn_t recv; pmix_ptl_cancel_fn_t cancel; pmix_ptl_connect_to_peer_fn_t connect_to_peer; pmix_ptl_query_servers_fn_t query_servers; pmix_ptl_setup_listener_fn_t setup_listener; pmix_ptl_setup_fork_fn_t setup_fork; }; typedef struct pmix_ptl_module_t pmix_ptl_module_t; /***** MACROS FOR EXECUTING PTL FUNCTIONS *****/ /* (TWO-WAY) send a message to the peer, and get a response delivered * to the specified callback function. The buffer will be free'd * at the completion of the send, and the cbfunc will be called * when the corresponding reply is received */ #define PMIX_PTL_SEND_RECV(r, p, b, c, d) \ do { \ pmix_ptl_sr_t *ms; \ pmix_peer_t *pr = (pmix_peer_t *) (p); \ if ((p)->finalized) { \ (r) = PMIX_ERR_UNREACH; \ } else { \ ms = PMIX_NEW(pmix_ptl_sr_t); \ PMIX_RETAIN(pr); \ ms->peer = pr; \ ms->bfr = (b); \ ms->cbfunc = (c); \ ms->cbdata = (d); \ PMIX_THREADSHIFT(ms, pmix_ptl_base_send_recv); \ (r) = PMIX_SUCCESS; \ } \ } while (0) /* (ONE-WAY) send a message to the peer. The buffer will be free'd * at the completion of the send */ #define PMIX_PTL_SEND_ONEWAY(r, p, b, t) \ do { \ pmix_ptl_queue_t *q; \ pmix_peer_t *pr = (pmix_peer_t *) (p); \ if ((p)->finalized) { \ (r) = PMIX_ERR_UNREACH; \ } else { \ q = PMIX_NEW(pmix_ptl_queue_t); \ PMIX_RETAIN(pr); \ q->peer = pr; \ q->buf = (b); \ q->tag = (t); \ PMIX_THREADSHIFT(q, pmix_ptl_base_send); \ (r) = PMIX_SUCCESS; \ } \ } while (0) /* expose functions used by the macros */ PMIX_EXPORT extern void pmix_ptl_base_send(int sd, short args, void *cbdata); PMIX_EXPORT extern void pmix_ptl_base_send_recv(int sd, short args, void *cbdata); PMIX_EXPORT extern void pmix_ptl_base_register_recv(int sd, short args, void *cbdata); /**** COMPONENT STRUCTURE DEFINITION ****/ /* * the standard component data structure */ struct pmix_ptl_base_component_t { pmix_mca_base_component_t base; int priority; char *uri; }; typedef struct pmix_ptl_base_component_t pmix_ptl_base_component_t; /* export the PTL module struct */ PMIX_EXPORT extern pmix_ptl_module_t pmix_ptl; /* * Macro for use in components that are of type ptl */ #define PMIX_PTL_BASE_VERSION_2_0_0 PMIX_MCA_BASE_VERSION_1_0_0("ptl", 2, 0, 0) END_C_DECLS #endif /* PMIX_PTL_H */ pmix-6.1.1~rc2/src/mca/ptl/tool/0000775000175000017500000000000015203536752016600 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/ptl/tool/ptl_tool.h0000664000175000017500000000247015203536752020610 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2018 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PTL_TOOL_H #define PMIX_PTL_TOOL_H #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_NETDB_H # include #endif #include "src/mca/ptl/ptl.h" BEGIN_C_DECLS extern pmix_ptl_base_component_t pmix_mca_ptl_tool_component; extern pmix_ptl_module_t pmix_ptl_tool_module; END_C_DECLS #endif /* PMIX_PTL_TOOL_H */ pmix-6.1.1~rc2/src/mca/ptl/tool/ptl_tool.c0000664000175000017500000000521715203536752020605 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2018 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_show_help.h" #include "ptl_tool.h" #include "src/mca/ptl/base/base.h" static pmix_status_t setup_listener(pmix_info_t info[], size_t ninfo); pmix_ptl_module_t pmix_ptl_tool_module = { .name = "tool", .connect_to_peer = pmix_ptl_base_connect_to_peer, .setup_fork = pmix_ptl_base_setup_fork, .setup_listener = setup_listener }; static pmix_status_t setup_listener(pmix_info_t info[], size_t ninfo) { pmix_status_t rc; char **clnup = NULL, *cptr = NULL; pmix_info_t dir; rc = pmix_ptl_base_setup_listener(info, ninfo); if (PMIX_SUCCESS != rc) { return rc; } /* if we are connected, then register any rendezvous files for cleanup */ if (pmix_atomic_check_bool(&pmix_globals.connected)) { if (NULL != pmix_ptl_base.nspace_filename) { PMIx_Argv_append_nosize(&clnup, pmix_ptl_base.nspace_filename); } if (NULL != pmix_ptl_base.session_filename) { PMIx_Argv_append_nosize(&clnup, pmix_ptl_base.session_filename); } if (NULL != clnup) { cptr = PMIx_Argv_join(clnup, ','); PMIx_Argv_free(clnup); PMIX_INFO_LOAD(&dir, PMIX_REGISTER_CLEANUP, cptr, PMIX_STRING); free(cptr); PMIx_Job_control_nb(&pmix_globals.myid, 1, &dir, 1, NULL, NULL); PMIX_INFO_DESTRUCT(&dir); } } return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/ptl/tool/Makefile.am0000664000175000017500000000341715203536752020641 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = ptl_tool.h sources = \ ptl_tool_component.c \ ptl_tool.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_ptl_tool_DSO lib = lib_sources = component = pmix_mca_ptl_tool.la component_sources = $(headers) $(sources) else lib = libpmix_mca_ptl_tool.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_ptl_tool_la_SOURCES = $(component_sources) pmix_mca_ptl_tool_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_ptl_tool_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_ptl_tool_la_SOURCES = $(lib_sources) libpmix_mca_ptl_tool_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/ptl/tool/ptl_tool_component.c0000664000175000017500000000575515203536752022676 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennptlee and The University * of Tennptlee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2017-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 IBM Corporation. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/mca/ptl/base/base.h" #include "src/mca/ptl/tool/ptl_tool.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" static int component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ PMIX_EXPORT pmix_ptl_base_component_t pmix_mca_ptl_tool_component = { .base = { PMIX_PTL_BASE_VERSION_2_0_0, /* Component name and version */ .pmix_mca_component_name = "tool", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_query_component = component_query }, .priority = 40, .uri = NULL }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, ptl, tool) static int component_query(pmix_mca_base_module_t **module, int *priority) { /* if I am not a tool, then look elsewhere */ if (!PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { *module = NULL; *priority = 0; return PMIX_ERR_TAKE_NEXT_OPTION; } *module = (pmix_mca_base_module_t *) &pmix_ptl_tool_module; *priority = pmix_mca_ptl_tool_component.priority; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/ptl/server/0000775000175000017500000000000015203536752017131 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/ptl/server/ptl_server.h0000664000175000017500000000223115203536752021465 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2018 IBM Corporation. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PTL_SERVER_H #define PMIX_PTL_SERVER_H #include "src/mca/ptl/ptl.h" BEGIN_C_DECLS extern pmix_ptl_base_component_t pmix_mca_ptl_server_component; extern pmix_ptl_module_t pmix_ptl_server_module; END_C_DECLS #endif /* PMIX_PTL_SERVER_H */ pmix-6.1.1~rc2/src/mca/ptl/server/ptl_server.c0000664000175000017500000000304115203536752021460 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2018 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_show_help.h" #include "ptl_server.h" #include "src/mca/ptl/base/base.h" pmix_ptl_module_t pmix_ptl_server_module = { .name = "server", .connect_to_peer = pmix_ptl_base_connect_to_peer, .setup_fork = pmix_ptl_base_setup_fork, .setup_listener = pmix_ptl_base_setup_listener }; pmix-6.1.1~rc2/src/mca/ptl/server/ptl_server_component.c0000664000175000017500000000601015203536752023541 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennptlee and The University * of Tennptlee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2017-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 IBM Corporation. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/mca/ptl/ptl.h" #include "src/mca/ptl/server/ptl_server.h" #include "src/util/pmix_error.h" static int component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ PMIX_EXPORT pmix_ptl_base_component_t pmix_mca_ptl_server_component = { .base = { PMIX_PTL_BASE_VERSION_2_0_0, /* Component name and version */ .pmix_mca_component_name = "server", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_query_component = component_query }, .priority = 30, .uri = NULL, }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, ptl, server) static int component_query(pmix_mca_base_module_t **module, int *priority) { /* if I am a server and not a tool, then take me */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { *module = (pmix_mca_base_module_t *) &pmix_ptl_server_module; *priority = pmix_mca_ptl_server_component.priority; return PMIX_SUCCESS; } *module = NULL; *priority = -1; return PMIX_ERR_TAKE_NEXT_OPTION; } pmix-6.1.1~rc2/src/mca/ptl/server/Makefile.am0000664000175000017500000000344515203536752021173 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = ptl_server.h sources = \ ptl_server_component.c \ ptl_server.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_ptl_server_DSO lib = lib_sources = component = pmix_mca_ptl_server.la component_sources = $(headers) $(sources) else lib = libpmix_mca_ptl_server.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_ptl_server_la_SOURCES = $(component_sources) pmix_mca_ptl_server_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_ptl_server_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_ptl_server_la_SOURCES = $(lib_sources) libpmix_mca_ptl_server_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/ptl/base/0000775000175000017500000000000015203536752016535 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/ptl/base/help-ptl-base.txt0000664000175000017500000000764715203536752021751 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2006 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2006 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2014-2020 Intel, Inc. All rights reserved. # Copyright (c) 2015-2020 Cisco Systems, Inc. All rights reserved # Copyright (c) 2021-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # [include-exclude] Both TCP interface include and exclude lists were specified: Include: %s Exclude: %s Only one of these can be given. # [not-parseable] The specified network is not parseable. Since we cannot determine your desired intent, we cannot establish a TCP socket for PMIx communications and will therefore abort. Please correct the network specification and retry. # [invalid if_inexclude] WARNING: An invalid value was given for pmix_ptl_base_if_%s. This value will be ignored. Local host: %s Value: %s Message: %s # [accept failed] WARNING: The accept(3) system call failed on a TCP socket. While this should generally never happen on a well-configured HPC system, the most common causes when it does occur are: * The process ran out of file descriptors * The operating system ran out of file descriptors * The operating system ran out of memory Your job may hang until the failure reason is fixed (e.g., more file descriptors and/or memory becomes available), and may eventually timeout / abort. Local host: %s Errno: %d (%s) Probable cause: %s # [too-many-conns] PMIx has found multiple possible servers to which it could connect. Further guidance is required to ensure the connection is made to a desirable server. Guidance can be in the form of the namespace or PID of a specific server, a directive to connect to a system server, a specific URI to use, or the name of a rendezvous file. Some connection handles have been read from files named pmix.* in subdirectories of $TMPDIR; delete them if they are stale. # [file-not-found] There was an error when attempting to access the specified server rendezvous file: Filename: %s Error: %s Please correct the error and try again. # [mismatch-id] The %s ID of the client process does not match the ID registered by the host runtime: Process: %u Registered: %u This could be a security issue. Please check the situation and try again. # [no-remote-interfaces] You requested support for remote tool connections, but no non-loopback interfaces were found after applying any include or exclude directives: Include: %s Exclude: %s Available: %s Please adjust your include or exclude to allow selection of a non-loopback interface. # [no-loopback-interfaces] You requested support for only local tool connections, but no loopback interfaces were found after applying any include or exclude directives: Include: %s Exclude: %s Available: %s Please adjust your include or exclude to allow selection of a loopback interface. # [no-available-interfaces] You requested support for tool connections, but no available interfaces were found after applying any include or exclude directives: Include: %s Exclude: %s Available: %s Please adjust your include or exclude to allow selection of an available interface. # [unexpected-message] The PMIx messaging system has received an unexpected message: Peer: %s Tag: %u The message cannot be processed and will be ignored. Please report this error to the PMIx developers. pmix-6.1.1~rc2/src/mca/ptl/base/ptl_base_connect.c0000664000175000017500000010321515203536752022205 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "include/pmix_stdint.h" #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_DIRENT_H # include #endif #if OAC_HAVE_APPLE && defined(HAVE_SYS_SYSCTL_H) # include #endif #include "src/client/pmix_client_ops.h" #include "src/common/pmix_attributes.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/gds.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_getid.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "src/util/pmix_strnlen.h" #include "src/mca/ptl/base/base.h" pmix_status_t pmix_ptl_base_set_nonblocking(int sd) { int flags; /* setup the socket as non-blocking */ if ((flags = fcntl(sd, F_GETFL, 0)) < 0) { pmix_output(0, "ptl:base:set_nonblocking: fcntl(F_GETFL) failed: %s (%d)\n", strerror(pmix_socket_errno), pmix_socket_errno); } else { flags |= O_NONBLOCK; if (fcntl(sd, F_SETFL, flags) < 0) pmix_output(0, "ptl:base:set_nonblocking: fcntl(F_SETFL) failed: %s (%d)\n", strerror(pmix_socket_errno), pmix_socket_errno); } return PMIX_SUCCESS; } pmix_status_t pmix_ptl_base_set_blocking(int sd) { int flags; /* setup the socket as non-blocking */ if ((flags = fcntl(sd, F_GETFL, 0)) < 0) { pmix_output(0, "ptl:base:set_blocking: fcntl(F_GETFL) failed: %s (%d)\n", strerror(pmix_socket_errno), pmix_socket_errno); } else { flags &= ~(O_NONBLOCK); if (fcntl(sd, F_SETFL, flags) < 0) pmix_output(0, "ptl:base:set_blocking: fcntl(F_SETFL) failed: %s (%d)\n", strerror(pmix_socket_errno), pmix_socket_errno); } return PMIX_SUCCESS; } /* * A blocking send on a non-blocking socket. Used to send the small amount of connection * information that identifies the peers endpoint. */ pmix_status_t pmix_ptl_base_send_blocking(int sd, char *ptr, size_t size) { size_t cnt = 0; int retval; pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "send blocking of %" PRIsize_t " bytes to socket %d", size, sd); while (cnt < size) { retval = send(sd, (char *) ptr + cnt, size - cnt, 0); if (retval < 0) { if (EAGAIN == pmix_socket_errno || EWOULDBLOCK == pmix_socket_errno) { /* just cycle and let it try again */ pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "blocking_send received error %d:%s from remote - cycling", pmix_socket_errno, strerror(pmix_socket_errno)); continue; } if (pmix_socket_errno != EINTR) { pmix_output_verbose( 8, pmix_ptl_base_framework.framework_output, "ptl:base:peer_send_blocking: send() to socket %d failed: %s (%d)\n", sd, strerror(pmix_socket_errno), pmix_socket_errno); return PMIX_ERR_UNREACH; } continue; } cnt += retval; } pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "blocking send complete to socket %d", sd); return PMIX_SUCCESS; } /* * A blocking recv on a non-blocking socket. Used to receive the small amount of connection * information that identifies the peers endpoint. */ pmix_status_t pmix_ptl_base_recv_blocking(int sd, char *data, size_t size) { size_t cnt = 0; pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "waiting for blocking recv of %" PRIsize_t " bytes", size); while (cnt < size) { int retval = recv(sd, (char *) data + cnt, size - cnt, MSG_WAITALL); /* remote closed connection */ if (retval == 0) { pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "ptl:base:recv_blocking: remote closed connection"); return PMIX_ERR_UNREACH; } /* handle errors */ if (retval < 0) { if (EAGAIN == pmix_socket_errno || EWOULDBLOCK == pmix_socket_errno) { /* just cycle and let it try again */ pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "blocking_recv received error %d:%s from remote - cycling", pmix_socket_errno, strerror(pmix_socket_errno)); continue; } if (pmix_socket_errno != EINTR) { /* If we overflow the listen backlog, it's possible that even though we finished the three way handshake, the remote host was unable to transition the connection from half connected (received the initial SYN) to fully connected (in the listen backlog). We likely won't see the failure until we try to receive, due to timing and the like. The first thing we'll get in that case is a RST packet, which receive will turn into a connection reset by peer errno. In that case, leave the socket in CONNECT_ACK and propagate the error up to recv_connect_ack, who will try to establish the connection again */ pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "blocking_recv received error %d:%s from remote - aborting", pmix_socket_errno, strerror(pmix_socket_errno)); return PMIX_ERR_UNREACH; } continue; } cnt += retval; } pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "blocking receive complete from remote"); return PMIX_SUCCESS; } #define PMIX_MAX_RETRIES 10 pmix_status_t pmix_ptl_base_connect(struct sockaddr_storage *addr, pmix_socklen_t addrlen, int *fd) { int sd = -1, sd2; int retries = -1; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl_base_connect: attempting to connect to server"); /* Create the new socket */ sd = socket(addr->ss_family, SOCK_STREAM, 0); while (retries < PMIX_MAX_RETRIES) { retries++; if (sd < 0) { pmix_output(0, "pmix:create_socket: socket() failed: %s (%d)\n", strerror(pmix_socket_errno), pmix_socket_errno); sd = socket(addr->ss_family, SOCK_STREAM, 0); continue; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix_ptl_base_connect: attempting to connect to server on socket %d", sd); /* try to connect */ if (connect(sd, (struct sockaddr *) addr, addrlen) < 0) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "Connect failed: %s (%d)", strerror(pmix_socket_errno), pmix_socket_errno); /* get a different socket, but do that BEFORE we release the current * one so we don't just get the same socket handed back to us */ sd2 = socket(addr->ss_family, SOCK_STREAM, 0); CLOSE_THE_SOCKET(sd); sd = sd2; continue; } else { /* otherwise, the connect succeeded - so break out of the loop */ break; } } if (retries == PMIX_MAX_RETRIES || sd < 0) { /* We were unsuccessful in establishing this connection, and are * not likely to suddenly become successful */ if (0 <= sd) { CLOSE_THE_SOCKET(sd); } return PMIX_ERR_UNREACH; } *fd = sd; return PMIX_SUCCESS; } char *pmix_ptl_base_get_cmd_line(void) { char *p = NULL; #if OAC_HAVE_APPLE int mib[3], argmax, nargs, num; size_t size; char *procargs = NULL, *cp, *cptr; char **stack = NULL; /* Get the maximum process arguments size. */ mib[0] = CTL_KERN; mib[1] = KERN_ARGMAX; size = sizeof(argmax); if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) { fprintf(stderr, "sysctl() argmax failed\n"); return NULL; } /* Allocate space for the arguments. */ procargs = (char *) malloc(argmax); if (procargs == NULL) { return NULL; } /* Make a sysctl() call to get the raw argument space of the process. */ mib[0] = CTL_KERN; mib[1] = KERN_PROCARGS2; mib[2] = getpid(); size = (size_t) argmax; if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) { fprintf(stderr, "Lacked permissions\n"); ; free(procargs); return NULL; } memcpy(&nargs, procargs, sizeof(nargs)); /* this points to the executable - skip over that to get the rest */ cp = procargs + sizeof(nargs); cp += strlen(cp); /* this is the first argv */ PMIx_Argv_append_nosize(&stack, cp); /* skip any embedded NULLs */ while (cp < &procargs[size] && '\0' == *cp) { ++cp; } if (cp != &procargs[size]) { /* from this point, we have the argv separated by NULLs - split them out */ cptr = cp; num = 0; while (cp < &procargs[size] && num < nargs) { if ('\0' == *cp) { PMIx_Argv_append_nosize(&stack, cptr); ++cp; // skip over the NULL cptr = cp; ++num; } else { ++cp; } } } p = PMIx_Argv_join(stack, ' '); PMIx_Argv_free(stack); free(procargs); #else char tmp[512]; FILE *fp; pid_t mypid; /* open the pid's info file */ mypid = getpid(); pmix_snprintf(tmp, 512, "/proc/%lu/cmdline", (unsigned long) mypid); fp = fopen(tmp, "r"); if (NULL != fp) { /* read the cmd line */ if (NULL == fgets(tmp, 512, fp)) { fclose(fp); return NULL; } if (0 != fclose(fp)) { ; } p = strdup(tmp); } #endif return p; } static pmix_status_t check_connections(pmix_list_t *connections) { size_t len; pmix_connection_t *cn, *cnbase; len = pmix_list_get_size(connections); if (0 == len) { return PMIX_ERR_NOT_FOUND; } if (1 == len) { return PMIX_SUCCESS; } /* check to see if all the connections are to the same target */ cnbase = (pmix_connection_t *) pmix_list_get_first(connections); PMIX_LIST_FOREACH (cn, connections, pmix_connection_t) { if (cn == cnbase) { continue; } if (0 != strcmp(cn->uri, cnbase->uri)) { // contains nspace and rank plus port pmix_show_help("help-ptl-base.txt", "too-many-conns", true); return PMIX_ERR_UNREACH; } } /* they are all to the same server */ return PMIX_SUCCESS; } static pmix_status_t tryfile(pmix_peer_t *peer, char **nspace, pmix_rank_t *rank, char **suri, bool optional, char *filename) { pmix_list_t connections; pmix_status_t rc; pmix_connection_t *cn; /* try to read the file */ PMIX_CONSTRUCT(&connections, pmix_list_t); rc = pmix_ptl_base_parse_uri_file(filename, optional, &connections); if (PMIX_SUCCESS == rc) { rc = check_connections(&connections); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&connections); return rc; } cn = (pmix_connection_t *) pmix_list_get_first(&connections); *nspace = cn->nspace; cn->nspace = NULL; *rank = cn->rank; *suri = cn->uri; cn->uri = NULL; peer->protocol = PMIX_PROTOCOL_V2; PMIX_SET_PEER_VERSION(peer, cn->version, 2, 0); } PMIX_LIST_DESTRUCT(&connections); return rc; } static pmix_status_t trysearch(pmix_peer_t *peer, char **nspace, pmix_rank_t *rank, char **suri, char *filename, pmix_info_t *iptr, size_t niptr, bool optional) { pmix_list_t connections; pmix_status_t rc; pmix_connection_t *cn; PMIX_CONSTRUCT(&connections, pmix_list_t); rc = pmix_ptl_base_df_search(pmix_ptl_base.system_tmpdir, filename, iptr, niptr, optional, &connections); if (PMIX_SUCCESS == rc) { rc = check_connections(&connections); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&connections); return rc; } cn = (pmix_connection_t *) pmix_list_get_first(&connections); peer->protocol = PMIX_PROTOCOL_V2; PMIX_SET_PEER_VERSION(peer, cn->version, 2, 0); *nspace = cn->nspace; cn->nspace = NULL; *rank = cn->rank; *suri = cn->uri; cn->uri = NULL; PMIX_LIST_DESTRUCT(&connections); return rc; } else if (1 < pmix_list_get_size(&connections)) { pmix_show_help("help-ptl-base.txt", "too-many-conns", true); } PMIX_LIST_DESTRUCT(&connections); return rc; } pmix_status_t pmix_ptl_base_connect_to_peer(struct pmix_peer_t *pr, pmix_info_t *info, size_t ninfo, char **suriout) { char *suri = NULL, *st, *evar; char *filename, *nspace = NULL; char **order = NULL; const char* tmp; pmix_rank_t rank = PMIX_RANK_WILDCARD; char *p = NULL, *server_nspace = NULL, *rendfile = NULL; int rc; size_t n, m; pid_t pid = 0; pmix_list_t ilist; pmix_info_caddy_t *kv; pmix_info_t *iptr = NULL, mypidinfo, mycmdlineinfo, launcher; pmix_info_t realuid, effectiveuid, realgid, effectivegid; size_t niptr = 0; pmix_peer_t *peer = (pmix_peer_t *) pr; bool optional = false; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:base: connecting to server"); /* check any provided directives * to see where they want us to connect to */ PMIX_CONSTRUCT(&ilist, pmix_list_t); *suriout = NULL; if (NULL != info) { for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECT_TO_SYSTEM)) { if (PMIX_INFO_TRUE(&info[n])) { if (NULL != order) { // overrides all prior specs PMIx_Argv_free(order); order = NULL; } PMIx_Argv_append_nosize(&order, PMIX_CONNECT_TO_SYSTEM); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECT_SYSTEM_FIRST)) { /* try the system-level */ if (PMIX_INFO_TRUE(&info[n])) { PMIx_Argv_prepend_nosize(&order, PMIX_CONNECT_SYSTEM_FIRST); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECT_TO_SCHEDULER)) { /* find the scheduler */ if (PMIX_INFO_TRUE(&info[n])) { PMIx_Argv_append_nosize(&order, PMIX_CONNECT_TO_SCHEDULER); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECT_TO_SYS_CONTROLLER)) { /* find the system controller */ if (PMIX_INFO_TRUE(&info[n])) { PMIx_Argv_append_nosize(&order, PMIX_CONNECT_TO_SYS_CONTROLLER); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECTION_ORDER)) { if (NULL != order) { // overrides all prior specs PMIx_Argv_free(order); order = NULL; } order = PMIx_Argv_split(info[n].value.data.string, ','); // the strings will just be the name of the attribute, so we // must convert them to the attribute values for (m=0; NULL != order[m]; m++) { tmp = pmix_attributes_lookup(order[m]); free(order[m]); order[m] = strdup(tmp); } } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_PIDINFO)) { pid = info[n].value.data.pid; } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_NSPACE)) { // if this is my nspace, then ignore it if (0 == strcmp(pmix_globals.myid.nspace, info[n].value.data.string)) { continue; } if (NULL != server_nspace) { /* they included it more than once */ if (0 == strcmp(server_nspace, info[n].value.data.string)) { /* same value, so ignore it */ continue; } /* otherwise, we don't know which one to use */ if (NULL != server_nspace) { free(server_nspace); } if (NULL != rendfile) { free(rendfile); } PMIx_Argv_free(order); PMIX_LIST_DESTRUCT(&ilist); return PMIX_ERR_BAD_PARAM; } server_nspace = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_TOOL_ATTACHMENT_FILE)) { if (NULL != rendfile) { free(rendfile); } rendfile = strdup(info[n].value.data.string); } else if (PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) && PMIX_CHECK_KEY(&info[n], PMIX_LAUNCHER_RENDEZVOUS_FILE)) { if (NULL != pmix_ptl_base.rendezvous_filename) { free(pmix_ptl_base.rendezvous_filename); } pmix_ptl_base.rendezvous_filename = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_TOOL_CONNECT_OPTIONAL)) { optional = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_TCP_URI) || PMIX_CHECK_KEY(&info[n], PMIX_SERVER_URI)) { if (NULL != pmix_ptl_base.uri) { free(pmix_ptl_base.uri); } pmix_ptl_base.uri = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_TMPDIR)) { if (NULL != pmix_ptl_base.session_tmpdir) { free(pmix_ptl_base.session_tmpdir); } pmix_ptl_base.session_tmpdir = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SYSTEM_TMPDIR)) { if (NULL != pmix_ptl_base.system_tmpdir) { free(pmix_ptl_base.system_tmpdir); } pmix_ptl_base.system_tmpdir = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECT_MAX_RETRIES)) { rc = PMIx_Value_get_number(&info[n].value, &pmix_ptl_base.max_retries, PMIX_INT); if (PMIX_SUCCESS != rc) { if (NULL != server_nspace) { free(server_nspace); } if (NULL != rendfile) { free(rendfile); } PMIx_Argv_free(order); PMIX_LIST_DESTRUCT(&ilist); return rc; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_CONNECT_RETRY_DELAY)) { rc = PMIx_Value_get_number(&info[n].value, &pmix_ptl_base.wait_to_connect, PMIX_INT); if (PMIX_SUCCESS != rc) { if (NULL != server_nspace) { free(server_nspace); } if (NULL != rendfile) { free(rendfile); } PMIx_Argv_free(order); PMIX_LIST_DESTRUCT(&ilist); return rc; } } else { /* need to pass this to server */ kv = PMIX_NEW(pmix_info_caddy_t); kv->info = &info[n]; pmix_list_append(&ilist, &kv->super); } } } /* add some info to the array - some of this is duplicative, but we * need to add it in the array because some peer cases failed to * include it, and we now need it for all cases */ /* add our pid to the array */ kv = PMIX_NEW(pmix_info_caddy_t); PMIX_INFO_LOAD(&mypidinfo, PMIX_PROC_PID, &pmix_globals.pid, PMIX_PID); kv->info = &mypidinfo; pmix_list_append(&ilist, &kv->super); /* add our real uid */ kv = PMIX_NEW(pmix_info_caddy_t); PMIX_INFO_LOAD(&realuid, PMIX_REALUID, &pmix_globals.realuid, PMIX_UINT32); kv->info = &realuid; pmix_list_append(&ilist, &kv->super); /* add our effective uid */ kv = PMIX_NEW(pmix_info_caddy_t); PMIX_INFO_LOAD(&effectiveuid, PMIX_USERID, &pmix_globals.uid, PMIX_UINT32); kv->info = &effectiveuid; pmix_list_append(&ilist, &kv->super); /* add our real gid */ kv = PMIX_NEW(pmix_info_caddy_t); PMIX_INFO_LOAD(&realgid, PMIX_REALGID, &pmix_globals.realgid, PMIX_UINT32); kv->info = &realgid; pmix_list_append(&ilist, &kv->super); /* add our effective gid */ kv = PMIX_NEW(pmix_info_caddy_t); PMIX_INFO_LOAD(&effectivegid, PMIX_GRPID, &pmix_globals.gid, PMIX_UINT32); kv->info = &effectivegid; pmix_list_append(&ilist, &kv->super); /* if I am a launcher, tell them so */ if (PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { kv = PMIX_NEW(pmix_info_caddy_t); PMIX_INFO_LOAD(&launcher, PMIX_LAUNCHER, NULL, PMIX_BOOL); kv->info = &launcher; pmix_list_append(&ilist, &kv->super); } /* if I am a system controller, tell them so */ if (PMIX_PEER_IS_SYS_CTRLR(pmix_globals.mypeer)) { kv = PMIX_NEW(pmix_info_caddy_t); PMIX_INFO_LOAD(&launcher, PMIX_SERVER_SYS_CONTROLLER, NULL, PMIX_BOOL); kv->info = &launcher; pmix_list_append(&ilist, &kv->super); } /* if I am a scheduler, tell them so */ if (PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { kv = PMIX_NEW(pmix_info_caddy_t); PMIX_INFO_LOAD(&launcher, PMIX_SERVER_SCHEDULER, NULL, PMIX_BOOL); kv->info = &launcher; pmix_list_append(&ilist, &kv->super); } /* add our cmd line to the array */ p = pmix_ptl_base_get_cmd_line(); if (NULL != p) { /* pass it along */ kv = PMIX_NEW(pmix_info_caddy_t); PMIX_INFO_LOAD(&mycmdlineinfo, PMIX_CMD_LINE, p, PMIX_STRING); kv->info = &mycmdlineinfo; pmix_list_append(&ilist, &kv->super); free(p); } /* if we need to pass anything, setup an array */ if (0 < (niptr = pmix_list_get_size(&ilist))) { PMIX_INFO_CREATE(iptr, niptr); n = 0; while (NULL != (kv = (pmix_info_caddy_t *) pmix_list_remove_first(&ilist))) { PMIX_INFO_XFER(&iptr[n], kv->info); PMIX_RELEASE(kv); ++n; } } PMIX_LIST_DESTRUCT(&ilist); /* mark that we are using the V2 protocol */ pmix_globals.mypeer->protocol = PMIX_PROTOCOL_V2; /* if we were given a URI, then look no further */ if (NULL != pmix_ptl_base.uri) { /* if the string starts with "file:", then they are pointing * us to a file we need to read to get the URI itself */ if (0 == strncmp(pmix_ptl_base.uri, "file:", 5)) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tool:tool getting connection info from %s", pmix_ptl_base.uri); rc = tryfile(peer, &nspace, &rank, &suri, optional, &pmix_ptl_base.uri[5]); if (PMIX_SUCCESS != rc) { goto cleanup; } goto complete; } else { st = strdup(pmix_ptl_base.uri); /* we need to extract the nspace/rank of the server from the string */ p = strchr(st, ';'); if (NULL == p) { free(st); rc = PMIX_ERR_BAD_PARAM; goto cleanup; } *p = '\0'; p++; suri = strdup(p); // save the uri portion /* the '.' in the first part of the original string separates * nspace from rank */ p = strchr(st, '.'); if (NULL == p) { free(st); rc = PMIX_ERR_BAD_PARAM; goto cleanup; } *p = '\0'; p++; nspace = strdup(st); rank = strtoull(p, NULL, 10); /* now update the URI */ free(st); } goto complete; } /* if they gave us a rendezvous file, use it */ if (NULL != rendfile) { rc = tryfile(peer, &nspace, &rank, &suri, optional, rendfile); if (PMIX_SUCCESS != rc && !optional) { /* since they gave us a specific rendfile and we couldn't * connect to it, return an error */ goto cleanup; } goto complete; } if (NULL != order) { // cycle thru the requested order for (n=0; NULL != order[n]; n++) { if (0 == strcmp(order[n], PMIX_CONNECT_SYSTEM_FIRST)) { if (0 > asprintf(&filename, "%s/pmix.sys.%s", pmix_ptl_base.system_tmpdir, pmix_globals.hostname)) { rc = PMIX_ERR_NOMEM; goto cleanup; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tool:tool looking for system server at %s", filename); // this is always optional as we are going to fallback to non-system servers rc = tryfile(peer, &nspace, &rank, &suri, true, filename); free(filename); if (PMIX_SUCCESS == rc) { PMIX_SET_PEER_TYPE(peer, PMIX_PROC_SERVER); goto complete; } } else if (0 == strcmp(order[n], PMIX_CONNECT_TO_SYSTEM)) { if (0 > asprintf(&filename, "%s/pmix.sys.%s", pmix_ptl_base.system_tmpdir, pmix_globals.hostname)) { rc = PMIX_ERR_NOMEM; goto cleanup; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tool:tool looking for system server at %s", filename); rc = tryfile(peer, &nspace, &rank, &suri, optional, filename); free(filename); if (PMIX_SUCCESS == rc) { PMIX_SET_PEER_TYPE(peer, PMIX_PROC_SERVER); goto complete; } if (!optional) { // not optional, so report error goto cleanup; } } else if (0 == strcmp(order[n], PMIX_CONNECT_TO_SCHEDULER)) { if (0 > asprintf(&filename, "%s/pmix.sched.%s", pmix_ptl_base.system_tmpdir, pmix_globals.hostname)) { rc = PMIX_ERR_NOMEM; goto cleanup; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tool:tool looking for scheduler at %s", filename); rc = tryfile(peer, &nspace, &rank, &suri, optional, filename); free(filename); if (PMIX_SUCCESS == rc) { PMIX_SET_PEER_TYPE(peer, PMIX_PROC_SCHEDULER); goto complete; } if (!optional) { // not optional, so report error goto cleanup; } } else if (0 == strcmp(order[n], PMIX_CONNECT_TO_SYS_CONTROLLER)) { if (0 > asprintf(&filename, "%s/pmix.sysctrlr.%s", pmix_ptl_base.system_tmpdir, pmix_globals.hostname)) { rc = PMIX_ERR_NOMEM; goto cleanup; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tool:tool looking for system controller at %s", filename); rc = tryfile(peer, &nspace, &rank, &suri, optional, filename); free(filename); if (PMIX_SUCCESS == rc) { PMIX_SET_PEER_TYPE(peer, PMIX_PROC_SYS_CTRLR); goto complete; } if (!optional) { // not optional, so report error goto cleanup; } } } } /* if they gave us a pid, then look for it */ if (0 != pid) { if (0 > asprintf(&filename, "pmix.%s.tool.%d", pmix_globals.hostname, pid)) { rc = PMIX_ERR_NOMEM; goto cleanup; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tool:tool searching for given session server %s", filename); rc = trysearch(peer, &nspace, &rank, &suri, filename, iptr, niptr, optional); free(filename); if (PMIX_SUCCESS != rc) { /* since they gave us a specific pid and we couldn't * connect to it, return an error */ goto cleanup; } PMIX_SET_PEER_TYPE(peer, PMIX_PROC_SERVER); goto complete; } /* if they gave us an nspace, then look for it */ if (NULL != server_nspace) { if (0 > asprintf(&filename, "pmix.%s.tool.%s", pmix_globals.hostname, server_nspace)) { rc = PMIX_ERR_NOMEM; goto cleanup; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tool:tool searching for given nspace server %s", filename); rc = trysearch(peer, &nspace, &rank, &suri, filename, iptr, niptr, optional); free(filename); if (PMIX_SUCCESS != rc) { /* since they gave us a specific nspace and we couldn't * connect to it, return an error */ goto cleanup; } PMIX_SET_PEER_TYPE(peer, PMIX_PROC_SERVER); goto complete; } /* see if we are a client of some server */ evar = NULL; rc = pmix_ptl_base_set_peer(peer, &evar); if (PMIX_SUCCESS == rc) { PMIX_SET_PEER_TYPE(pmix_globals.mypeer, PMIX_PROC_CLIENT_TOOL); rc = pmix_ptl_base_parse_uri(evar, &nspace, &rank, &suri); if (PMIX_SUCCESS != rc) { goto cleanup; } goto complete; } else if (!PMIX_PEER_IS_SERVER(pmix_globals.mypeer) || PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { /* we aren't a client, so we will search to see what session-level * tools are available to this user. We will take the first connection * that succeeds - this is based on the likelihood that there is only * one session per user on a node */ if (0 > asprintf(&filename, "pmix.%s.tool", pmix_globals.hostname)) { rc = PMIX_ERR_NOMEM; goto cleanup; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tool:tool searching for session server %s", filename); rc = trysearch(peer, &nspace, &rank, &suri, filename, iptr, niptr, optional); free(filename); if (PMIX_SUCCESS == rc) { PMIX_SET_PEER_TYPE(peer, PMIX_PROC_SERVER); goto complete; } if (!optional) { goto cleanup; } } rc = PMIX_ERR_UNREACH; goto cleanup; complete: rc = pmix_ptl_base_make_connection(peer, suri, iptr, niptr); if (PMIX_SUCCESS != rc) { goto cleanup; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "tool_peer_try_connect: Connection across to server succeeded"); pmix_ptl_base_complete_connection(peer, nspace, rank); cleanup: *suriout = suri; if (NULL != nspace) { free(nspace); } if (NULL != iptr) { PMIX_INFO_FREE(iptr, niptr); } if (NULL != rendfile) { free(rendfile); } if (NULL != server_nspace) { free(server_nspace); } return rc; } pmix-6.1.1~rc2/src/mca/ptl/base/ptl_base_select.c0000664000175000017500000000645615203536752022044 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/util/pmix_error.h" #include "src/util/pmix_show_help.h" #include "src/mca/ptl/base/base.h" /* Function for selecting a component * from all those that are available. */ int pmix_ptl_base_select(void) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_ptl_base_component_t *component = NULL; pmix_mca_base_module_t *mod; pmix_ptl_module_t *pmod; int rc, pri, best_pri = -1; ; bool inserted = false; if (pmix_ptl_base.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_ptl_base.selected = true; /* Query all available components and ask if they have a module */ PMIX_LIST_FOREACH (cli, &pmix_ptl_base_framework.framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_ptl_base_component_t *) cli->cli_component; pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "mca:ptl:select: checking available component %s", component->base.pmix_mca_component_name); /* get the module for this component */ rc = component->base.pmix_mca_query_component(&mod, &pri); if (PMIX_SUCCESS != rc || NULL == mod) { continue; } /* If we got a module, try to initialize it */ pmod = (pmix_ptl_module_t *) mod; if (NULL != pmod->init && PMIX_SUCCESS != pmod->init()) { continue; } /* keep only the highest priority module */ if (best_pri < pri) { best_pri = pri; /* give any prior module a chance to finalize */ if (NULL != pmix_ptl.finalize) { pmix_ptl.finalize(); } pmix_ptl = *pmod; inserted = true; } } /* if no modules were found, then that's an error as we require at least one */ if (!inserted) { pmix_show_help("help-pmix-runtime.txt", "no-plugins", true, "PTL"); return PMIX_ERR_SILENT; } pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "mca:ptl:select: using component %s", pmix_ptl.name); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/ptl/base/ptl_base_listener.c0000664000175000017500000010756215203536752022412 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include #include #include #include "src/class/pmix_list.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_error.h" #include "src/util/pmix_fd.h" #include "src/util/pmix_net.h" #include "src/util/pmix_os_dirpath.h" #include "src/util/pmix_output.h" #include "src/util/pmix_if.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_parse_options.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "src/mca/ptl/base/base.h" // local connection handler static void connection_event_handler(int incoming_sd, short flags, void *cbdata); // local value for connection support static bool setup_complete = false; /* * start listening event */ pmix_status_t pmix_ptl_base_start_listening(pmix_info_t info[], size_t ninfo) { pmix_status_t rc; /* setup the listener */ if (!setup_complete) { rc = pmix_ptl.setup_listener(info, ninfo); if (PMIX_SUCCESS != rc) { return rc; } } setup_complete = true; pmix_event_set(pmix_globals.evbase, &pmix_ptl_base.listener.ev, pmix_ptl_base.listener.socket, PMIX_EV_READ|PMIX_EV_PERSIST, connection_event_handler, 0); pmix_ptl_base.listener.active = true; pmix_event_add(&pmix_ptl_base.listener.ev, 0); return PMIX_SUCCESS; } void pmix_ptl_base_stop_listening(void) { pmix_listener_t *lt = &pmix_ptl_base.listener; pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "listen_thread: shutdown"); if (!lt->active) { /* nothing we need do */ return; } /* mark it as inactive */ lt->active = false; pmix_event_del(<->ev); /* close the socket to remove the connection points */ CLOSE_THE_SOCKET(lt->socket); lt->socket = -1; } /* * Handler for accepting connections from the event library */ static void connection_event_handler(int incoming_sd, short flags, void *cbdata) { struct sockaddr addr; pmix_socklen_t addrlen = sizeof(struct sockaddr); int sd; pmix_pending_connection_t *pending_connection; pmix_listener_t *lt = &pmix_ptl_base.listener; PMIX_HIDE_UNUSED_PARAMS(flags, cbdata); sd = accept(incoming_sd, (struct sockaddr *) &addr, &addrlen); pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "connection_event_handler: working connection " "(%d, %d) %s:%d\n", sd, pmix_socket_errno, pmix_net_get_hostname((struct sockaddr *) &addr), pmix_net_get_port((struct sockaddr *) &addr)); if (sd < 0) { /* Non-fatal errors */ if (EINTR == pmix_socket_errno || EAGAIN == pmix_socket_errno || EWOULDBLOCK == pmix_socket_errno) { return; } /* If we run out of file descriptors, log an extra warning (so that the user can know to fix this problem) and abandon all hope. */ else if (EMFILE == pmix_socket_errno) { CLOSE_THE_SOCKET(incoming_sd); PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE); pmix_show_help("help-ptl-base.txt", "accept failed", true, pmix_globals.hostname, pmix_socket_errno, strerror(pmix_socket_errno), "Out of file descriptors"); return; } /* For all other cases, close the socket, print a warning but try to continue */ else { CLOSE_THE_SOCKET(incoming_sd); pmix_show_help("help-ptl-base.txt", "accept failed", true, pmix_globals.hostname, pmix_socket_errno, strerror(pmix_socket_errno), "Unknown cause; job will try to continue"); return; } } /* this descriptor is ready to be read, which means a connection * request has been received - so harvest it. All we want to do * here is accept the connection and push the info onto the event * library for subsequent processing - we don't want to actually * process the connection here as it takes too long, and so the * OS might start rejecting connections due to timeout. */ pending_connection = PMIX_NEW(pmix_pending_connection_t); pending_connection->protocol = lt->protocol; pmix_event_assign(&pending_connection->ev, pmix_globals.evbase, -1, EV_WRITE, lt->cbfunc, pending_connection); pending_connection->sd = sd; pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "connection_event_handler: new connection: (%d, %d)", pending_connection->sd, pmix_socket_errno); /* post the object */ PMIX_POST_OBJECT(pending_connection); /* activate the event */ pmix_event_active(&pending_connection->ev, EV_WRITE, 1); } static pmix_status_t write_rndz_file(char *filename, char *uri, bool *dir_created, bool *file_created) { int fd; char *dirname, *tmp; time_t mytime; int rc; mode_t mode = 0; dirname = pmix_dirname(filename); if (NULL != dirname) { mode = S_IRWXU; if (pmix_ptl_base.allow_foreign_tools) { mode |= S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH; } rc = pmix_os_dirpath_create(dirname, mode); if (PMIX_ERR_SILENT == rc) { // error has already been reported return rc; } if (PMIX_SUCCESS != rc && PMIX_ERR_EXISTS != rc) { PMIX_ERROR_LOG(rc); free(dirname); return rc; } if (PMIX_SUCCESS == rc) { // do not change the dir_created flag if the directory // already exists as we don't know if we previously // created it or it already existed. Success is returned // when we were able to both create the directory // and change its mode as directed *dir_created = true; } free(dirname); } /* set the file mode */ mode = S_IRUSR | S_IWUSR ; if (pmix_ptl_base.allow_foreign_tools) { mode |= S_IRGRP | S_IROTH; } fd = open(filename, O_RDWR | O_CREAT | O_EXCL, mode); if (0 > fd) { if (EEXIST == errno) { // the file already exists *file_created = false; return PMIX_ERR_EXISTS; } pmix_output(0, "Impossible to open the file %s in write mode\n", filename); PMIX_ERROR_LOG(PMIX_ERR_FILE_OPEN_FAILURE); *file_created = false; return PMIX_ERR_FILE_OPEN_FAILURE; } /* output the information */ mytime = time(NULL); pmix_asprintf(&tmp, "%s\n%s\n%lu\n%lu:%lu\n%s\n", uri, PMIX_VERSION, (unsigned long)pmix_globals.pid, (unsigned long)pmix_globals.uid, (unsigned long)pmix_globals.gid, ctime(&mytime)); rc = write(fd, tmp, strlen(tmp)); if (0 > rc) { PMIX_ERROR_LOG(PMIX_ERR_FILE_WRITE_FAILURE); *file_created = false; pmix_free(tmp); close(fd); return PMIX_ERR_FILE_WRITE_FAILURE; } pmix_free(tmp); close(fd); *file_created = true; return PMIX_SUCCESS; } /* discover the available * interfaces, filter them thru any given directives, and select * the one we will listen on for connection requests. This will * be a loopback device by default, unless we are asked to support * tool connections - in that case, we will take a non-loopback * device by default, if one is available after filtering directives * * If we are a tool and were give a rendezvous file, then we first * check to see if it already exists. If it does, then this is the * connection info we are to use. If it doesn't, then this is the * name of the file we are to use to store our listener info. * * If we are a server and are given a rendezvous file, then that is * is the name of the file we are to use to store our listener info. */ pmix_status_t pmix_ptl_base_setup_listener(pmix_info_t info[], size_t ninfo) { int flags = 0; pmix_listener_t *lt; int i, rc = 0, saveindex = -1, savelpbk = -1; char **interfaces = NULL, **candidates = NULL, **ports; bool including = false; char name[32]; struct sockaddr_storage my_ss; int kindex; pmix_socklen_t addrlen; char *prefix; char myconnhost[PMIX_MAXHOSTNAMELEN] = {0}; int myport; pmix_kval_t *urikv; pid_t mypid; int outpipe; char *leftover; size_t n; FILE *fptst; uint16_t port = 0; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tool setup_listener"); for (n = 0; n < ninfo; n++) { if (0 == strcmp(info[n].key, PMIX_SERVER_SESSION_SUPPORT)) { pmix_ptl_base.session_tool = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_SYSTEM_SUPPORT)) { pmix_ptl_base.system_tool = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_ALLOW_FOREIGN_TOOLS)) { pmix_ptl_base.allow_foreign_tools = PMIX_INFO_TRUE(&info[n]); } else if (0 == strcmp(info[n].key, PMIX_SERVER_TOOL_SUPPORT)) { pmix_ptl_base.tool_support = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_REMOTE_CONNECTIONS)) { pmix_ptl_base.remote_connections = PMIX_INFO_TRUE(&info[n]); pmix_ptl_base.connections_specified = true; } else if (PMIX_CHECK_KEY(&info[n], PMIX_TCP_IF_INCLUDE)) { if (NULL != pmix_ptl_base.if_include) { free(pmix_ptl_base.if_include); } pmix_ptl_base.if_include = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_TCP_IF_EXCLUDE)) { if (NULL != pmix_ptl_base.if_exclude) { free(pmix_ptl_base.if_exclude); } pmix_ptl_base.if_exclude = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_TCP_IPV4_PORT)) { if (PMIX_INT == info[n].value.type) { if (NULL != pmix_ptl_base.ipv4_ports) { PMIx_Argv_free(pmix_ptl_base.ipv4_ports); } pmix_ptl_base.ipv4_ports = pmix_malloc(2*sizeof(char*)); pmix_ptl_base.ipv4_ports[1] = NULL; if (0 < info[n].value.data.integer) { pmix_asprintf(&pmix_ptl_base.ipv4_ports[0], "%d", info[n].value.data.integer); } else { pmix_ptl_base.ipv4_ports[0] = strdup("0"); } } else if (PMIX_STRING == info[n].value.type) { if (NULL != pmix_ptl_base.ipv4_ports) { PMIx_Argv_free(pmix_ptl_base.ipv4_ports); } if (NULL == info[n].value.data.string) { pmix_ptl_base.ipv4_ports = pmix_malloc(2*sizeof(char*)); pmix_ptl_base.ipv4_ports[0] = strdup("0"); pmix_ptl_base.ipv4_ports[1] = NULL; } else { pmix_util_parse_range_options(info[n].value.data.string, &pmix_ptl_base.ipv4_ports); if (0 == strcmp(pmix_ptl_base.ipv4_ports[0], "-1")) { PMIx_Argv_free(pmix_ptl_base.ipv4_ports); pmix_ptl_base.ipv4_ports = pmix_malloc(2*sizeof(char*)); pmix_ptl_base.ipv4_ports[0] = strdup("0"); pmix_ptl_base.ipv4_ports[1] = NULL; } } } #if PMIX_ENABLE_IPV6 } else if (PMIX_CHECK_KEY(&info[n], PMIX_TCP_IPV6_PORT)) { if (PMIX_INT == info[n].value.type) { if (NULL != pmix_ptl_base.ipv6_ports) { PMIx_Argv_free(pmix_ptl_base.ipv6_ports); pmix_ptl_base.ipv6_ports = NULL; } pmix_ptl_base.ipv6_ports = pmix_malloc(2*sizeof(char*)); pmix_ptl_base.ipv6_ports[1] = NULL; if (0 < info[n].value.data.integer) { pmix_asprintf(&pmix_ptl_base.ipv6_ports[0], "%d", info[n].value.data.integer); } else { pmix_ptl_base.ipv6_ports[0] = strdup("0"); } } else if (PMIX_STRING == info[n].value.type) { if (NULL != pmix_ptl_base.ipv6_ports) { PMIx_Argv_free(pmix_ptl_base.ipv6_ports); } if (NULL == info[n].value.data.string) { pmix_ptl_base.ipv6_ports = pmix_malloc(2*sizeof(char*)); pmix_ptl_base.ipv6_ports[0] = strdup("0"); pmix_ptl_base.ipv6_ports[1] = NULL; } else { pmix_util_parse_range_options(info[n].value.data.string, &pmix_ptl_base.ipv6_ports); if (0 == strcmp(pmix_ptl_base.ipv6_ports[0], "-1")) { PMIx_Argv_free(pmix_ptl_base.ipv6_ports); pmix_ptl_base.ipv6_ports = pmix_malloc(2*sizeof(char*)); pmix_ptl_base.ipv6_ports[0] = strdup("0"); pmix_ptl_base.ipv6_ports[1] = NULL; } } } #endif } else if (PMIX_CHECK_KEY(&info[n], PMIX_TCP_DISABLE_IPV4)) { pmix_ptl_base.disable_ipv4_family = PMIX_INFO_TRUE(&info[n]); #if PMIX_ENABLE_IPV6 } else if (PMIX_CHECK_KEY(&info[n], PMIX_TCP_DISABLE_IPV6)) { pmix_ptl_base.disable_ipv6_family = PMIX_INFO_TRUE(&info[n]); #endif } else if (PMIX_CHECK_KEY(&info[n], PMIX_TCP_REPORT_URI)) { if (NULL != pmix_ptl_base.report_uri) { free(pmix_ptl_base.report_uri); } pmix_ptl_base.report_uri = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_TMPDIR)) { if (NULL != pmix_ptl_base.session_tmpdir) { free(pmix_ptl_base.session_tmpdir); } pmix_ptl_base.session_tmpdir = strdup(info[n].value.data.string); } else if (PMIX_CHECK_KEY(&info[n], PMIX_SYSTEM_TMPDIR)) { if (NULL != pmix_ptl_base.system_tmpdir) { free(pmix_ptl_base.system_tmpdir); } pmix_ptl_base.system_tmpdir = strdup(info[n].value.data.string); } } if (NULL != pmix_ptl_base.if_include && NULL != pmix_ptl_base.if_exclude) { pmix_show_help("help-ptl-base.txt", "include-exclude", true, pmix_ptl_base.if_include, pmix_ptl_base.if_exclude); return PMIX_ERR_SILENT; } lt = &pmix_ptl_base.listener; /* if interface include was given, construct a list * of those interfaces which match the specifications - remember, * the includes could be given as named interfaces, IP addrs, or * subnet+mask */ if (NULL != pmix_ptl_base.if_include) { interfaces = pmix_ptl_base_split_and_resolve(pmix_ptl_base.if_include, "include"); including = true; } else if (NULL != pmix_ptl_base.if_exclude) { interfaces = pmix_ptl_base_split_and_resolve(pmix_ptl_base.if_exclude, "exclude"); including = false; } /* look at all available interfaces and pick one - we default to a * loopback interface if available, but otherwise pick the first * available interface since we are only talking locally */ for (i = pmix_ifbegin(); i >= 0; i = pmix_ifnext(i)) { if (PMIX_SUCCESS != pmix_ifindextoaddr(i, (struct sockaddr *) &my_ss, sizeof(my_ss))) { pmix_output(0, "ptl_tool: problems getting address for index %i (kernel index %i)\n", i, pmix_ifindextokindex(i)); continue; } /* ignore non-ip4/6 interfaces */ if (AF_INET != my_ss.ss_family && AF_INET6 != my_ss.ss_family) { continue; } /* get the name for diagnostic purposes */ pmix_ifindextoname(i, name, sizeof(name)); /* ignore any virtual interfaces */ if (0 == strncmp(name, "vir", 3)) { continue; } /* ignore any interfaces in a disabled family */ if (AF_INET == my_ss.ss_family) { if (pmix_ptl_base.disable_ipv4_family) { continue; } #if PMIX_ENABLE_IPV6 } else if (AF_INET6 == my_ss.ss_family) { if (pmix_ptl_base.disable_ipv6_family) { continue; } #endif } else { /* ignore any other type */ continue; } /* get the kernel index */ kindex = pmix_ifindextokindex(i); if (kindex <= 0) { continue; } // cache the candidates PMIx_Argv_append_nosize(&candidates, name); pmix_output_verbose(10, pmix_ptl_base_framework.framework_output, "WORKING INTERFACE %d KERNEL INDEX %d FAMILY: %s", i, kindex, (AF_INET == my_ss.ss_family) ? "V4" : "V6"); /* handle include/exclude directives */ if (NULL != interfaces) { /* check for match */ rc = pmix_ifmatches(kindex, interfaces); /* if one of the network specifications isn't parseable, then * error out as we can't do what was requested */ if (PMIX_ERR_FABRIC_NOT_PARSEABLE == rc) { pmix_show_help("help-ptl-base.txt", "not-parseable", true); PMIx_Argv_free(interfaces); PMIx_Argv_free(candidates); return PMIX_ERR_BAD_PARAM; } /* if we are including, then ignore this if not present */ if (including) { if (PMIX_SUCCESS != rc) { pmix_output_verbose( 10, pmix_ptl_base_framework.framework_output, "ptl:tool:init rejecting interface %s (not in include list)", name); continue; } } else { /* we are excluding, so ignore if present */ if (PMIX_SUCCESS == rc) { pmix_output_verbose(10, pmix_ptl_base_framework.framework_output, "ptl:tool:init rejecting interface %s (in exclude list)", name); continue; } } } /* if this is the loopback device and they didn't enable * remote connections, then we are done */ if (pmix_ifisloopback(i)) { pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "ptl:tool:init loopback interface %s found", name); if (savelpbk < 0) { savelpbk = i; } } else if (saveindex < 0) { saveindex = i; } if (0 <= savelpbk && 0 <= saveindex) { break; } } /* cleanup */ if (NULL != interfaces) { PMIx_Argv_free(interfaces); } // if they enabled remote connections, then we must have a public // interface available to us if (pmix_ptl_base.remote_connections) { if (saveindex < 0) { prefix = PMIx_Argv_join(candidates, ','); pmix_show_help("help-ptl-base.txt", "no-remote-interfaces", true, (NULL == pmix_ptl_base.if_include) ? "NULL" : pmix_ptl_base.if_include, (NULL == pmix_ptl_base.if_exclude) ? "NULL" : pmix_ptl_base.if_exclude, prefix); PMIx_Argv_free(candidates); free(prefix); return PMIX_ERR_SILENT; } // if we found a public interface, then just fall through and use it PMIx_Argv_free(candidates); } else { // if there are no loopback interfaces, and if they didn't specify // we shouldn't support remote connections, then take a public // interface if available if (savelpbk < 0) { if (!pmix_ptl_base.connections_specified) { // fallback to a public interface, if available if (saveindex < 0) { // didn't find anything! prefix = PMIx_Argv_join(candidates, ','); pmix_show_help("help-ptl-base.txt", "no-available-interfaces", true, (NULL == pmix_ptl_base.if_include) ? "NULL" : pmix_ptl_base.if_include, (NULL == pmix_ptl_base.if_exclude) ? "NULL" : pmix_ptl_base.if_exclude, prefix); PMIx_Argv_free(candidates); free(prefix); return PMIX_ERR_SILENT; } else { // go ahead and use the public interface PMIx_Argv_free(candidates); goto complete; } } else { // they said not to allow remote connections, so we cannot // take a public interface prefix = PMIx_Argv_join(candidates, ','); pmix_show_help("help-ptl-base.txt", "no-loopback-interfaces", true, (NULL == pmix_ptl_base.if_include) ? "NULL" : pmix_ptl_base.if_include, (NULL == pmix_ptl_base.if_exclude) ? "NULL" : pmix_ptl_base.if_exclude, prefix); PMIx_Argv_free(candidates); free(prefix); return PMIX_ERR_SILENT; } } else { // they didn't ask for remote support, and we found a loopback // interface, so use it saveindex = savelpbk; PMIx_Argv_free(candidates); } } complete: /* save the connection */ if (PMIX_SUCCESS != pmix_ifindextoaddr(saveindex, (struct sockaddr *) pmix_ptl_base.connection, sizeof(struct sockaddr))) { pmix_output(0, "ptl:base: problems getting address for kernel index %i\n", pmix_ifindextokindex(saveindex)); return PMIX_ERR_NOT_AVAILABLE; } // set the ports to scan based on the connection we selected if (AF_INET == pmix_ptl_base.connection->ss_family) { ports = pmix_ptl_base.ipv4_ports; #if PMIX_ENABLE_IPV6 } else if (AF_INET6 == pmix_ptl_base.connection->ss_family) { ports = pmix_ptl_base.ipv6_ports; #endif } else { /* unrecognized family type - shouldn't be possible as we only * included IPv4 and IPv6 interfaces, but this is needed to * silence warnings */ return PMIX_ERR_NOT_SUPPORTED; } for (n=0; NULL != ports[n]; n++) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:setup_listener - trying port %s", ports[n]); /* get the port number */ port = strtol(ports[n], NULL, 10); /* convert it to network-byte-order */ port = htons(port); /* set the port */ if (AF_INET == pmix_ptl_base.connection->ss_family) { ((struct sockaddr_in *) pmix_ptl_base.connection)->sin_port = port; addrlen = sizeof(struct sockaddr_in); if (0 != port) { flags = 1; } #if PMIX_ENABLE_IPV6 } else if (AF_INET6 == pmix_ptl_base.connection->ss_family) { ((struct sockaddr_in6 *) pmix_ptl_base.connection)->sin6_port = port; addrlen = sizeof(struct sockaddr_in6); if (0 != port) { flags = 1; } #endif } lt->varname = pmix_bfrops_base_get_components(); lt->protocol = PMIX_PROTOCOL_V2; lt->cbfunc = pmix_ptl_base_connection_handler; /* create a listen socket for incoming connection attempts */ lt->socket = socket(pmix_ptl_base.connection->ss_family, SOCK_STREAM, 0); if (lt->socket < 0) { printf("%s:%d socket() failed\n", __FILE__, __LINE__); goto sockerror; } /* set reusing ports flag */ if (setsockopt(lt->socket, SOL_SOCKET, SO_REUSEADDR, (const char *) &flags, sizeof(flags)) < 0) { pmix_output(0, "ptl:base:create_listen: unable to set the " "SO_REUSEADDR option (%s:%d)\n", strerror(pmix_socket_errno), pmix_socket_errno); goto sockerror; } /* Set the socket to close-on-exec so that no children inherit * this FD */ if (pmix_fd_set_cloexec(lt->socket) != PMIX_SUCCESS) { goto sockerror; } if (bind(lt->socket, (struct sockaddr *) pmix_ptl_base.connection, addrlen) < 0) { if ((EADDRINUSE == pmix_socket_errno) || (EADDRNOTAVAIL == pmix_socket_errno)) { continue; } printf("[%u] %s:%d bind() failed for socket %d storage size %u: %s\n", (unsigned) getpid(), __FILE__, __LINE__, lt->socket, (unsigned) addrlen, strerror(errno)); goto sockerror; } else { break; // got one that works } } /* resolve assigned port */ if (getsockname(lt->socket, (struct sockaddr *) pmix_ptl_base.connection, &addrlen) < 0) { pmix_output(0, "ptl:tool:create_listen: getsockname(): %s (%d)", strerror(pmix_socket_errno), pmix_socket_errno); goto sockerror; } /* setup listen backlog to maximum allowed by kernel */ if (listen(lt->socket, SOMAXCONN) < 0) { printf("%s:%d listen() failed\n", __FILE__, __LINE__); goto sockerror; } /* set socket up to be non-blocking, otherwise accept could block */ if ((flags = fcntl(lt->socket, F_GETFL, 0)) < 0) { printf("%s:%d fcntl(F_GETFL) failed\n", __FILE__, __LINE__); goto sockerror; } flags |= O_NONBLOCK; if (fcntl(lt->socket, F_SETFL, flags) < 0) { printf("%s:%d fcntl(F_SETFL) failed\n", __FILE__, __LINE__); goto sockerror; } if (AF_INET == pmix_ptl_base.connection->ss_family) { prefix = "tcp4://"; myport = ntohs(((struct sockaddr_in *) pmix_ptl_base.connection)->sin_port); inet_ntop(AF_INET, &((struct sockaddr_in *) pmix_ptl_base.connection)->sin_addr, myconnhost, PMIX_MAXHOSTNAMELEN - 1); } else if (AF_INET6 == pmix_ptl_base.connection->ss_family) { prefix = "tcp6://"; myport = ntohs(((struct sockaddr_in6 *) pmix_ptl_base.connection)->sin6_port); inet_ntop(AF_INET6, &((struct sockaddr_in6 *) pmix_ptl_base.connection)->sin6_addr, myconnhost, PMIX_MAXHOSTNAMELEN - 1); } else { goto sockerror; } rc = asprintf(<->uri, "%s.%u;%s%s:%d", pmix_globals.myid.nspace, pmix_globals.myid.rank, prefix, myconnhost, myport); if (0 > rc || NULL == lt->uri) { goto sockerror; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:base URI %s", lt->uri); /* save the URI internally so we can report it */ urikv = PMIX_NEW(pmix_kval_t); urikv->key = strdup(PMIX_MYSERVER_URI); PMIX_VALUE_CREATE(urikv->value, 1); PMIX_VALUE_LOAD(urikv->value, lt->uri, PMIX_STRING); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, urikv); PMIX_RELEASE(urikv); // maintain accounting /* save a legacy URI internally so we can report it * to older tools */ urikv = PMIX_NEW(pmix_kval_t); urikv->key = strdup(PMIX_SERVER_URI); PMIX_VALUE_CREATE(urikv->value, 1); PMIX_VALUE_LOAD(urikv->value, lt->uri, PMIX_STRING); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, urikv); PMIX_RELEASE(urikv); // maintain accounting if (NULL != pmix_ptl_base.report_uri) { /* if the string is a "-", then output to stdout */ if (0 == strcmp(pmix_ptl_base.report_uri, "-")) { fprintf(stdout, "%s\n", lt->uri); } else if (0 == strcmp(pmix_ptl_base.report_uri, "+")) { /* output to stderr */ fprintf(stderr, "%s\n", lt->uri); } else { /* see if it is an integer pipe */ leftover = NULL; outpipe = strtol(pmix_ptl_base.report_uri, &leftover, 10); if (NULL == leftover || 0 == strlen(leftover)) { /* stitch together the var names and URI */ pmix_asprintf(&leftover, "%s;%s", lt->varname, lt->uri); /* output to the pipe */ rc = pmix_fd_write(outpipe, strlen(leftover) + 1, leftover); free(leftover); close(outpipe); } else { /* must be a file */ FILE *fp; fp = fopen(pmix_ptl_base.report_uri, "w"); if (NULL == fp) { pmix_output(0, "Impossible to open the file %s in write mode\n", pmix_ptl_base.report_uri); PMIX_ERROR_LOG(PMIX_ERR_FILE_OPEN_FAILURE); goto sockerror; } /* output my nspace and rank plus the URI */ fprintf(fp, "%s\n", lt->uri); /* add a flag that indicates we accept v2.1 protocols */ fprintf(fp, "v%s\n", PMIX_VERSION); fclose(fp); pmix_ptl_base.created_urifile = true; } } } /* if we were given a rendezvous file, then drop it */ if (NULL != pmix_ptl_base.rendezvous_filename) { /* if we are a tool and the file already exists, then we * just use it as providing the rendezvous info for our * server */ if (PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { fptst = fopen(pmix_ptl_base.rendezvous_filename, "r"); if (NULL != fptst) { fclose(fptst); goto nextstep; } } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "WRITING RENDEZVOUS FILE %s", pmix_ptl_base.rendezvous_filename); rc = write_rndz_file(pmix_ptl_base.rendezvous_filename, lt->uri, &pmix_ptl_base.created_rendezvous_dir, &pmix_ptl_base.created_rendezvous_file); if (PMIX_SUCCESS != rc) { goto sockerror; } } nextstep: /* if we are the scheduler, then drop an appropriately named * contact file so the system's resource manager can find us */ if (PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { if (0 > asprintf(&pmix_ptl_base.scheduler_filename, "%s/pmix.sched.%s", pmix_ptl_base.system_tmpdir, pmix_globals.hostname)) { goto sockerror; } rc = write_rndz_file(pmix_ptl_base.scheduler_filename, lt->uri, &pmix_ptl_base.created_system_tmpdir, &pmix_ptl_base.created_scheduler_filename); if (PMIX_SUCCESS != rc) { goto sockerror; } } else if (PMIX_PEER_IS_SYS_CTRLR(pmix_globals.mypeer)) { /* if we are the system controller, then drop an appropriately named * contact file so others can find us */ if (0 > asprintf(&pmix_ptl_base.sysctrlr_filename, "%s/pmix.sysctrlr.%s", pmix_ptl_base.system_tmpdir, pmix_globals.hostname)) { goto sockerror; } rc = write_rndz_file(pmix_ptl_base.sysctrlr_filename, lt->uri, &pmix_ptl_base.created_system_tmpdir, &pmix_ptl_base.created_sysctrlr_filename); if (PMIX_SUCCESS != rc) { goto sockerror; } } else if (pmix_ptl_base.tool_support) { /* if we are going to support tools, then drop contact file(s) */ if (pmix_ptl_base.system_tool) { if (0 > asprintf(&pmix_ptl_base.system_filename, "%s/pmix.sys.%s", pmix_ptl_base.system_tmpdir, pmix_globals.hostname)) { goto sockerror; } rc = write_rndz_file(pmix_ptl_base.system_filename, lt->uri, &pmix_ptl_base.created_system_tmpdir, &pmix_ptl_base.created_system_filename); if (PMIX_SUCCESS != rc) { goto sockerror; } } if (pmix_ptl_base.session_tool) { /* first output to a std file */ if (0 > asprintf(&pmix_ptl_base.session_filename, "%s/pmix.%s.tool", pmix_ptl_base.session_tmpdir, pmix_globals.hostname)) { goto sockerror; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "WRITING SESSION TOOL FILE %s", pmix_ptl_base.session_filename); rc = write_rndz_file(pmix_ptl_base.session_filename, lt->uri, &pmix_ptl_base.created_session_tmpdir, &pmix_ptl_base.created_session_filename); if (PMIX_SUCCESS != rc) { goto sockerror; } } /* now output to a file based on pid */ mypid = getpid(); if (0 > asprintf(&pmix_ptl_base.pid_filename, "%s/pmix.%s.tool.%d", pmix_ptl_base.session_tmpdir, pmix_globals.hostname, mypid)) { goto sockerror; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "WRITING PID TOOL FILE %s", pmix_ptl_base.pid_filename); rc = write_rndz_file(pmix_ptl_base.pid_filename, lt->uri, &pmix_ptl_base.created_session_tmpdir, &pmix_ptl_base.created_pid_filename); if (PMIX_SUCCESS != rc) { goto sockerror; } /* now output it into a file based on my nspace */ if (0 > asprintf(&pmix_ptl_base.nspace_filename, "%s/pmix.%s.tool.%s", pmix_ptl_base.session_tmpdir, pmix_globals.hostname, pmix_globals.myid.nspace)) { goto sockerror; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "WRITING NSPACE TOOL FILE %s", pmix_ptl_base.nspace_filename); rc = write_rndz_file(pmix_ptl_base.nspace_filename, lt->uri, &pmix_ptl_base.created_session_tmpdir, &pmix_ptl_base.created_nspace_filename); if (PMIX_SUCCESS != rc) { goto sockerror; } } return PMIX_SUCCESS; sockerror: CLOSE_THE_SOCKET(lt->socket); return rc; } pmix-6.1.1~rc2/src/mca/ptl/base/ptl_base_frame.c0000664000175000017500000006203115203536752021646 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2009 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/mca.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_error.h" #include "src/util/pmix_os_dirpath.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_parse_options.h" #include "src/util/pmix_show_help.h" #include "src/mca/ptl/base/base.h" #include "src/mca/ptl/ptl_types.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public mca_base_component_t struct. */ #include "src/mca/ptl/base/static-components.h" /* Instantiate the global vars */ pmix_ptl_base_t pmix_ptl_base = { .initialized = false, .selected = false, .posted_recvs = PMIX_LIST_STATIC_INIT, .unexpected_msgs = PMIX_LIST_STATIC_INIT, .listener = PMIX_LISTENER_STATIC_INIT, .connection = NULL, .max_msg_size = 0, .session_tmpdir = NULL, .system_tmpdir = NULL, .report_uri = NULL, .uri = NULL, .urifile = NULL, .sysctrlr_filename = NULL, .scheduler_filename = NULL, .system_filename = NULL, .session_filename = NULL, .nspace_filename = NULL, .pid_filename = NULL, .rendezvous_filename = NULL, .created_rendezvous_dir = false, .created_rendezvous_file = false, .created_session_tmpdir = false, .created_system_tmpdir = false, .created_sysctrlr_filename = false, .created_scheduler_filename = false, .created_system_filename = false, .created_session_filename = false, .created_nspace_filename = false, .created_pid_filename = false, .created_urifile = false, .remote_connections = false, .connections_specified = false, .system_tool = false, .allow_foreign_tools = true, .session_tool = false, .tool_support = false, .if_include = NULL, .if_exclude = NULL, .ipv4_ports = NULL, .disable_ipv4_family = false, .ipv6_ports = NULL, .disable_ipv6_family = true, .max_retries = 0, .wait_to_connect = 0, .handshake_wait_time = 0, .handshake_max_retries = 0 }; int pmix_ptl_base_output = -1; pmix_ptl_module_t pmix_ptl = { .name = NULL, .init = NULL, .finalize = NULL, .recv = NULL, .cancel = NULL, .connect_to_peer = NULL, .query_servers = NULL, .setup_listener = NULL, .setup_fork = NULL }; static size_t max_msg_size = 32; static char *dyn_port_string; #if PMIX_ENABLE_IPV6 static char *dyn_port_string6; #endif static int pmix_ptl_register(pmix_mca_base_register_flag_t flags) { int idx; (void) flags; pmix_mca_base_var_register("pmix", "ptl", "base", "max_msg_size", "Max size (in Mbytes) of a client/server msg", PMIX_MCA_BASE_VAR_TYPE_SIZE_T, &max_msg_size); if (0 == max_msg_size) { max_msg_size = PMIX_TAINT_SIZE_LIMIT; } else { pmix_ptl_base.max_msg_size = max_msg_size * 1024 * 1024; } idx = pmix_mca_base_var_register("pmix", "ptl", "base", "if_include", "Comma-delimited list of devices and/or CIDR notation of TCP networks " "(e.g., \"eth0,192.168.0.0/16\"). Mutually exclusive with ptl_tcp_if_exclude.", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_ptl_base.if_include); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "if_include", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); idx = pmix_mca_base_var_register("pmix", "ptl", "base", "if_exclude", "Comma-delimited list of devices and/or CIDR notation of TCP networks to NOT use " "-- all devices not matching these specifications will be used (e.g., " "\"eth0,192.168.0.0/16\"). " "If set to a non-default value, it is mutually exclusive with ptl_tcp_if_include.", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_ptl_base.if_exclude); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "if_exclude", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); /* if_include and if_exclude need to be mutually exclusive */ if (NULL != pmix_ptl_base.if_include && NULL != pmix_ptl_base.if_exclude) { pmix_show_help("help-ptl-base.txt", "include-exclude", true, pmix_ptl_base.if_include, pmix_ptl_base.if_exclude); return PMIX_ERR_NOT_AVAILABLE; } dyn_port_string = NULL; idx = pmix_mca_base_var_register("pmix", "ptl", "base", "ipv4_ports", "IPv4 port(s) to be used", PMIX_MCA_BASE_VAR_TYPE_STRING, &dyn_port_string); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "base", "ipv4_port", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "ipv4_port", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); if (NULL != dyn_port_string) { pmix_util_parse_range_options(dyn_port_string, &pmix_ptl_base.ipv4_ports); if (0 == strcmp(pmix_ptl_base.ipv4_ports[0], "-1")) { PMIx_Argv_free(pmix_ptl_base.ipv4_ports); pmix_ptl_base.ipv4_ports = pmix_malloc(2*sizeof(char*)); pmix_ptl_base.ipv4_ports[0] = strdup("0"); pmix_ptl_base.ipv4_ports[1] = NULL; } } else { pmix_ptl_base.ipv4_ports = pmix_malloc(2*sizeof(char*)); pmix_ptl_base.ipv4_ports[0] = strdup("0"); pmix_ptl_base.ipv4_ports[1] = NULL; } #if PMIX_ENABLE_IPV6 dyn_port_string6 = NULL; idx = pmix_mca_base_var_register("pmix", "ptl", "base", "ipv6_ports", "IPv6 port(s) to be used", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_ptl_base.ipv6_ports); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "base", "ipv6_port", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "ipv6_port", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); if (NULL != dyn_port_string6) { pmix_util_parse_range_options(dyn_port_string6, &pmix_ptl_base.ipv6_ports); if (0 == strcmp(pmix_ptl_base.ipv6_ports[0], "-1")) { PMIx_Argv_free(pmix_ptl_base.ipv6_ports); pmix_ptl_base.ipv6_ports = pmix_malloc(2*sizeof(char*)); pmix_ptl_base.ipv6_ports[0] = strdup("0"); pmix_ptl_base.ipv6_ports[1] = NULL; } } else { pmix_ptl_base.ipv6_ports = pmix_malloc(2*sizeof(char*)); pmix_ptl_base.ipv6_ports[0] = strdup("0"); pmix_ptl_base.ipv6_ports[1] = NULL; } #endif idx = pmix_mca_base_var_register("pmix", "ptl", "base", "disable_ipv4_family", "Disable the IPv4 interfaces", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_ptl_base.disable_ipv4_family); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "disable_ipv4_family", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); pmix_ptl_base.disable_ipv6_family = true; idx = pmix_mca_base_var_register("pmix", "ptl", "base", "disable_ipv6_family", "Disable the IPv6 interfaces (default:disabled)", PMIX_MCA_BASE_VAR_TYPE_BOOL, &pmix_ptl_base.disable_ipv6_family); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "disable_ipv6_family", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); idx = pmix_mca_base_var_register("pmix", "ptl", "base", "connection_wait_time", "Number of seconds to wait for the server connection file to appear", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_ptl_base.wait_to_connect); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "connection_wait_time", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); idx = pmix_mca_base_var_register("pmix", "ptl", "base", "max_retries", "Number of times to look for the connection file before quitting", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_ptl_base.max_retries); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "max_retries", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); idx = pmix_mca_base_var_register("pmix", "ptl", "base", "handshake_wait_time", "Number of seconds to wait for the server reply to the handshake request", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_ptl_base.handshake_wait_time); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "handshake_wait_time", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); idx = pmix_mca_base_var_register("pmix", "ptl", "base", "handshake_max_retries", "Number of times to retry the handshake request before giving up", PMIX_MCA_BASE_VAR_TYPE_INT, &pmix_ptl_base.handshake_max_retries); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "handshake_max_retries", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); idx = pmix_mca_base_var_register("pmix", "ptl", "base", "report_uri", "Output URI [- => stdout, + => stderr, or filename]", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_ptl_base.report_uri); (void) pmix_mca_base_var_register_synonym(idx, "pmix", "ptl", "tcp", "report_uri", PMIX_MCA_BASE_VAR_SYN_FLAG_DEPRECATED); return PMIX_SUCCESS; } static bool _check_file(const char *root, const char *path) { struct stat st; char *fullpath; int rc; /* * Keep: * - non-zero files starting with "output-" */ if (0 == strncmp(path, "output-", strlen("output-"))) { memset(&st, 0, sizeof(struct stat)); fullpath = pmix_os_path(false, root, path, NULL); rc = stat(fullpath, &st); if (0 != rc) { free(fullpath); return true; } free(fullpath); if (0 == st.st_size) { return true; } return false; } return true; } static pmix_status_t pmix_ptl_close(void) { int rc; char *tmp; if (!pmix_ptl_base.initialized) { return PMIX_SUCCESS; } pmix_ptl_base.initialized = false; pmix_ptl_base.selected = false; /* ensure the listen thread has been shut down */ pmix_ptl_base_stop_listening(); if (NULL != pmix_client_globals.myserver) { if (0 <= pmix_client_globals.myserver->sd) { CLOSE_THE_SOCKET(pmix_client_globals.myserver->sd); pmix_client_globals.myserver->sd = -1; } } if (NULL != pmix_ptl_base.connection) { free(pmix_ptl_base.connection); } /* the component will cleanup when closed */ PMIX_LIST_DESTRUCT(&pmix_ptl_base.posted_recvs); PMIX_DESTRUCT(&pmix_ptl_base.listener); if (NULL != pmix_ptl_base.scheduler_filename) { if (pmix_ptl_base.created_scheduler_filename) { rc = remove(pmix_ptl_base.scheduler_filename); if (0 != rc) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "Remove of %s failed: %s", pmix_ptl_base.scheduler_filename, strerror(errno)); } } free(pmix_ptl_base.scheduler_filename); } if (NULL != pmix_ptl_base.sysctrlr_filename) { if (pmix_ptl_base.created_sysctrlr_filename) { rc = remove(pmix_ptl_base.sysctrlr_filename); if (0 != rc) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "Remove of %s failed: %s", pmix_ptl_base.sysctrlr_filename, strerror(errno)); } } free(pmix_ptl_base.sysctrlr_filename); } if (NULL != pmix_ptl_base.system_filename) { if (pmix_ptl_base.created_system_filename) { rc = remove(pmix_ptl_base.system_filename); if (0 != rc) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "Remove of %s failed: %s", pmix_ptl_base.system_filename, strerror(errno)); } } free(pmix_ptl_base.system_filename); } if (NULL != pmix_ptl_base.session_filename) { if (pmix_ptl_base.created_session_filename) { rc = remove(pmix_ptl_base.session_filename); if (0 != rc) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "Remove of %s failed: %s", pmix_ptl_base.session_filename, strerror(errno)); } } free(pmix_ptl_base.session_filename); } if (NULL != pmix_ptl_base.nspace_filename) { if (pmix_ptl_base.created_nspace_filename) { rc = remove(pmix_ptl_base.nspace_filename); if (0 != rc) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "Remove of %s failed: %s", pmix_ptl_base.nspace_filename, strerror(errno)); } } free(pmix_ptl_base.nspace_filename); } if (NULL != pmix_ptl_base.pid_filename) { if (pmix_ptl_base.created_pid_filename) { rc = remove(pmix_ptl_base.pid_filename); if (0 != rc) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "Remove of %s failed: %s", pmix_ptl_base.pid_filename, strerror(errno)); } } free(pmix_ptl_base.pid_filename); } if (NULL != pmix_ptl_base.rendezvous_filename) { if (pmix_ptl_base.created_rendezvous_dir) { tmp = pmix_dirname(pmix_ptl_base.rendezvous_filename); pmix_os_dirpath_destroy(tmp, true, _check_file); free(tmp); } if (pmix_ptl_base.created_rendezvous_file) { rc = remove(pmix_ptl_base.rendezvous_filename); if (0 != rc) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "Remove of %s failed: %s", pmix_ptl_base.rendezvous_filename, strerror(errno)); } } free(pmix_ptl_base.rendezvous_filename); } if (NULL != pmix_ptl_base.uri) { free(pmix_ptl_base.uri); } if (NULL != pmix_ptl_base.urifile) { if (pmix_ptl_base.created_urifile) { /* remove the file */ rc = remove(pmix_ptl_base.urifile); if (0 != rc) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "Remove of %s failed: %s", pmix_ptl_base.urifile, strerror(errno)); } } free(pmix_ptl_base.urifile); pmix_ptl_base.urifile = NULL; } if (NULL != pmix_ptl_base.session_tmpdir) { /* if I created the session tmpdir, then remove it if empty */ if (pmix_ptl_base.created_session_tmpdir) { pmix_os_dirpath_destroy(pmix_ptl_base.session_tmpdir, true, _check_file); } free(pmix_ptl_base.session_tmpdir); } if (NULL != pmix_ptl_base.system_tmpdir) { if (pmix_ptl_base.created_system_tmpdir) { pmix_os_dirpath_destroy(pmix_ptl_base.system_tmpdir, true, _check_file); } free(pmix_ptl_base.system_tmpdir); } if (NULL != pmix_ptl_base.ipv4_ports) { PMIx_Argv_free(pmix_ptl_base.ipv4_ports); } #if PMIX_ENABLE_IPV6 if (NULL != pmix_ptl_base.ipv6_ports) { PMIx_Argv_free(pmix_ptl_base.ipv6_ports); } #endif return pmix_mca_base_framework_components_close(&pmix_ptl_base_framework, NULL); } static pmix_status_t pmix_ptl_open(pmix_mca_base_open_flag_t flags) { pmix_status_t rc; char *tdir; /* initialize globals */ pmix_ptl_base.initialized = true; PMIX_CONSTRUCT(&pmix_ptl_base.posted_recvs, pmix_list_t); PMIX_CONSTRUCT(&pmix_ptl_base.listener, pmix_listener_t); pmix_ptl_base.connection = (struct sockaddr_storage *)malloc(sizeof(struct sockaddr_storage)); if (NULL == pmix_ptl_base.connection) { return PMIX_ERR_NOMEM; } memset(pmix_ptl_base.connection, 0, sizeof(struct sockaddr_storage)); /* check for environ-based directives * on system tmpdir to use */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) || PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { pmix_ptl_base.session_tmpdir = strdup(pmix_server_globals.tmpdir); } else { if (NULL != (tdir = getenv("PMIX_SERVER_TMPDIR"))) { pmix_ptl_base.session_tmpdir = strdup(tdir); } else { pmix_ptl_base.session_tmpdir = strdup(pmix_tmp_directory()); } } if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) || PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { pmix_ptl_base.system_tmpdir = strdup(pmix_server_globals.system_tmpdir); } else { if (NULL != (tdir = getenv("PMIX_SYSTEM_TMPDIR"))) { pmix_ptl_base.system_tmpdir = strdup(tdir); } else { pmix_ptl_base.system_tmpdir = strdup(pmix_tmp_directory()); } } if (NULL != pmix_ptl_base.report_uri && 0 != strcmp(pmix_ptl_base.report_uri, "-") && 0 != strcmp(pmix_ptl_base.report_uri, "+")) { pmix_ptl_base.urifile = strdup(pmix_ptl_base.report_uri); } if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) || PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { if (NULL != (tdir = getenv("PMIX_LAUNCHER_RENDEZVOUS_FILE"))) { pmix_ptl_base.rendezvous_filename = strdup(tdir); } } /* Open up all available components */ rc = pmix_mca_base_framework_components_open(&pmix_ptl_base_framework, flags); pmix_ptl_base_output = pmix_ptl_base_framework.framework_output; return rc; } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, ptl, "PMIx Transfer Layer", pmix_ptl_register, pmix_ptl_open, pmix_ptl_close, pmix_mca_ptl_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); /*** INSTANTIATE INTERNAL CLASSES ***/ static void scon(pmix_ptl_send_t *p) { memset(&p->hdr, 0, sizeof(pmix_ptl_hdr_t)); p->hdr.tag = UINT32_MAX; p->hdr.nbytes = 0; p->data = NULL; p->hdr_sent = false; p->sdptr = NULL; p->sdbytes = 0; } static void sdes(pmix_ptl_send_t *p) { if (NULL != p->data) { PMIX_RELEASE(p->data); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_ptl_send_t, pmix_list_item_t, scon, sdes); static void rcon(pmix_ptl_recv_t *p) { p->peer = NULL; memset(&p->hdr, 0, sizeof(pmix_ptl_hdr_t)); p->hdr.tag = UINT32_MAX; p->hdr.nbytes = 0; p->data = NULL; p->hdr_recvd = false; p->rdptr = NULL; p->rdbytes = 0; } static void rdes(pmix_ptl_recv_t *p) { if (NULL != p->peer) { PMIX_RELEASE(p->peer); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_ptl_recv_t, pmix_list_item_t, rcon, rdes); static void prcon(pmix_ptl_posted_recv_t *p) { p->peer = NULL; p->tag = UINT32_MAX; p->cbfunc = NULL; p->cbdata = NULL; } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_ptl_posted_recv_t, pmix_list_item_t, prcon, NULL); static void srcon(pmix_ptl_sr_t *p) { p->peer = NULL; p->bfr = NULL; p->cbfunc = NULL; p->cbdata = NULL; } static void srdes(pmix_ptl_sr_t *p) { if (NULL != p->peer) { PMIX_RELEASE(p->peer); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_ptl_sr_t, pmix_object_t, srcon, srdes); static void pccon(pmix_pending_connection_t *p) { p->need_id = false; p->nspace_created = false; p->rinfo_created = false; PMIX_LOAD_PROCID(&p->proc, NULL, PMIX_RANK_UNDEF); p->info = NULL; p->ninfo = 0; p->peer = NULL; p->version = NULL; p->bfrops = NULL; p->psec = NULL; p->gds = NULL; p->cred = NULL; p->proc_type.type = PMIX_PROC_UNDEF; p->proc_type.major = PMIX_MAJOR_WILDCARD; p->proc_type.minor = PMIX_MINOR_WILDCARD; p->proc_type.release = PMIX_RELEASE_WILDCARD; p->proc_type.flag = 0; } static void pcdes(pmix_pending_connection_t *p) { if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->ninfo); } if (NULL != p->version) { free(p->version); } if (NULL != p->bfrops) { free(p->bfrops); } if (NULL != p->psec) { free(p->psec); } if (NULL != p->gds) { free(p->gds); } if (NULL != p->cred) { free(p->cred); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_pending_connection_t, pmix_object_t, pccon, pcdes); static void lcon(pmix_listener_t *p) { memset(&p->ev, 0, sizeof(pmix_event_t)); p->active = false; p->socket = -1; p->varname = NULL; p->uri = NULL; p->owner_given = false; p->group_given = false; p->mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; } static void ldes(pmix_listener_t *p) { if (0 <= p->socket) { CLOSE_THE_SOCKET(p->socket); } if (NULL != p->varname) { free(p->varname); } if (NULL != p->uri) { free(p->uri); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_listener_t, pmix_list_item_t, lcon, ldes); static void qcon(pmix_ptl_queue_t *p) { p->peer = NULL; p->buf = NULL; p->tag = UINT32_MAX; } static void qdes(pmix_ptl_queue_t *p) { if (NULL != p->peer) { PMIX_RELEASE(p->peer); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_ptl_queue_t, pmix_object_t, qcon, qdes); static void ccon(pmix_connection_t *p) { p->sd = -1; p->nspace = NULL; p->rank = PMIX_RANK_INVALID; p->uri = NULL; p->version = NULL; } static void dcon(pmix_connection_t *p) { if (NULL != p->nspace) { free(p->nspace); } if (NULL != p->uri) { free(p->uri); } if (NULL != p->version) { free(p->version); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_connection_t, pmix_list_item_t, ccon, dcon); pmix-6.1.1~rc2/src/mca/ptl/base/ptl_base_handshake.h0000664000175000017500000002140115203536752022503 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PTL_BASE_HANDSHAKE_H_ #define PMIX_PTL_BASE_HANDSHAKE_H_ #include "src/include/pmix_config.h" #ifdef HAVE_STRING_H # include #endif /* The following macros are for use in the PTL connection * handler. For simplicity, they include variables that are * defined in the functions where they are used - thus, these * macros are NOT portable for use elsewhere * * A symmetric pair of macros are provided specifically to * make it easier to read and compare the two ends of the * handshake */ BEGIN_C_DECLS /* define flag values that indicate the type of process attempting * to connect to a server: * 0 => simple client process * 1 => legacy tool - may or may not have an identifier * 2 => legacy launcher - may or may not have an identifier * ------------------------------------------ * 3 => self-started tool process that needs an identifier * 4 => self-started tool process that was given an identifier by caller * 5 => tool that was started by a PMIx server - identifier specified by server * 6 => self-started launcher that needs an identifier * 7 => self-started launcher that was given an identifier by caller * 8 => launcher that was started by a PMIx server - identifier specified by server * 9 => singleton client - treated like a tool that has an identifier * ------------------------------------------ * 10 => scheduler */ typedef uint8_t pmix_rnd_flag_t; #define PMIX_SIMPLE_CLIENT 0 #define PMIX_LEGACY_TOOL 1 #define PMIX_LEGACY_LAUNCHER 2 #define PMIX_TOOL_NEEDS_ID 3 #define PMIX_TOOL_GIVEN_ID 4 #define PMIX_TOOL_CLIENT 5 #define PMIX_LAUNCHER_NEEDS_ID 6 #define PMIX_LAUNCHER_GIVEN_ID 7 #define PMIX_LAUNCHER_CLIENT 8 #define PMIX_SINGLETON_CLIENT 9 #define PMIX_SCHEDULER_WITH_ID 10 /* The following macros are used in the ptl_base_connection_hdlr.c * file to parse the handshake message and extract its fields */ #define PMIX_PTL_GET_STRING(n) \ do { \ size_t _l; \ PMIX_STRNLEN(_l, mg, cnt); \ if (_l < cnt) { \ (n) = strdup(mg); \ mg += strlen((n)) + 1; \ cnt -= strlen((n)) + 1; \ } else { \ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); \ goto error; \ } \ } while (0) /* numerical value must be converted back to host * order, so we use an intermediate storage place * for that purpose */ #define PMIX_PTL_GET_U32_NOERROR(r, n) \ do { \ uint32_t _u; \ if (sizeof(uint32_t) <= cnt) { \ memcpy(&_u, mg, sizeof(uint32_t)); \ (n) = ntohl(_u); \ mg += sizeof(uint32_t); \ cnt -= sizeof(uint32_t); \ (r) = PMIX_SUCCESS; \ } else { \ (r) = PMIX_ERR_BAD_PARAM; \ } \ } while (0) #define PMIX_PTL_GET_U32(n) \ do { \ uint32_t _u; \ if (sizeof(uint32_t) <= cnt) { \ memcpy(&_u, mg, sizeof(uint32_t)); \ (n) = ntohl(_u); \ mg += sizeof(uint32_t); \ cnt -= sizeof(uint32_t); \ } else { \ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); \ goto error; \ } \ } while (0) #define PMIX_PTL_GET_BLOB(b, l) \ do { \ if (0 < (l)) { \ (b) = (char *) malloc((l)); \ if (NULL == (b)) { \ PMIX_ERROR_LOG(PMIX_ERR_NOMEM); \ goto error; \ } \ memcpy((b), mg, (l)); \ mg += (l); \ cnt -= (l); \ } \ } while (0) #define PMIX_PTL_GET_U8(n) \ do { \ if (sizeof(uint8_t) <= cnt) { \ memcpy(&(n), mg, sizeof(uint8_t)); \ mg += sizeof(uint8_t); \ cnt -= sizeof(uint8_t); \ } else { \ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); \ goto error; \ } \ } while (0) #define PMIX_PTL_GET_PROCID(p) \ do { \ char *_n; \ uint32_t _r; \ pmix_status_t _rc; \ PMIX_PTL_GET_STRING(_n); \ PMIX_PTL_GET_U32_NOERROR(_rc, _r); \ if (PMIX_SUCCESS != _rc) { \ PMIX_ERROR_LOG(_rc); \ free(_n); \ goto error; \ } \ PMIX_LOAD_PROCID(&(p), _n, _r); \ free(_n); \ } while (0) /* The following macros are for use in the ptl_base_fns.c * when constructing the handshake message. */ #define PMIX_PTL_PUT_STRING(n) \ do { \ memcpy(msg + csize, (n), strlen((n))); \ csize += strlen((n)) + 1; \ } while (0) /* numerical value must be converted to network byte * order, so we use an intermediate storage place * for that purpose */ #define PMIX_PTL_PUT_U32(n) \ do { \ uint32_t _u; \ _u = htonl((uint32_t)(n)); \ memcpy(msg + csize, &_u, sizeof(uint32_t)); \ csize += sizeof(uint32_t); \ } while (0) #define PMIX_PTL_PUT_BLOB(b, l) \ do { \ if (0 < (l)) { \ memcpy(msg + csize, (b), (l)); \ csize += (l); \ } \ } while (0) #define PMIX_PTL_PUT_U8(n) \ do { \ memcpy(msg + csize, &(n), sizeof(uint8_t)); \ csize += sizeof(uint8_t); \ } while (0) #define PMIX_PTL_PUT_PROCID(p) \ do { \ PMIX_PTL_PUT_STRING((p).nspace); \ PMIX_PTL_PUT_U32((p).rank); \ } while (0) /* the following macros are for use in the ptl_base_fns.c * when sending/recving values during the handshake */ #define PMIX_PTL_RECV_NSPACE(s, n) \ do { \ pmix_status_t r; \ r = pmix_ptl_base_recv_blocking((s), (char *) (n), PMIX_MAX_NSLEN + 1); \ (n)[PMIX_MAX_NSLEN] = '\0'; /* ensure NULL termination */ \ if (PMIX_SUCCESS != r) { \ return r; \ } \ } while (0) #define PMIX_PTL_RECV_U32(s, n) \ do { \ pmix_status_t r; \ uint32_t _u; \ r = pmix_ptl_base_recv_blocking((s), (char *) &_u, sizeof(uint32_t)); \ if (PMIX_SUCCESS != r) { \ return r; \ } \ (n) = htonl(_u); \ } while (0) END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/ptl/base/ptl_base_fns.c0000664000175000017500000013625415203536752021353 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_DIRENT_H # include #endif #include #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/bfrops/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_net.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_if.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "src/util/pmix_string_copy.h" #include "src/mca/ptl/base/base.h" #include "src/mca/ptl/base/ptl_base_handshake.h" /**** SUPPORTING FUNCTIONS ****/ static void timeout(int sd, short args, void *cbdata); static pmix_status_t construct_message(pmix_peer_t *peer, char **msgout, size_t *sz, pmix_info_t *iptr, size_t niptr); pmix_status_t pmix_ptl_base_set_peer(pmix_peer_t *peer, char **evar) { pmix_status_t rc; char *vrs; pmix_bfrops_base_active_module_t *mod; char *ptr, *tmp, check[2], *eval; int major, minor; bool evalgiven; vrs = getenv("PMIX_VERSION"); if (NULL == evar) { return PMIX_ERR_BAD_PARAM; } if (NULL == *evar) { eval = NULL; evalgiven = false; } else { // they are passing in the bfrops module to use eval = *evar; evalgiven = true; } PMIX_LIST_FOREACH(mod, &pmix_bfrops_globals.actives, pmix_bfrops_base_active_module_t) { // these are in priority order, so take the highest priority that we find ptr = strrchr(mod->component->base.pmix_mca_component_name, 'v'); ++ptr; pmix_asprintf(&tmp, "PMIX_SERVER_URI%s", ptr); if (evalgiven) { if (0 != strcmp(tmp, eval)) { free(tmp); continue; } } else { if (NULL == (eval = getenv(tmp))) { free(tmp); continue; } } free(tmp); /* must use the v bfrops module */ pmix_asprintf(&tmp, "v%s", ptr); PMIX_BFROPS_SET_MODULE(rc, pmix_globals.mypeer, peer, tmp); free(tmp); if (PMIX_SUCCESS != rc) { continue; } check[1] = '\0'; // must be at least one number in the version check[0] = ptr[0]; major = strtoul(check, NULL, 10); // might not be a second - e.g., v4 if (2 == strlen(ptr)) { check[0] = ptr[1]; minor = strtoul(check, NULL, 10); } else { minor = 0; } /* we are talking to a vmajor.minor server */ PMIX_SET_PEER_TYPE(peer, PMIX_PROC_SERVER); PMIX_SET_PEER_VERSION(peer, vrs, major, minor); pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "Version %s SERVER DETECTED - BFROPS %s", vrs, mod->component->base.pmix_mca_component_name); if (!evalgiven) { // return the uri *evar = eval; } return PMIX_SUCCESS; } return PMIX_ERR_UNREACH; } pmix_status_t pmix_ptl_base_setup_fork(const pmix_proc_t *proc, char ***env) { PMIX_HIDE_UNUSED_PARAMS(proc); PMIx_Setenv("PMIX_SERVER_TMPDIR", pmix_ptl_base.session_tmpdir, true, env); PMIx_Setenv("PMIX_SYSTEM_TMPDIR", pmix_ptl_base.system_tmpdir, true, env); return PMIX_SUCCESS; } pmix_status_t pmix_ptl_base_parse_uri(const char *evar, char **nspace, pmix_rank_t *rank, char **suri) { char **uri; char *p; uri = PMIx_Argv_split(evar, ';'); if (2 != PMIx_Argv_count(uri)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIx_Argv_free(uri); return PMIX_ERR_NOT_SUPPORTED; } /* set the server nspace - the rank is appended * to the end with a '.' separator. NOTE: we * cannot search from the FRONT as that would * stop on any FQDN or IPv4 separations */ if (NULL == (p = strrchr(uri[0], '.'))) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIx_Argv_free(uri); return PMIX_ERR_NOT_SUPPORTED; } *p = '\0'; ++p; *nspace = strdup(uri[0]); /* set the server rank */ *rank = strtoull(p, NULL, 10); if (NULL != suri) { *suri = strdup(uri[1]); } PMIx_Argv_free(uri); return PMIX_SUCCESS; } pmix_status_t pmix_ptl_base_parse_uri_file(char *filename, bool optional, pmix_list_t *connections) { FILE *fp; char *srvr, *p = NULL; pmix_lock_t lock; pmix_event_t ev; struct timeval tv; int retries; pmix_status_t rc; pmix_connection_t *cn; char *nspace = NULL; pmix_rank_t rank; char *uri = NULL; /* if we cannot open the file, then the server must not * be configured to support tool connections, or this * user isn't authorized to access it - or it may just * not exist yet! Check for existence */ /* coverity[TOCTOU] */ if (0 != access(filename, R_OK)) { if (ENOENT == errno && !optional) { /* the file does not exist, so give it * a little time to see if the server * is still starting up */ retries = 0; do { ++retries; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "WAITING FOR CONNECTION FILE %s", filename); PMIX_CONSTRUCT_LOCK(&lock); if (0 < pmix_ptl_base.wait_to_connect) { tv.tv_sec = pmix_ptl_base.wait_to_connect; tv.tv_usec = 0; pmix_event_evtimer_set(pmix_globals.evbase, &ev, timeout, &lock); PMIX_POST_OBJECT(&ev); pmix_event_evtimer_add(&ev, &tv); } else { tv.tv_sec = 0; tv.tv_usec = 10000; // use 0.01 sec as default pmix_event_evtimer_set(pmix_globals.evbase, &ev, timeout, &lock); PMIX_POST_OBJECT(&ev); pmix_event_evtimer_add(&ev, &tv); } PMIX_WAIT_THREAD(&lock); PMIX_DESTRUCT_LOCK(&lock); /* coverity[TOCTOU] */ if (0 == access(filename, R_OK)) { goto process; } } while (retries < pmix_ptl_base.max_retries); /* otherwise, mark it as unreachable */ } if (!optional) { if (EACCES == errno) { pmix_show_help("help-ptl-base.txt", "file-not-found", true, filename, "access denied"); } else { pmix_show_help("help-ptl-base.txt", "file-not-found", true, filename, "could not be found"); } } return PMIX_ERR_UNREACH; } process: fp = fopen(filename, "r"); if (NULL == fp) { if (!optional) { if (EACCES == errno) { pmix_show_help("help-ptl-base.txt", "file-not-found", true, filename, "access denied"); } else { pmix_show_help("help-ptl-base.txt", "file-not-found", true, filename, "could not be found"); } } return PMIX_ERR_UNREACH; } /* get the URI - might seem crazy, but there is actually * a race condition here where the server may have created * the file but not yet finished writing into it. So give * us a chance to get the required info */ for (retries = 0; retries < 3; retries++) { srvr = pmix_getline(fp); if (NULL != srvr) { break; } fclose(fp); tv.tv_sec = 0; tv.tv_usec = 10000; // use 0.01 sec as default PMIX_CONSTRUCT_LOCK(&lock); pmix_event_evtimer_set(pmix_globals.evbase, &ev, timeout, &lock); PMIX_POST_OBJECT(&ev); pmix_event_evtimer_add(&ev, &tv); PMIX_WAIT_THREAD(&lock); PMIX_DESTRUCT_LOCK(&lock); fp = fopen(filename, "r"); if (NULL == fp) { return PMIX_ERR_UNREACH; } } if (NULL == srvr) { if (!optional) { pmix_show_help("help-ptl-base.txt", "file-not-found", true, filename, "could not be read"); } fclose(fp); return PMIX_ERR_UNREACH; } /* see if this file contains the server's version */ p = pmix_getline(fp); fclose(fp); /* parse the URI */ rc = pmix_ptl_base_parse_uri(srvr, &nspace, &rank, &uri); free(srvr); if (PMIX_SUCCESS == rc) { cn = PMIX_NEW(pmix_connection_t); cn->nspace = nspace; cn->rank = rank; cn->uri = uri; cn->version = p; pmix_list_append(connections, &cn->super); } else { if (NULL != nspace) { free(nspace); } if (NULL != uri) { free(uri); } if (NULL != p) { free(p); } } return rc; } pmix_status_t pmix_ptl_base_df_search(char *dirname, char *prefix, pmix_info_t info[], size_t ninfo, bool optional, pmix_list_t *connections) { char *newdir; DIR *cur_dirp, *tst; struct dirent *dir_entry; pmix_status_t rc; if (NULL == (cur_dirp = opendir(dirname))) { return PMIX_ERR_NOT_FOUND; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:ptl: searching directory %s", dirname); /* search the entries for something that starts with the provided prefix */ while (NULL != (dir_entry = readdir(cur_dirp))) { /* ignore the . and .. entries */ if (0 == strcmp(dir_entry->d_name, ".") || 0 == strcmp(dir_entry->d_name, "..")) { continue; } newdir = pmix_os_path(false, dirname, dir_entry->d_name, NULL); /* if it is a directory, down search */ tst = opendir(newdir); if (NULL != tst) { closedir(tst); pmix_ptl_base_df_search(newdir, prefix, info, ninfo, optional, connections); free(newdir); continue; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:tool: checking %s vs %s", dir_entry->d_name, prefix); /* see if it starts with our prefix */ if (0 == strncmp(dir_entry->d_name, prefix, strlen(prefix))) { /* try to read this file */ pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:tool: reading file %s", newdir); rc = pmix_ptl_base_parse_uri_file(newdir, optional, connections); if (PMIX_SUCCESS != rc) { free(newdir); closedir(cur_dirp); return rc; } } free(newdir); } closedir(cur_dirp); if (0 == pmix_list_get_size(connections)) { return PMIX_ERR_NOT_FOUND; } return PMIX_SUCCESS; } pmix_status_t pmix_ptl_base_setup_connection(char *uri, struct sockaddr_storage *connection, size_t *len) { char *p = NULL, *p2, *host; struct sockaddr_in *in; struct sockaddr_in6 *in6; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:base setup connection to %s", uri); memset(connection, 0, sizeof(struct sockaddr_storage)); if (0 == strncmp(uri, "tcp4", 4)) { /* need to skip the tcp4: part */ p = strdup(&uri[7]); if (NULL == p) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } /* separate the IP address from the port */ p2 = strrchr(p, ':'); if (NULL == p2) { free(p); PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } *p2 = '\0'; p2++; host = p; /* load the address */ in = (struct sockaddr_in *) connection; in->sin_family = AF_INET; in->sin_addr.s_addr = inet_addr(host); if (in->sin_addr.s_addr == INADDR_NONE) { free(p); PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } in->sin_port = htons(atoi(p2)); *len = sizeof(struct sockaddr_in); } else { /* need to skip the tcp6: part */ p = strdup(&uri[7]); if (NULL == p) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } p2 = strrchr(p, ':'); if (NULL == p2) { free(p); PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } *p2 = '\0'; if (']' == p[strlen(p) - 1]) { p[strlen(p) - 1] = '\0'; } if ('[' == p[0]) { host = &p[1]; } else { host = &p[0]; } /* load the address */ in6 = (struct sockaddr_in6 *) connection; in6->sin6_family = AF_INET6; if (0 == inet_pton(AF_INET6, host, (void *) &in6->sin6_addr)) { pmix_output(0, "ptl_tcp_parse_uri: Could not convert %s\n", host); free(p); PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } in6->sin6_port = htons(atoi(p2)); *len = sizeof(struct sockaddr_in6); } if (NULL != p) { free(p); } return PMIX_SUCCESS; } static pmix_status_t send_connect_ack(pmix_peer_t *peer, pmix_info_t iptr[], size_t niptr) { char *msg; size_t sdsize = 0; pmix_status_t rc; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:ptl SEND CONNECT ACK"); /* set our ID flag and compute the required handshake size */ peer->proc_type.flag = pmix_ptl_base_set_flag(&sdsize); /* construct the contact message */ rc = construct_message(peer, &msg, &sdsize, iptr, niptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* send the entire message across */ if (PMIX_SUCCESS != pmix_ptl_base_send_blocking(peer->sd, msg, sdsize)) { free(msg); return PMIX_ERR_UNREACH; } free(msg); return PMIX_SUCCESS; } /* we receive a connection acknowledgment from the server, * consisting of nothing more than a status report. If success, * then we initiate authentication method */ static pmix_status_t recv_connect_ack(pmix_peer_t *peer) { pmix_status_t reply; pmix_status_t rc; struct timeval save; pmix_socklen_t sz = sizeof(save); bool sockopt = true; uint32_t u32; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix: RECV CONNECT ACK FROM SERVER"); /* set the socket timeout so we don't hang on blocking recv */ rc = pmix_ptl_base_set_timeout(peer, &save, &sz, &sockopt); if (PMIX_SUCCESS != rc) { return rc; } /* receive the status reply */ rc = pmix_ptl_base_recv_blocking(peer->sd, (char *) &u32, sizeof(uint32_t)); if (PMIX_SUCCESS != rc) { if (sockopt) { /* return the socket to normal */ if (0 != setsockopt(peer->sd, SOL_SOCKET, SO_RCVTIMEO, &save, sz)) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix: could not reset setsockopt SO_RCVTIMEO"); } } return rc; } reply = ntohl(u32); if ((PMIX_PEER_IS_CLIENT(pmix_globals.mypeer) || PMIX_PEER_IS_SINGLETON(pmix_globals.mypeer)) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { rc = pmix_ptl_base_client_handshake(peer, reply); } else { // we are a tool rc = pmix_ptl_base_tool_handshake(peer, reply); } if (sockopt) { /* return the socket to normal */ if (0 != setsockopt(peer->sd, SOL_SOCKET, SO_RCVTIMEO, &save, sz)) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix: could not reset setsockopt SO_RCVTIMEO"); } } return rc; } pmix_status_t pmix_ptl_base_make_connection(pmix_peer_t *peer, char *suri, pmix_info_t *iptr, size_t niptr) { struct sockaddr_storage myconnection; pmix_status_t rc; size_t len; int retries = 0; /* setup the connection */ if (PMIX_SUCCESS != (rc = pmix_ptl_base_setup_connection(suri, &myconnection, &len))) { return rc; } retry: /* try to connect */ if (PMIX_SUCCESS != (rc = pmix_ptl_base_connect(&myconnection, len, &peer->sd))) { /* do not error log - might just be a stale connection point */ return rc; } /* send our identity and any authentication credentials to the server */ if (PMIX_SUCCESS != (rc = send_connect_ack(peer, iptr, niptr))) { PMIX_ERROR_LOG(rc); CLOSE_THE_SOCKET(peer->sd); return rc; } /* do whatever handshake is required */ if (PMIX_SUCCESS != (rc = recv_connect_ack(peer))) { CLOSE_THE_SOCKET(peer->sd); if (PMIX_ERR_TEMP_UNAVAILABLE == rc) { ++retries; if (retries < pmix_ptl_base.handshake_max_retries) { goto retry; } } return rc; } /* Assign the lower half of the tag space for sendrecvs */ peer->dyn_tags_start = PMIX_PTL_TAG_DYNAMIC; peer->dyn_tags_current = PMIX_PTL_TAG_DYNAMIC; peer->dyn_tags_end = PMIX_PTL_TAG_DYNAMIC + (UINT32_MAX - PMIX_PTL_TAG_DYNAMIC)/2; return PMIX_SUCCESS; } void pmix_ptl_base_complete_connection(pmix_peer_t *peer, char *nspace, pmix_rank_t rank) { pmix_atomic_set_bool(&pmix_globals.connected); /* setup the server info */ if (NULL == peer->info) { peer->info = PMIX_NEW(pmix_rank_info_t); } if (NULL == peer->nptr) { peer->nptr = PMIX_NEW(pmix_namespace_t); } if (NULL != peer->nptr->nspace) { free(peer->nptr->nspace); } peer->nptr->nspace = strdup(nspace); if (NULL != peer->info->pname.nspace) { free(peer->info->pname.nspace); } peer->info->pname.nspace = strdup(peer->nptr->nspace); peer->info->pname.rank = rank; pmix_ptl_base_set_nonblocking(peer->sd); /* setup recv event */ pmix_event_assign(&peer->recv_event, pmix_globals.evbase, peer->sd, EV_READ | EV_PERSIST, pmix_ptl_base_recv_handler, peer); peer->recv_ev_active = true; PMIX_POST_OBJECT(peer); pmix_event_add(&peer->recv_event, 0); /* setup send event */ pmix_event_assign(&peer->send_event, pmix_globals.evbase, peer->sd, EV_WRITE | EV_PERSIST, pmix_ptl_base_send_handler, peer); peer->send_ev_active = false; } pmix_rnd_flag_t pmix_ptl_base_set_flag(size_t *sz) { pmix_rnd_flag_t flag; size_t sdsize = 0; /* Defined marker values: * */ if (PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) { /* if we are both launcher and client, then we need * to tell the server we are both */ flag = PMIX_LAUNCHER_CLIENT; /* add space for our uid/gid for ACL purposes */ sdsize += 2 * sizeof(uint32_t); /* add space for our identifier */ sdsize += strlen(pmix_globals.myid.nspace) + 1 + sizeof(uint32_t); } else { /* add space for our uid/gid for ACL purposes */ sdsize += 2 * sizeof(uint32_t); /* if they gave us an identifier, we need to pass it */ if (0 < strlen(pmix_globals.myid.nspace) && PMIX_RANK_INVALID != pmix_globals.myid.rank) { flag = PMIX_LAUNCHER_GIVEN_ID; sdsize += strlen(pmix_globals.myid.nspace) + 1 + sizeof(uint32_t); } else { flag = PMIX_LAUNCHER_NEEDS_ID; } } } else if (PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { /* add space for our uid/gid for ACL purposes */ sdsize += 2 * sizeof(uint32_t); flag = PMIX_SCHEDULER_WITH_ID; sdsize += strlen(pmix_globals.myid.nspace) + 1 + sizeof(uint32_t); } else if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { if (PMIX_PEER_IS_SINGLETON(pmix_globals.mypeer)) { flag = PMIX_SINGLETON_CLIENT; /* reserve space for our nspace and rank info */ sdsize += strlen(pmix_globals.myid.nspace) + 1 + sizeof(uint32_t); /* add space for our uid/gid for ACL purposes */ sdsize += 2 * sizeof(uint32_t); } else { /* we are a simple client */ flag = PMIX_SIMPLE_CLIENT; /* reserve space for our nspace and rank info */ sdsize += strlen(pmix_globals.myid.nspace) + 1 + sizeof(uint32_t); } } else { // must be a tool of some sort /* add space for our uid/gid for ACL purposes */ sdsize += 2 * sizeof(uint32_t); if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) { /* if we are both tool and client, then we need * to tell the server we are both */ flag = PMIX_TOOL_CLIENT; /* add space for our identifier */ sdsize += strlen(pmix_globals.myid.nspace) + 1 + sizeof(uint32_t); } else if (0 < strlen(pmix_globals.myid.nspace) && PMIX_RANK_INVALID != pmix_globals.myid.rank) { /* we were given an identifier by the caller, pass it */ sdsize += strlen(pmix_globals.myid.nspace) + 1 + sizeof(uint32_t); flag = PMIX_TOOL_GIVEN_ID; } else { /* we are a self-started tool that needs an identifier */ flag = PMIX_TOOL_NEEDS_ID; } } *sz += sdsize; return flag; } static pmix_status_t construct_message(pmix_peer_t *peer, char **msgout, size_t *sz, pmix_info_t *iptr, size_t niptr) { char *msg; char *sec, *bfrops, *gds; pmix_bfrop_buffer_type_t bftype; uid_t euid; gid_t egid; pmix_buffer_t buf; pmix_status_t rc; pmix_ptl_hdr_t hdr; size_t sdsize, csize; pmix_byte_object_t cred; sdsize = *sz; /* setup the header */ memset(&hdr, 0, sizeof(pmix_ptl_hdr_t)); hdr.pindex = -1; hdr.tag = UINT32_MAX; /* add the name of our active sec module - we selected it * in pmix_client.c prior to entering here */ sec = pmix_globals.mypeer->nptr->compat.psec->name; sdsize += strlen(sec) + 1; /* a security module was assigned to us during rte_init based * on a list of available security modules provided by our * local PMIx server, if known. Now use that module to * get a credential, if the security system provides one. Not * every psec module will do so, thus we must first check */ PMIX_BYTE_OBJECT_CONSTRUCT(&cred); PMIX_PSEC_CREATE_CRED(rc, pmix_globals.mypeer, NULL, 0, NULL, 0, &cred); if (PMIX_SUCCESS != rc) { PMIX_BYTE_OBJECT_DESTRUCT(&cred); return rc; } sdsize += sizeof(uint32_t); // need to pass the number of bytes sdsize += cred.size; // account for the payload itself /* add our type flag */ sdsize += 1; /* add our version string */ sdsize += strlen(PMIX_VERSION) + 1; /* add our active bfrops module name */ bfrops = pmix_globals.mypeer->nptr->compat.bfrops->version; sdsize += strlen(bfrops) + 1; /* and the type of buffer we are using */ bftype = pmix_globals.mypeer->nptr->compat.type; sdsize += sizeof(bftype); /* add our active gds module for working with the server */ gds = (char *) peer->nptr->compat.gds->name; sdsize += strlen(gds) + 1; /* if we were given info structs to pass to the server, pack them */ if (NULL != iptr) { PMIX_CONSTRUCT(&buf, pmix_buffer_t); PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &buf, &niptr, 1, PMIX_SIZE); PMIX_BFROPS_PACK(rc, pmix_globals.mypeer, &buf, iptr, niptr, PMIX_INFO); sdsize += buf.bytes_used; } /* set the number of bytes to be read beyond the header */ hdr.nbytes = sdsize; /* create a space for our message */ sdsize = sizeof(hdr) + hdr.nbytes; if (NULL == (msg = (char *) malloc(sdsize))) { PMIX_BYTE_OBJECT_DESTRUCT(&cred); free(sec); if (NULL != iptr) { PMIX_DESTRUCT(&buf); } return PMIX_ERR_OUT_OF_RESOURCE; } memset(msg, 0, sdsize); /* load the header */ csize = 0; memcpy(msg, &hdr, sizeof(pmix_ptl_hdr_t)); csize += sizeof(pmix_ptl_hdr_t); /* provide our active psec module */ PMIX_PTL_PUT_STRING(sec); /* load the length of the credential */ PMIX_PTL_PUT_U32(cred.size); /* load the credential */ PMIX_PTL_PUT_BLOB(cred.bytes, cred.size); PMIX_BYTE_OBJECT_DESTRUCT(&cred); /* load our process type - this is a single byte, * so no worry about heterogeneity here */ PMIX_PTL_PUT_U8(peer->proc_type.flag); switch (peer->proc_type.flag) { case PMIX_SIMPLE_CLIENT: /* simple client process */ PMIX_PTL_PUT_PROCID(pmix_globals.myid); break; /* we cannot have cases 1 or 2 because those are only * for legacy processes */ case PMIX_TOOL_NEEDS_ID: case PMIX_LAUNCHER_NEEDS_ID: /* self-started tool/launcher process that needs an identifier */ euid = geteuid(); PMIX_PTL_PUT_U32(euid); egid = getegid(); PMIX_PTL_PUT_U32(egid); break; case PMIX_TOOL_GIVEN_ID: case PMIX_LAUNCHER_GIVEN_ID: case PMIX_SCHEDULER_WITH_ID: case PMIX_SINGLETON_CLIENT: /* self-started tool/launcher/singleton process that was given an identifier by caller */ euid = geteuid(); PMIX_PTL_PUT_U32(euid); egid = getegid(); PMIX_PTL_PUT_U32(egid); /* add our identifier */ PMIX_PTL_PUT_PROCID(pmix_globals.myid); break; case PMIX_TOOL_CLIENT: case PMIX_LAUNCHER_CLIENT: /* tool/launcher that was started by a PMIx server - identifier specified by server */ euid = geteuid(); PMIX_PTL_PUT_U32(euid); egid = getegid(); PMIX_PTL_PUT_U32(egid); /* add our identifier */ PMIX_PTL_PUT_PROCID(pmix_globals.myid); break; default: /* we don't know what they are! */ if (NULL != iptr) { PMIX_DESTRUCT(&buf); } free(msg); return PMIX_ERR_NOT_SUPPORTED; } /* provide our version */ PMIX_PTL_PUT_STRING(PMIX_VERSION); /* provide our active bfrops module */ PMIX_PTL_PUT_STRING(bfrops); /* provide the bfrops type */ PMIX_PTL_PUT_U8(bftype); /* provide the gds module */ PMIX_PTL_PUT_STRING(gds); /* provide the info struct bytes */ if (NULL != iptr) { PMIX_PTL_PUT_BLOB(buf.base_ptr, buf.bytes_used); PMIX_DESTRUCT(&buf); } *msgout = msg; *sz = sdsize; return PMIX_SUCCESS; } pmix_status_t pmix_ptl_base_set_timeout(pmix_peer_t *peer, struct timeval *save, pmix_socklen_t *sz, bool *sockopt) { struct timeval tv; /* get the current timeout value so we can reset to it */ if (0 != getsockopt(peer->sd, SOL_SOCKET, SO_RCVTIMEO, (void *) save, sz)) { *sockopt = false; } else { /* set a timeout on the blocking recv so we don't hang */ tv.tv_sec = pmix_ptl_base.handshake_wait_time; tv.tv_usec = 0; if (0 != setsockopt(peer->sd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) { *sockopt = false; } } return PMIX_SUCCESS; } void pmix_ptl_base_setup_socket(pmix_peer_t *peer) { PMIX_HIDE_UNUSED_PARAMS(peer); #if defined(TCP_NODELAY) int optval; optval = 1; if (setsockopt(peer->sd, IPPROTO_TCP, TCP_NODELAY, (char *) &optval, sizeof(optval)) < 0) { opal_backtrace_print(stderr, NULL, 1); pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "[%s:%d] setsockopt(TCP_NODELAY) failed: %s (%d)", __FILE__, __LINE__, strerror(pmix_socket_errno), pmix_socket_errno); } #endif #if defined(SO_NOSIGPIPE) /* Some BSD flavors generate EPIPE when we write to a disconnected peer. We need * the prevent this signal to be able to trap socket shutdown and cleanly release * the endpoint. */ int optval2 = 1; if (setsockopt(peer->sd, SOL_SOCKET, SO_NOSIGPIPE, (char *) &optval2, sizeof(optval2)) < 0) { pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "[%s:%d] setsockopt(SO_NOSIGPIPE) failed: %s (%d)", __FILE__, __LINE__, strerror(pmix_socket_errno), pmix_socket_errno); } #endif } pmix_status_t pmix_ptl_base_client_handshake(pmix_peer_t *peer, pmix_status_t reply) { pmix_status_t rc; /* see if they want us to do the handshake */ if (PMIX_ERR_READY_FOR_HANDSHAKE == reply) { PMIX_PSEC_CLIENT_HANDSHAKE(rc, peer, peer->sd); if (PMIX_SUCCESS != rc) { return rc; } } else if (PMIX_SUCCESS != reply) { return reply; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix: RECV CONNECT CONFIRMATION"); /* receive our index into the peer's client array */ PMIX_PTL_RECV_U32(peer->sd, pmix_globals.pindex); return PMIX_SUCCESS; } /* the "peer" object passed into this function is that of the SERVER * to which the tool is connecting - it is NOT the peer of the tool itself*/ pmix_status_t pmix_ptl_base_tool_handshake(pmix_peer_t *peer, pmix_status_t rp) { pmix_nspace_t nspace; pmix_rank_t rank; pmix_status_t reply; /* if the status indicates an error, then we are done */ if (PMIX_SUCCESS != rp) { return rp; } /* if we need an identifier, it comes next */ if (PMIX_TOOL_NEEDS_ID == peer->proc_type.flag || PMIX_LAUNCHER_NEEDS_ID == peer->proc_type.flag) { PMIX_PTL_RECV_NSPACE(peer->sd, pmix_globals.myid.nspace); PMIX_PTL_RECV_U32(peer->sd, pmix_globals.myid.rank); } /* get the server's nspace and rank so we can send to it */ if (NULL == peer->info) { peer->info = PMIX_NEW(pmix_rank_info_t); } if (NULL == peer->nptr) { peer->nptr = PMIX_NEW(pmix_namespace_t); } PMIX_PTL_RECV_NSPACE(peer->sd, nspace); PMIX_PTL_RECV_U32(peer->sd, rank); if (NULL != peer->nptr->nspace) { free(peer->nptr->nspace); } peer->nptr->nspace = strdup(nspace); if (NULL != peer->info->pname.nspace) { free(peer->info->pname.nspace); } peer->info->pname.nspace = strdup(nspace); peer->info->pname.rank = rank; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix: RECV CONNECT CONFIRMATION FOR TOOL %s:%d FROM SERVER %s:%d", pmix_globals.myid.nspace, pmix_globals.myid.rank, peer->info->pname.nspace, peer->info->pname.rank); /* get the returned status from the security handshake */ PMIX_PTL_RECV_U32(peer->sd, reply); if (PMIX_SUCCESS != reply) { /* see if they want us to do the handshake */ if (PMIX_ERR_READY_FOR_HANDSHAKE == reply) { PMIX_PSEC_CLIENT_HANDSHAKE(reply, peer, peer->sd); if (PMIX_SUCCESS != reply) { return reply; } /* if the handshake succeeded, then fall thru to the next step */ } else { return reply; } } return PMIX_SUCCESS; } static void check_server(char *filename, pmix_list_t *servers) { FILE *fp; char *srvr, *p, *p2; pmix_lock_t lock; pmix_event_t ev; struct timeval tv; int retries; pmix_info_t *sdata; size_t ndata, n; pmix_infolist_t *iptr, *ians; char *nspace = NULL, *version = NULL; pmix_rank_t rank; pmix_list_t mylist; uint32_t u32; pmix_status_t rc; /* if we cannot open the file, then the server must not * be configured to support tool connections, or this * user isn't authorized to access it - or it may just * not exist yet! Check for existence */ /* coverity[TOCTOU] */ if (0 == access(filename, R_OK)) { goto process; } else { if (ENOENT == errno) { /* the file does not exist, so give it * a little time to see if the server * is still starting up */ retries = 0; do { ++retries; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "WAITING FOR CONNECTION FILE %s", filename); PMIX_CONSTRUCT_LOCK(&lock); if (0 < pmix_ptl_base.wait_to_connect) { tv.tv_sec = pmix_ptl_base.wait_to_connect; tv.tv_usec = 0; pmix_event_evtimer_set(pmix_globals.evbase, &ev, timeout, &lock); PMIX_POST_OBJECT(&ev); pmix_event_evtimer_add(&ev, &tv); } else { tv.tv_sec = 0; tv.tv_usec = 10000; // use 0.01 sec as default pmix_event_evtimer_set(pmix_globals.evbase, &ev, timeout, &lock); PMIX_POST_OBJECT(&ev); pmix_event_evtimer_add(&ev, &tv); } PMIX_WAIT_THREAD(&lock); PMIX_DESTRUCT_LOCK(&lock); /* coverity[TOCTOU] */ if (0 == access(filename, R_OK)) { goto process; } } while (retries < pmix_ptl_base.max_retries); /* otherwise, it is unreachable */ } } return; process: fp = fopen(filename, "r"); if (NULL == fp) { return; } /* get the URI - might seem crazy, but there is actually * a race condition here where the server may have created * the file but not yet finished writing into it. So give * us a chance to get the required info */ for (retries = 0; retries < 3; retries++) { srvr = pmix_getline(fp); if (NULL != srvr) { break; } fclose(fp); tv.tv_sec = 0; tv.tv_usec = 10000; // use 0.01 sec as default pmix_event_evtimer_set(pmix_globals.evbase, &ev, timeout, &lock); PMIX_POST_OBJECT(&ev); pmix_event_evtimer_add(&ev, &tv); PMIX_WAIT_THREAD(&lock); PMIX_DESTRUCT_LOCK(&lock); fp = fopen(filename, "r"); if (NULL == fp) { return; } } if (NULL == srvr) { PMIX_ERROR_LOG(PMIX_ERR_FILE_READ_FAILURE); fclose(fp); return; } rc = pmix_ptl_base_parse_uri(srvr, &nspace, &rank, NULL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); fclose(fp); if (NULL != nspace) { free(nspace); } free(srvr); return; } /* see if we already have this server in our list */ PMIX_LIST_FOREACH (iptr, servers, pmix_infolist_t) { /* each item contains an array starting with the server nspace */ sdata = (pmix_info_t *) iptr->info.value.data.darray->array; ndata = iptr->info.value.data.darray->size; if (0 == strcmp(sdata[0].value.data.string, nspace) && sdata[1].value.data.rank == rank) { /* already have this one */ fclose(fp); free(srvr); free(nspace); return; } } /* begin collecting data for the new entry */ PMIX_CONSTRUCT(&mylist, pmix_list_t); iptr = PMIX_NEW(pmix_infolist_t); PMIX_INFO_LOAD(&iptr->info, PMIX_SERVER_NSPACE, nspace, PMIX_STRING); pmix_list_append(&mylist, &iptr->super); iptr = PMIX_NEW(pmix_infolist_t); PMIX_INFO_LOAD(&iptr->info, PMIX_SERVER_RANK, &rank, PMIX_PROC_RANK); pmix_list_append(&mylist, &iptr->super); free(srvr); free(nspace); /* see if this file contains the server's version */ p2 = pmix_getline(fp); if (NULL == p2) { version = strdup("v2.0"); pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "V20 SERVER DETECTED"); } else { version = p2; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "VERSION %s SERVER DETECTED", p2); } iptr = PMIX_NEW(pmix_infolist_t); PMIX_INFO_LOAD(&iptr->info, PMIX_VERSION_INFO, version, PMIX_STRING); pmix_list_append(&mylist, &iptr->super); free(p2); /* see if the file contains the pid */ p2 = pmix_getline(fp); if (NULL == p2) { goto complete; } u32 = strtoul(p2, NULL, 10); iptr = PMIX_NEW(pmix_infolist_t); PMIX_INFO_LOAD(&iptr->info, PMIX_SERVER_PIDINFO, &u32, PMIX_UINT32); pmix_list_append(&mylist, &iptr->super); free(p2); /* check for uid:gid */ p2 = pmix_getline(fp); if (NULL == p2) { goto complete; } /* find the colon */ if (NULL == (p = strchr(p2, ':'))) { /* bad format */ free(p2); goto complete; } *p = '\0'; ++p; u32 = strtoul(p2, NULL, 10); iptr = PMIX_NEW(pmix_infolist_t); PMIX_INFO_LOAD(&iptr->info, PMIX_USERID, &u32, PMIX_UINT32); pmix_list_append(&mylist, &iptr->super); u32 = strtoul(p, NULL, 10); iptr = PMIX_NEW(pmix_infolist_t); PMIX_INFO_LOAD(&iptr->info, PMIX_GRPID, &u32, PMIX_UINT32); pmix_list_append(&mylist, &iptr->super); free(p2); /* check for timestamp */ p2 = pmix_getline(fp); if (NULL == p2) { goto complete; } iptr = PMIX_NEW(pmix_infolist_t); PMIX_INFO_LOAD(&iptr->info, PMIX_SERVER_START_TIME, p2, PMIX_STRING); pmix_list_append(&mylist, &iptr->super); free(p2); complete: fclose(fp); /* convert the list to an array */ if (0 < (ndata = pmix_list_get_size(&mylist))) { ians = PMIX_NEW(pmix_infolist_t); PMIX_LOAD_KEY(ians->info.key, PMIX_SERVER_INFO_ARRAY); ians->info.value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(ians->info.value.data.darray, ndata, PMIX_INFO); sdata = (pmix_info_t *) ians->info.value.data.darray->array; n = 0; PMIX_LIST_FOREACH (iptr, &mylist, pmix_infolist_t) { PMIX_INFO_XFER(&sdata[n], &iptr->info); ++n; } PMIX_LIST_DESTRUCT(&mylist); pmix_list_append(servers, &ians->super); } } static void query_servers(char *dirname, pmix_list_t *servers) { char *newdir, *dname; DIR *cur_dirp, *tst; struct dirent *dir_entry; /* search the system tmpdir directory tree for files * beginning with "pmix." as these can be potential * servers */ if (NULL == dirname) { /* we first check the system tmpdir to see if a system-level * server is present */ dname = pmix_ptl_base.system_tmpdir; } else { dname = dirname; } cur_dirp = opendir(dname); if (NULL == cur_dirp) { return; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:tcp: searching directory %s", (NULL == dirname) ? pmix_ptl_base.system_tmpdir : dirname); /* search the entries for something that starts with the "pmix." prefix */ while (NULL != (dir_entry = readdir(cur_dirp))) { /* ignore the . and .. entries */ if (0 == strcmp(dir_entry->d_name, ".") || 0 == strcmp(dir_entry->d_name, "..")) { continue; } newdir = pmix_os_path(false, dname, dir_entry->d_name, NULL); /* if it is a directory, down search */ tst = opendir(newdir); if (NULL != tst) { closedir(tst); query_servers(newdir, servers); free(newdir); continue; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:tcp: checking %s", dir_entry->d_name); /* see if it starts with our prefix */ if (0 == strncmp(dir_entry->d_name, "pmix.", strlen("pmix."))) { /* try to read this file */ pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:tcp: reading file %s", newdir); check_server(newdir, servers); } free(newdir); } closedir(cur_dirp); } static void _local_relcb(void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; if (NULL != cd->info) { PMIX_INFO_FREE(cd->info, cd->ninfo); } PMIX_RELEASE(cd); } void pmix_ptl_base_query_servers(int sd, short args, void *cbdata) { pmix_query_caddy_t *cd = (pmix_query_caddy_t *) cbdata; pmix_list_t servers; size_t n; pmix_infolist_t *iptr; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_CONSTRUCT(&servers, pmix_list_t); query_servers(NULL, &servers); /* convert the list to an array of pmix_info_t */ cd->ninfo = pmix_list_get_size(&servers); if (0 == cd->ninfo) { rc = PMIX_ERR_NOT_FOUND; } else { PMIX_INFO_CREATE(cd->info, cd->ninfo); n = 0; PMIX_LIST_FOREACH (iptr, &servers, pmix_infolist_t) { PMIX_INFO_XFER(&cd->info[n], &iptr->info); ++n; } rc = PMIX_SUCCESS; } PMIX_LIST_DESTRUCT(&servers); /* execute the callback function */ cd->cbfunc(rc, cd->info, cd->ninfo, cd->cbdata, _local_relcb, cd); } static void timeout(int sd, short args, void *cbdata) { pmix_lock_t *lock = (pmix_lock_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_WAKEUP_THREAD(lock); } /* * Go through a list of argv; if there are any subnet specifications * (a.b.c.d/e), resolve them to an interface name (Currently only * supporting IPv4). If unresolvable, warn and remove. */ char **pmix_ptl_base_split_and_resolve(const char *orig_str, const char *name) { int i, ret, if_index; char **argv, **interfaces, *str; char if_name[PMIX_IF_NAMESIZE]; struct sockaddr_storage argv_inaddr, if_inaddr; uint32_t argv_prefix; bool found; /* Sanity check */ if (NULL == orig_str) { return NULL; } argv = PMIx_Argv_split(orig_str, ','); interfaces = NULL; for (i = 0; NULL != argv[i]; ++i) { if (isalpha(argv[i][0])) { /* This is an interface name. If not already in the interfaces array, add it */ PMIx_Argv_append_unique_nosize(&interfaces, argv[i]); pmix_output_verbose(20, pmix_ptl_base_framework.framework_output, "ptl:tool: Using interface: %s ", argv[i]); continue; } /* Found a subnet notation. Convert it to an IP address/netmask. Get the prefix first. */ argv_prefix = 0; str = strchr(argv[i], '/'); if (NULL == str) { pmix_show_help("help-ptl-base.txt", "invalid if_inexclude", true, name, pmix_globals.hostname, argv[i], "Invalid specification (missing \"/\")"); continue; } *str = '\0'; argv_prefix = atoi(str + 1); /* Now convert the IPv4 address */ ((struct sockaddr *) &argv_inaddr)->sa_family = AF_INET; ret = inet_pton(AF_INET, argv[i], &((struct sockaddr_in *) &argv_inaddr)->sin_addr); *str = '/'; if (1 != ret) { pmix_show_help("help-ptl-base.txt", "invalid if_inexclude", true, name, pmix_globals.hostname, argv[i], "Invalid specification (inet_pton() failed)"); continue; } pmix_output_verbose(20, pmix_ptl_base_framework.framework_output, "ptl:base: Searching for %s address+prefix: %s / %u", name, pmix_net_get_hostname((struct sockaddr *) &argv_inaddr), argv_prefix); /* Go through all interfaces and see if we can find a match */ found = false; for (if_index = pmix_ifbegin(); if_index >= 0; if_index = pmix_ifnext(if_index)) { pmix_ifindextoaddr(if_index, (struct sockaddr*) &if_inaddr, sizeof(if_inaddr)); if (pmix_net_samenetwork(&argv_inaddr, &if_inaddr, argv_prefix)) { /* We found a match. If it's not already in the interfaces array, add it. If it's already in the array, treat it as a match */ found = true; pmix_ifindextoname(if_index, if_name, sizeof(if_name)); PMIx_Argv_append_unique_nosize(&interfaces, if_name); pmix_output_verbose(20, pmix_ptl_base_framework.framework_output, "ptl:base: Found match: %s (%s)", pmix_net_get_hostname((struct sockaddr*) &if_inaddr), if_name); } } /* If we didn't find a match, report it but keep trying */ if (!found) { pmix_show_help("help-ptl-base.txt", "invalid if_inexclude", true, name, pmix_globals.hostname, argv[i], "Did not find interface matching this subnet"); } } PMIx_Argv_free(argv); return interfaces; } char *pmix_ptl_base_peer_type(pmix_peer_t *peer) { char **types = NULL; char *ans; if (PMIX_PEER_IS_CLIENT(peer)) { PMIx_Argv_append_nosize(&types, "CLIENT"); } if (PMIX_PEER_IS_SINGLETON(peer)) { PMIx_Argv_append_nosize(&types, "SINGLETON"); } if (PMIX_PEER_IS_SERVER(peer)) { PMIx_Argv_append_nosize(&types, "SERVER"); } if (PMIX_PEER_IS_TOOL(peer)) { PMIx_Argv_append_nosize(&types, "TOOL"); } if (PMIX_PEER_IS_LAUNCHER(peer)) { PMIx_Argv_append_nosize(&types, "LAUNCHER"); } if (PMIX_PEER_IS_GATEWAY(peer)) { PMIx_Argv_append_nosize(&types, "GATEWAY"); } if (PMIX_PEER_IS_SCHEDULER(peer)) { PMIx_Argv_append_nosize(&types, "SCHEDULER"); } if (PMIX_PEER_IS_SYS_CTRLR(peer)) { PMIx_Argv_append_nosize(&types, "SYSCTRLR"); } ans = PMIx_Argv_join(types, ','); PMIx_Argv_free(types); return ans; } pmix-6.1.1~rc2/src/mca/ptl/base/base.h0000664000175000017500000001663715203536752017635 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PTL_BASE_H_ #define PMIX_PTL_BASE_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_pointer_array.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/mca.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_stdatomic.h" #include "src/mca/ptl/base/ptl_base_handshake.h" #include "src/mca/ptl/ptl.h" BEGIN_C_DECLS /* * MCA Framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_ptl_base_framework; /** * PTL select function * * Cycle across available components and construct the list * of active modules */ PMIX_EXPORT pmix_status_t pmix_ptl_base_select(void); /* framework globals */ struct pmix_ptl_base_t { bool initialized; bool selected; pmix_list_t posted_recvs; // list of pmix_ptl_posted_recv_t pmix_list_t unexpected_msgs; pmix_listener_t listener; struct sockaddr_storage *connection; size_t max_msg_size; char *session_tmpdir; char *system_tmpdir; char *report_uri; char *uri; char *urifile; char *sysctrlr_filename; char *scheduler_filename; char *system_filename; char *session_filename; char *nspace_filename; char *pid_filename; char *rendezvous_filename; bool created_rendezvous_dir; bool created_rendezvous_file; bool created_session_tmpdir; bool created_system_tmpdir; bool created_sysctrlr_filename; bool created_scheduler_filename; bool created_system_filename; bool created_session_filename; bool created_nspace_filename; bool created_pid_filename; bool created_urifile; bool remote_connections; bool connections_specified; bool system_tool; bool allow_foreign_tools; bool session_tool; bool tool_support; char *if_include; char *if_exclude; char **ipv4_ports; bool disable_ipv4_family; char **ipv6_ports; bool disable_ipv6_family; int max_retries; int wait_to_connect; int handshake_wait_time; int handshake_max_retries; }; typedef struct pmix_ptl_base_t pmix_ptl_base_t; PMIX_EXPORT extern pmix_ptl_base_t pmix_ptl_base; typedef struct { pmix_list_item_t super; int sd; char *nspace; pmix_rank_t rank; char *uri; char *version; } pmix_connection_t; PMIX_CLASS_DECLARATION(pmix_connection_t); /* API stubs */ PMIX_EXPORT pmix_status_t pmix_ptl_base_set_notification_cbfunc(pmix_ptl_cbfunc_t cbfunc); PMIX_EXPORT pmix_status_t pmix_ptl_base_connect_to_peer(struct pmix_peer_t *peer, pmix_info_t info[], size_t ninfo, char **suri); PMIX_EXPORT pmix_status_t pmix_ptl_base_parse_uri_file(char *filename, bool optional, pmix_list_t *connections); PMIX_EXPORT pmix_status_t pmix_ptl_base_setup_connection(char *uri, struct sockaddr_storage *connection, size_t *len); PMIX_EXPORT pmix_status_t pmix_ptl_base_start_listening(pmix_info_t info[], size_t ninfo); PMIX_EXPORT void pmix_ptl_base_stop_listening(void); /* base support functions */ PMIX_EXPORT pmix_status_t pmix_ptl_base_setup_fork(const pmix_proc_t *proc, char ***env); PMIX_EXPORT void pmix_ptl_base_send_handler(int sd, short flags, void *cbdata); PMIX_EXPORT void pmix_ptl_base_recv_handler(int sd, short flags, void *cbdata); PMIX_EXPORT void pmix_ptl_base_process_msg(int fd, short flags, void *cbdata); PMIX_EXPORT pmix_status_t pmix_ptl_base_set_nonblocking(int sd); PMIX_EXPORT pmix_status_t pmix_ptl_base_set_blocking(int sd); PMIX_EXPORT pmix_status_t pmix_ptl_base_send_blocking(int sd, char *ptr, size_t size); PMIX_EXPORT pmix_status_t pmix_ptl_base_recv_blocking(int sd, char *data, size_t size); PMIX_EXPORT pmix_status_t pmix_ptl_base_connect(struct sockaddr_storage *addr, pmix_socklen_t len, int *fd); PMIX_EXPORT void pmix_ptl_base_connection_handler(int sd, short args, void *cbdata); PMIX_EXPORT pmix_status_t pmix_ptl_base_setup_listener(pmix_info_t info[], size_t ninfo); PMIX_EXPORT pmix_status_t pmix_ptl_base_send_connect_ack(int sd); PMIX_EXPORT pmix_status_t pmix_ptl_base_recv_connect_ack(int sd); PMIX_EXPORT void pmix_ptl_base_lost_connection(pmix_peer_t *peer, pmix_status_t err); PMIX_EXPORT bool pmix_ptl_base_peer_is_earlier(pmix_peer_t *peer, uint8_t major, uint8_t minor, uint8_t release); PMIX_EXPORT void pmix_ptl_base_query_servers(int sd, short args, void *cbdata); PMIX_EXPORT pmix_status_t pmix_ptl_base_parse_uri(const char *evar, char **nspace, pmix_rank_t *rank, char **suri); PMIX_EXPORT pmix_status_t pmix_ptl_base_df_search(char *dirname, char *prefix, pmix_info_t info[], size_t ninfo, bool optional, pmix_list_t *connections); PMIX_EXPORT pmix_rnd_flag_t pmix_ptl_base_set_flag(size_t *sz); PMIX_EXPORT pmix_status_t pmix_ptl_base_make_connection(pmix_peer_t *peer, char *suri, pmix_info_t *iptr, size_t niptr); PMIX_EXPORT void pmix_ptl_base_complete_connection(pmix_peer_t *peer, char *nspace, pmix_rank_t rank); PMIX_EXPORT pmix_status_t pmix_ptl_base_set_timeout(pmix_peer_t *peer, struct timeval *save, pmix_socklen_t *sz, bool *sockopt); PMIX_EXPORT void pmix_ptl_base_setup_socket(pmix_peer_t *peer); PMIX_EXPORT pmix_status_t pmix_ptl_base_client_handshake(pmix_peer_t *peer, pmix_status_t reply); PMIX_EXPORT pmix_status_t pmix_ptl_base_tool_handshake(pmix_peer_t *peer, pmix_status_t rp); PMIX_EXPORT char **pmix_ptl_base_split_and_resolve(const char *orig_str, const char *name); PMIX_EXPORT pmix_status_t pmix_ptl_base_set_peer(pmix_peer_t *peer, char **evar); PMIX_EXPORT char *pmix_ptl_base_get_cmd_line(void); PMIX_EXPORT char *pmix_ptl_base_peer_type(pmix_peer_t *peer); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/ptl/base/usock.h0000664000175000017500000000423715203536752020040 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef USOCK_H #define USOCK_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_types.h" #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_NET_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include /* usock common variables */ typedef struct { } pmix_usock_globals_t; extern pmix_usock_globals_t pmix_usock_globals; /* usock common functions */ void pmix_usock_init(pmix_usock_cbfunc_t cbfunc); void pmix_usock_finalize(void); #endif // USOCK_H pmix-6.1.1~rc2/src/mca/ptl/base/ptl_base_stubs.c0000664000175000017500000000734415203536752021722 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/mca/ptl/base/base.h" bool pmix_ptl_base_peer_is_earlier(pmix_peer_t *peer, uint8_t major, uint8_t minor, uint8_t release) { if (0 == PMIX_PEER_MAJOR_VERSION(peer)) { /* the peer's version was never assigned. This happens * when the application never calls PMIx_Init - we * cannot assign the version because the client never * told us what they are using. Normally, this indicates * that the application is not a PMIx one. All we can do * is assume the peer is NOT earlier */ return false; } /* if they don't care, then don't check */ if (PMIX_MAJOR_WILDCARD != major) { if (PMIX_PEER_MAJOR_VERSION(peer) == PMIX_MAJOR_WILDCARD) { /* we don't know what it is - assume earlier */ return true; } if (PMIX_PEER_MAJOR_VERSION(peer) > major) { return false; } if (PMIX_PEER_MAJOR_VERSION(peer) < major) { return true; } } /* major value must be equal, so check minor */ if (PMIX_MINOR_WILDCARD != minor) { if (PMIX_PEER_MINOR_VERSION(peer) == PMIX_MINOR_WILDCARD) { /* we don't know what it is - assume earlier */ return true; } if (PMIX_PEER_MINOR_VERSION(peer) > minor) { return false; } if (PMIX_PEER_MINOR_VERSION(peer) < minor) { return true; } } /* major and minor must be equal - check release */ if (PMIX_RELEASE_WILDCARD != release) { if (PMIX_PEER_REL_VERSION(peer) == PMIX_RELEASE_WILDCARD) { /* we don't know what it is - assume earlier */ return true; } if (PMIX_PEER_REL_VERSION(peer) > release) { return false; } if (PMIX_PEER_REL_VERSION(peer) < release) { return true; } } /* must be equal */ return false; } pmix_status_t pmix_ptl_base_set_notification_cbfunc(pmix_ptl_cbfunc_t cbfunc) { pmix_ptl_posted_recv_t *req; /* post a persistent recv for the special 0 tag so the client can recv * error notifications from the server */ req = PMIX_NEW(pmix_ptl_posted_recv_t); if (NULL == req) { return PMIX_ERR_NOMEM; } req->tag = 0; req->cbfunc = cbfunc; pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "posting notification recv on tag %d", req->tag); /* add it to the list of recvs - we cannot have unexpected messages * in this subsystem as the server never sends us something that * we didn't previously request */ pmix_list_prepend(&pmix_ptl_base.posted_recvs, &req->super); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/ptl/base/Makefile.include0000664000175000017500000000271715203536752021626 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.include does not stand on its own - it is included from # src/Makefile.am EXTRA_DIST = base/help-ptl-base.txt headers += \ base/base.h \ base/ptl_base_handshake.h sources += \ base/ptl_base_frame.c \ base/ptl_base_select.c \ base/ptl_base_sendrecv.c \ base/ptl_base_listener.c \ base/ptl_base_stubs.c \ base/ptl_base_connect.c \ base/ptl_base_fns.c \ base/ptl_base_connection_hdlr.c pmix-6.1.1~rc2/src/mca/ptl/base/ptl_base_sendrecv.c0000664000175000017500000010614115203536752022366 0ustar alastairalastair/* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include "src/class/pmix_pointer_array.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" #include "src/mca/psensor/psensor.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_show_help.h" #include "src/mca/ptl/base/base.h" static void _notify_complete(pmix_status_t status, void *cbdata) { (void) status; pmix_event_chain_t *chain = (pmix_event_chain_t *) cbdata; PMIX_RELEASE(chain); } static void lost_connection(pmix_peer_t *peer) { pmix_server_trkr_t *trk, *tnxt; pmix_server_caddy_t *rinfo, *rnext; pmix_ptl_posted_recv_t *rcv; pmix_buffer_t buf; pmix_ptl_hdr_t hdr; pmix_status_t rc; bool flag; size_t n; /* stop all events */ if (peer->recv_ev_active) { pmix_event_del(&peer->recv_event); peer->recv_ev_active = false; } if (peer->send_ev_active) { pmix_event_del(&peer->send_event); peer->send_ev_active = false; } if (NULL != peer->recv_msg) { PMIX_RELEASE(peer->recv_msg); peer->recv_msg = NULL; } CLOSE_THE_SOCKET(peer->sd); if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { /* if I am a server, then we need to ensure that * we properly account for the loss of this client * from any local collectives in which it was * participating - note that the proc would not * have been added to any collective tracker until * after it successfully connected */ PMIX_LIST_FOREACH_SAFE (trk, tnxt, &pmix_server_globals.collectives, pmix_server_trkr_t) { /* check if the process should be participating in this collective */ flag = false; for (n=0; n < trk->npcs; n++) { if (PMIX_CHECK_NAMES(&trk->pcs[n], &peer->info->pname)) { flag = true; break; } } if (!flag) { continue; } /* it should - adjust the count */ --trk->nlocal; if (0 < trk->nlocal) { rc = PMIX_ERR_PARTIAL_SUCCESS; } else { rc = PMIX_ERR_LOST_CONNECTION; } PMIX_INFO_LOAD(&trk->info[trk->ninfo-1], PMIX_LOCAL_COLLECTIVE_STATUS, &rc, PMIX_STATUS); /* see if it already participated in this tracker */ PMIX_LIST_FOREACH_SAFE (rinfo, rnext, &trk->local_cbs, pmix_server_caddy_t) { if (!PMIX_CHECK_NAMES(&rinfo->peer->info->pname, &peer->info->pname)) { continue; } /* remove it from the list */ pmix_list_remove_item(&trk->local_cbs, &rinfo->super); PMIX_RELEASE(rinfo); } /* if the host has already been called for this tracker, * then do nothing here - just wait for the host to return * from the operation */ if (trk->host_called) { continue; } /* are we now locally complete? */ if (trk->def_complete && trk->nlocal == pmix_list_get_size(&trk->local_cbs)) { /* if this is a local-only collective, then resolve it now */ if (trk->local) { /* everyone else has called in - we need to let them know * that this proc has disappeared * as otherwise the collective will never complete */ if (PMIX_FENCENB_CMD == trk->type) { if (NULL != trk->modexcbfunc) { trk->modexcbfunc(rc, NULL, 0, trk, NULL, NULL); } } else if (PMIX_CONNECTNB_CMD == trk->type) { if (NULL != trk->op_cbfunc) { trk->op_cbfunc(rc, trk); } } else if (PMIX_DISCONNECTNB_CMD == trk->type) { if (NULL != trk->op_cbfunc) { trk->op_cbfunc(rc, trk); } } else if (PMIX_GROUP_CONSTRUCT_CMD == trk->type) { if (NULL != trk->op_cbfunc) { trk->op_cbfunc(rc, trk); } } } else { /* if the host has not been called, then we need to pass the call * up to the host as otherwise the global collective will hang */ if (PMIX_FENCENB_CMD == trk->type) { trk->host_called = true; rc = pmix_host_server.fence_nb(trk->pcs, trk->npcs, trk->info, trk->ninfo, NULL, 0, trk->modexcbfunc, trk); if (PMIX_SUCCESS != rc) { pmix_list_remove_item(&pmix_server_globals.collectives, &trk->super); PMIX_RELEASE(trk); } } else if (PMIX_CONNECTNB_CMD == trk->type) { trk->host_called = true; rc = pmix_host_server.connect(trk->pcs, trk->npcs, trk->info, trk->ninfo, trk->op_cbfunc, trk); if (PMIX_SUCCESS != rc) { pmix_list_remove_item(&pmix_server_globals.collectives, &trk->super); PMIX_RELEASE(trk); } } else if (PMIX_DISCONNECTNB_CMD == trk->type) { trk->host_called = true; rc = pmix_host_server.disconnect(trk->pcs, trk->npcs, trk->info, trk->ninfo, trk->op_cbfunc, trk); if (PMIX_SUCCESS != rc) { pmix_list_remove_item(&pmix_server_globals.collectives, &trk->super); PMIX_RELEASE(trk); } } } } } /* if the peer simply died without finalizing, * then reduce the number of local procs */ if (!peer->finalized && 0 < peer->nptr->nlocalprocs) { --peer->nptr->nlocalprocs; } /* purge any notifications cached for this client */ pmix_server_purge_events(peer, NULL); if (PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { /* only connection I can lose is to my server, so mark it */ pmix_atomic_unset_bool(&pmix_globals.connected); } else { /* cleanup any sensors that are monitoring them */ pmix_psensor.stop(peer, NULL); } if (!pmix_globals.mypeer->finalized) { /* if the peer is a tool, then we always generate the * lost connection event so that the host can know the * tool departed */ if (PMIX_PEER_IS_TOOL(peer) && !PMIX_PEER_IS_CLIENT(peer)) { PMIX_REPORT_EVENT(PMIX_ERR_LOST_CONNECTION, peer, PMIX_RANGE_PROC_LOCAL, _notify_complete); } else if (!peer->finalized) { /* if this peer already called finalize, then * we are just seeing their connection go away * when they terminate - so do not generate * an event. If an abnormal termination, then we do */ PMIX_REPORT_EVENT(PMIX_ERR_LOST_CONNECTION, peer, PMIX_RANGE_PROC_LOCAL, _notify_complete); } } } else if (peer == pmix_client_globals.myserver) { /* if this was the server to which I am connected, * then we need to exit */ pmix_atomic_unset_bool(&pmix_globals.connected); /* it is possible that we have sendrecv's in progress where * we are waiting for a response to arrive. Since we have * lost connection to the server, that will never happen. * Thus, to preclude any chance of hanging, cycle thru * the list of posted recvs and complete any that are * the return call from a sendrecv - i.e., any that are * waiting on dynamic tags */ PMIX_CONSTRUCT(&buf, pmix_buffer_t); /* must set the buffer type so it doesn't fail in unpack */ buf.type = pmix_client_globals.myserver->nptr->compat.type; hdr.nbytes = 0; // initialize the hdr to something safe PMIX_LIST_FOREACH (rcv, &pmix_ptl_base.posted_recvs, pmix_ptl_posted_recv_t) { if (UINT_MAX != rcv->tag && NULL != rcv->cbfunc) { /* construct and load the buffer */ hdr.tag = rcv->tag; rcv->cbfunc(pmix_globals.mypeer, &hdr, &buf, rcv->cbdata); } } PMIX_DESTRUCT(&buf); /* if I called finalize, then don't generate an event */ if (!pmix_globals.mypeer->finalized) { PMIX_REPORT_EVENT(PMIX_ERR_LOST_CONNECTION, pmix_client_globals.myserver, PMIX_RANGE_PROC_LOCAL, _notify_complete); } } } static pmix_status_t send_msg(int sd, pmix_ptl_send_t *msg) { struct iovec iov[2]; int iov_count; ssize_t remain = msg->sdbytes, rc; iov[0].iov_base = msg->sdptr; iov[0].iov_len = msg->sdbytes; if (!msg->hdr_sent && NULL != msg->data) { iov[1].iov_base = msg->data->base_ptr; iov[1].iov_len = ntohl(msg->hdr.nbytes); remain += ntohl(msg->hdr.nbytes); iov_count = 2; } else { iov_count = 1; } retry: rc = writev(sd, iov, iov_count); if (PMIX_LIKELY(rc == remain)) { /* we successfully sent the header and the msg data if any */ msg->hdr_sent = true; msg->sdbytes = 0; msg->sdptr = (char *) iov[iov_count - 1].iov_base + iov[iov_count - 1].iov_len; return PMIX_SUCCESS; } else if (rc < 0) { if (pmix_socket_errno == EINTR) { goto retry; } else if (pmix_socket_errno == EAGAIN) { /* tell the caller to keep this message on active, * but let the event lib cycle so other messages * can progress while this socket is busy */ return PMIX_ERR_RESOURCE_BUSY; } else if (pmix_socket_errno == EWOULDBLOCK) { /* tell the caller to keep this message on active, * but let the event lib cycle so other messages * can progress while this socket is busy */ return PMIX_ERR_WOULD_BLOCK; } else { /* we hit an error and cannot progress this message */ pmix_output(0, "pmix_ptl_base: send_msg: write failed: %s (%d) [sd = %d]", strerror(pmix_socket_errno), pmix_socket_errno, sd); return PMIX_ERR_UNREACH; } } else { /* short writev. This usually means the kernel buffer is full, * so there is no point for retrying at that time. * simply update the msg and return with PMIX_ERR_RESOURCE_BUSY */ if ((size_t) rc < msg->sdbytes) { /* partial write of the header or the msg data */ msg->sdptr = (char *) msg->sdptr + rc; msg->sdbytes -= rc; } else { /* header was fully written, but only a part of the msg data was written */ msg->hdr_sent = true; rc -= msg->sdbytes; if (NULL != msg->data) { /* technically, this should never happen as iov_count * would be 1 for a zero-byte message, and so we cannot * have a case where we write the header and part of the * msg. However, code checkers don't know that and are * fooled by our earlier check for NULL, and so * we silence their warnings by using this check */ msg->sdptr = (char *) msg->data->base_ptr + rc; } msg->sdbytes = ntohl(msg->hdr.nbytes) - rc; } return PMIX_ERR_RESOURCE_BUSY; } } static pmix_status_t read_bytes(int sd, char **buf, size_t *remain) { pmix_status_t ret = PMIX_SUCCESS; int rc; char *ptr = *buf; /* read until all bytes recvd or error */ while (0 < *remain) { rc = read(sd, ptr, *remain); if (rc < 0) { if (pmix_socket_errno == EINTR) { continue; } else if (pmix_socket_errno == EAGAIN) { /* tell the caller to keep this message on active, * but let the event lib cycle so other messages * can progress while this socket is busy */ ret = PMIX_ERR_RESOURCE_BUSY; goto exit; } else if (pmix_socket_errno == EWOULDBLOCK) { /* tell the caller to keep this message on active, * but let the event lib cycle so other messages * can progress while this socket is busy */ ret = PMIX_ERR_WOULD_BLOCK; goto exit; } /* we hit an error and cannot progress this message - report * the error back to the RML and let the caller know * to abort this message */ pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix_ptl_base_msg_recv: readv failed: %s (%d)", strerror(pmix_socket_errno), pmix_socket_errno); ret = PMIX_ERR_UNREACH; goto exit; } else if (0 == rc) { /* the remote peer closed the connection */ ret = PMIX_ERR_UNREACH; goto exit; } /* we were able to read something, so adjust counters and location */ *remain -= rc; ptr += rc; } /* we read the full data block */ exit: *buf = ptr; return ret; } /* * A file descriptor is available/ready for send. Check the state * of the socket and take the appropriate action. */ void pmix_ptl_base_send_handler(int sd, short flags, void *cbdata) { pmix_peer_t *peer = (pmix_peer_t *) cbdata; pmix_ptl_send_t *msg = peer->send_msg; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, flags); /* acquire the object */ PMIX_ACQUIRE_OBJECT(peer); pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "%s ptl:base:send_handler SENDING TO PEER %s tag %u with %s msg", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_PNAME_PRINT(&peer->info->pname), (NULL == msg) ? UINT_MAX : ntohl(msg->hdr.tag), (NULL == msg) ? "NULL" : "NON-NULL"); if (NULL != msg) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:base:send_handler SENDING MSG TO %s TAG %u", PMIX_PNAME_PRINT(&peer->info->pname), ntohl(msg->hdr.tag)); if (PMIX_SUCCESS == (rc = send_msg(peer->sd, msg))) { // message is complete pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:base:send_handler MSG SENT"); PMIX_RELEASE(msg); peer->send_msg = NULL; } else if (PMIX_ERR_RESOURCE_BUSY == rc || PMIX_ERR_WOULD_BLOCK == rc) { /* exit this event and let the event lib progress */ pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:base:send_handler RES BUSY OR WOULD BLOCK"); /* ensure we post the modified peer object before another thread * picks it back up */ PMIX_POST_OBJECT(peer); return; } else { pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "%s SEND ERROR %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIx_Error_string(rc)); // report the error pmix_event_del(&peer->send_event); peer->send_ev_active = false; PMIX_RELEASE(msg); peer->send_msg = NULL; lost_connection(peer); /* ensure we post the modified peer object before another thread * picks it back up */ PMIX_POST_OBJECT(peer); return; } /* if current message completed - progress any pending sends by * moving the next in the queue into the "on-deck" position. Note * that this doesn't mean we send the message right now - we will * wait for another send_event to fire before doing so. This gives * us a chance to service any pending recvs. */ peer->send_msg = (pmix_ptl_send_t *) pmix_list_remove_first(&peer->send_queue); } /* if nothing else to do unregister for send event notifications */ if (NULL == peer->send_msg && peer->send_ev_active) { pmix_event_del(&peer->send_event); peer->send_ev_active = false; } /* ensure we post the modified peer object before another thread * picks it back up */ PMIX_POST_OBJECT(peer); } /* * Dispatch to the appropriate action routine based on the state * of the connection with the peer. */ void pmix_ptl_base_recv_handler(int sd, short flags, void *cbdata) { pmix_status_t rc; pmix_peer_t *peer = (pmix_peer_t *) cbdata; pmix_ptl_recv_t *msg = NULL; pmix_ptl_hdr_t hdr; size_t nbytes; char *ptr; PMIX_HIDE_UNUSED_PARAMS(flags); /* acquire the object */ PMIX_ACQUIRE_OBJECT(peer); pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "%s ptl:base:recv:handler called with peer %s:%u", PMIX_NAME_PRINT(&pmix_globals.myid), (NULL == peer) ? "NULL" : peer->info->pname.nspace, (NULL == peer) ? PMIX_RANK_UNDEF : peer->info->pname.rank); if (NULL == peer) { return; } /* allocate a new message and setup for recv */ if (NULL == peer->recv_msg) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:base:recv:handler allocate new recv msg"); peer->recv_msg = PMIX_NEW(pmix_ptl_recv_t); if (NULL == peer->recv_msg) { pmix_output(0, "sptl:base:recv_handler: unable to allocate recv message\n"); goto err_close; } PMIX_RETAIN(peer); peer->recv_msg->peer = peer; // provide a handle back to the peer object /* start by reading the header */ peer->recv_msg->rdptr = (char *) &peer->recv_msg->hdr; peer->recv_msg->rdbytes = sizeof(pmix_ptl_hdr_t); } msg = peer->recv_msg; msg->sd = sd; /* if the header hasn't been completely read, read it */ if (!msg->hdr_recvd) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:base:recv:handler read hdr on socket %d", peer->sd); nbytes = sizeof(pmix_ptl_hdr_t); ptr = (char *) &hdr; if (PMIX_SUCCESS == (rc = read_bytes(peer->sd, &ptr, &nbytes))) { /* completed reading the header */ peer->recv_msg->hdr_recvd = true; /* convert the hdr to host format */ peer->recv_msg->hdr.pindex = ntohl(hdr.pindex); peer->recv_msg->hdr.tag = ntohl(hdr.tag); peer->recv_msg->hdr.nbytes = ntohl(hdr.nbytes); pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "%s RECVD MSG FROM %s FOR TAG %d SIZE %d", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_PNAME_PRINT(&peer->info->pname), (int) peer->recv_msg->hdr.tag, (int) peer->recv_msg->hdr.nbytes); /* if this is a zero-byte message, then we are done */ if (0 == peer->recv_msg->hdr.nbytes) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "%s RECVD ZERO-BYTE MESSAGE FROM %s for tag %d", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_PNAME_PRINT(&peer->info->pname), peer->recv_msg->hdr.tag); peer->recv_msg->data = NULL; // make sure peer->recv_msg->rdptr = NULL; peer->recv_msg->rdbytes = 0; /* post it for delivery */ PMIX_ACTIVATE_POST_MSG(peer->recv_msg); peer->recv_msg = NULL; PMIX_POST_OBJECT(peer); return; } else { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:base:recv:handler allocate data region of size %lu", (unsigned long) peer->recv_msg->hdr.nbytes); /* allocate the data region */ if (pmix_ptl_base.max_msg_size < peer->recv_msg->hdr.nbytes) { pmix_show_help("help-pmix-runtime.txt", "ptl:msg_size", true, (unsigned long) peer->recv_msg->hdr.nbytes, (unsigned long) pmix_ptl_base.max_msg_size); goto err_close; } peer->recv_msg->data = (char *) malloc(peer->recv_msg->hdr.nbytes); memset(peer->recv_msg->data, 0, peer->recv_msg->hdr.nbytes); /* point to it */ peer->recv_msg->rdptr = peer->recv_msg->data; peer->recv_msg->rdbytes = peer->recv_msg->hdr.nbytes; } /* fall thru and attempt to read the data */ } else if (PMIX_ERR_RESOURCE_BUSY == rc || PMIX_ERR_WOULD_BLOCK == rc) { /* exit this event and let the event lib progress */ return; } else { /* the remote peer closed the connection - report that condition * and let the caller know */ pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "%s ptl:base:msg_recv: peer %s closed connection", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_PNAME_PRINT(&peer->info->pname)); goto err_close; } } if (peer->recv_msg->hdr_recvd) { /* continue to read the data block - we start from * wherever we left off, which could be at the * beginning or somewhere in the message */ if (PMIX_SUCCESS == (rc = read_bytes(peer->sd, &msg->rdptr, &msg->rdbytes))) { /* we recvd all of the message */ pmix_output_verbose( 2, pmix_ptl_base_framework.framework_output, "%s:%d RECVD COMPLETE MESSAGE FROM SERVER OF %d BYTES FOR TAG %d ON PEER SOCKET %d", pmix_globals.myid.nspace, pmix_globals.myid.rank, (int) peer->recv_msg->hdr.nbytes, peer->recv_msg->hdr.tag, peer->sd); /* post it for delivery */ PMIX_ACTIVATE_POST_MSG(peer->recv_msg); peer->recv_msg = NULL; /* ensure we post the modified peer object before another thread * picks it back up */ PMIX_POST_OBJECT(peer); return; } else if (PMIX_ERR_RESOURCE_BUSY == rc || PMIX_ERR_WOULD_BLOCK == rc) { /* exit this event and let the event lib progress */ /* ensure we post the modified peer object before another thread * picks it back up */ PMIX_POST_OBJECT(peer); return; } else { /* the remote peer closed the connection - report that condition * and let the caller know */ pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "%s:%d ptl:base:msg_recv: peer %s:%d closed connection", pmix_globals.myid.nspace, pmix_globals.myid.rank, peer->nptr->nspace, peer->info->pname.rank); goto err_close; } } /* success */ return; err_close: /* stop all events */ if (peer->recv_ev_active) { pmix_event_del(&peer->recv_event); peer->recv_ev_active = false; } if (peer->send_ev_active) { pmix_event_del(&peer->send_event); peer->send_ev_active = false; } if (NULL != peer->recv_msg) { PMIX_RELEASE(peer->recv_msg); peer->recv_msg = NULL; } lost_connection(peer); /* ensure we post the modified peer object before another thread * picks it back up */ PMIX_POST_OBJECT(peer); } void pmix_ptl_base_send(int sd, short args, void *cbdata) { pmix_ptl_queue_t *queue = (pmix_ptl_queue_t *) cbdata; pmix_ptl_send_t *snd; pmix_ptl_recv_t *msg; PMIX_HIDE_UNUSED_PARAMS(sd, args); /* acquire the object */ PMIX_ACQUIRE_OBJECT(queue); if (NULL == queue->peer || NULL == queue->peer->info || NULL == queue->peer->nptr) { /* we don't know this peer */ if (NULL != queue->buf) { PMIX_RELEASE(queue->buf); } PMIX_RELEASE(queue); return; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "[%s:%d] send to %s:%u of size %u on tag %d", __FILE__, __LINE__, (queue->peer)->info->pname.nspace, (queue->peer)->info->pname.rank, (NULL == queue->buf) ? 0 : (unsigned) queue->buf->bytes_used, (queue->tag)); if (NULL == queue->buf) { /* nothing to send? */ PMIX_RELEASE(queue); return; } /* is this a send to myself? */ if (queue->peer == pmix_globals.mypeer) { /* just push it to the matching code */ msg = PMIX_NEW(pmix_ptl_recv_t); PMIX_RETAIN(queue->peer); msg->peer = queue->peer; msg->hdr.pindex = pmix_globals.pindex; msg->hdr.tag = queue->tag; if (NULL != queue->buf) { msg->hdr.nbytes = (queue->buf)->bytes_used; msg->data = (queue->buf)->base_ptr; (queue->buf)->base_ptr = NULL; (queue->buf)->bytes_used = 0; PMIX_RELEASE(queue->buf); } PMIX_ACTIVATE_POST_MSG(msg); PMIX_RELEASE(queue); return; } /* do we have a live connection? */ if (queue->peer->sd < 0) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "%s no connection", PMIX_NAME_PRINT(&pmix_globals.myid)); if (NULL != queue->buf) { PMIX_RELEASE(queue->buf); } PMIX_RELEASE(queue); return; } snd = PMIX_NEW(pmix_ptl_send_t); snd->hdr.pindex = htonl(pmix_globals.pindex); snd->hdr.tag = htonl(queue->tag); snd->hdr.nbytes = htonl((queue->buf)->bytes_used); snd->data = (queue->buf); /* always start with the header */ snd->sdptr = (char *) &snd->hdr; snd->sdbytes = sizeof(pmix_ptl_hdr_t); /* if there is no message on-deck, put this one there */ if (NULL == (queue->peer)->send_msg) { (queue->peer)->send_msg = snd; } else { /* add it to the queue */ pmix_list_append(&(queue->peer)->send_queue, &snd->super); } /* ensure the send event is active */ if (!(queue->peer)->send_ev_active) { (queue->peer)->send_ev_active = true; PMIX_POST_OBJECT(queue->peer); pmix_event_add(&(queue->peer)->send_event, 0); } PMIX_RELEASE(queue); PMIX_POST_OBJECT(snd); } void pmix_ptl_base_send_recv(int fd, short args, void *cbdata) { pmix_ptl_sr_t *ms = (pmix_ptl_sr_t *) cbdata; pmix_ptl_posted_recv_t *req; pmix_ptl_send_t *snd; uint32_t tag; pmix_ptl_recv_t *msg; PMIX_HIDE_UNUSED_PARAMS(fd, args); /* acquire the object */ PMIX_ACQUIRE_OBJECT(ms); if (NULL == ms->peer || ms->peer->sd < 0 || NULL == ms->peer->info || NULL == ms->peer->nptr) { /* this peer has lost connection */ if (NULL != ms->bfr) { PMIX_RELEASE(ms->bfr); } PMIX_RELEASE(ms); return; } if (NULL == ms->bfr) { /* nothing to send? */ PMIX_RELEASE(ms); return; } /* take the next tag in the sequence of tags for this peer */ ms->peer->dyn_tags_current++; if (ms->peer->dyn_tags_current == ms->peer->dyn_tags_end) { ms->peer->dyn_tags_current = ms->peer->dyn_tags_start; } tag = ms->peer->dyn_tags_current; if (NULL != ms->cbfunc) { /* if a callback msg is expected, setup a recv for it */ req = PMIX_NEW(pmix_ptl_posted_recv_t); req->peer = ms->peer; req->tag = tag; req->cbfunc = ms->cbfunc; req->cbdata = ms->cbdata; pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "posting recv on tag %d", req->tag); /* add it to the list of recvs - we cannot have unexpected messages * in this subsystem as the server never sends us something that * we didn't previously request */ pmix_list_prepend(&pmix_ptl_base.posted_recvs, &req->super); } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "QUEUEING MSG TO SERVER %s ON SOCKET %d OF SIZE %d", PMIX_PNAME_PRINT(&ms->peer->info->pname), ms->peer->sd, (int) ms->bfr->bytes_used); /* is this a send to myself? */ if (ms->peer == pmix_globals.mypeer) { /* just push it to the matching code */ msg = PMIX_NEW(pmix_ptl_recv_t); PMIX_RETAIN(ms->peer); msg->peer = ms->peer; msg->hdr.pindex = pmix_globals.pindex; msg->hdr.tag = tag; msg->hdr.nbytes = ms->bfr->bytes_used; msg->data = ms->bfr->base_ptr; ms->bfr->base_ptr = NULL; ms->bfr->bytes_used = 0; PMIX_ACTIVATE_POST_MSG(msg); PMIX_RELEASE(ms); return; } snd = PMIX_NEW(pmix_ptl_send_t); snd->hdr.pindex = htonl(pmix_globals.pindex); snd->hdr.tag = htonl(tag); snd->hdr.nbytes = htonl(ms->bfr->bytes_used); snd->data = ms->bfr; /* always start with the header */ snd->sdptr = (char *) &snd->hdr; snd->sdbytes = sizeof(pmix_ptl_hdr_t); /* if there is no message on-deck, put this one there */ if (NULL == ms->peer->send_msg) { ms->peer->send_msg = snd; } else { /* add it to the queue */ pmix_list_append(&ms->peer->send_queue, &snd->super); } /* ensure the send event is active */ if (!ms->peer->send_ev_active) { ms->peer->send_ev_active = true; PMIX_POST_OBJECT(snd); pmix_event_add(&ms->peer->send_event, 0); } /* cleanup */ PMIX_RELEASE(ms); PMIX_POST_OBJECT(snd); } void pmix_ptl_base_process_msg(int fd, short flags, void *cbdata) { pmix_ptl_recv_t *msg = (pmix_ptl_recv_t *) cbdata; pmix_ptl_posted_recv_t *rcv; pmix_buffer_t buf; PMIX_HIDE_UNUSED_PARAMS(fd, flags); /* acquire the object */ PMIX_ACQUIRE_OBJECT(msg); pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "%s message received from %s with %d bytes for tag %u on socket %d", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_PEER_PRINT(msg->peer), (int) msg->hdr.nbytes, msg->hdr.tag, msg->sd); /* see if we have a waiting recv for this message */ PMIX_LIST_FOREACH (rcv, &pmix_ptl_base.posted_recvs, pmix_ptl_posted_recv_t) { pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "checking msg from %s on tag %u for peer %s tag %u", (NULL == msg->peer) ? "NULL" : PMIX_PEER_PRINT(msg->peer), msg->hdr.tag, (NULL == rcv->peer) ? "NULL" : PMIX_PEER_PRINT(rcv->peer), rcv->tag); // if the msg and rcv peers don't match, then skip this rcv if (NULL != rcv->peer && msg->peer != rcv->peer && UINT_MAX != rcv->tag) { continue; } if (msg->hdr.tag == rcv->tag || UINT_MAX == rcv->tag) { if (NULL != rcv->cbfunc) { /* construct and load the buffer */ PMIX_CONSTRUCT(&buf, pmix_buffer_t); if (NULL != msg->data) { PMIX_LOAD_BUFFER(msg->peer, &buf, msg->data, msg->hdr.nbytes); } else { /* we need to at least set the buffer type so * unpack of a zero-byte message doesn't error */ buf.type = msg->peer->nptr->compat.type; } msg->data = NULL; // protect the data region pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "%s:%d EXECUTE CALLBACK for tag %u with %d bytes", pmix_globals.myid.nspace, pmix_globals.myid.rank, msg->hdr.tag, (int)buf.bytes_used); rcv->cbfunc(msg->peer, &msg->hdr, &buf, rcv->cbdata); pmix_output_verbose(5, pmix_ptl_base_framework.framework_output, "%s:%d CALLBACK COMPLETE", pmix_globals.myid.nspace, pmix_globals.myid.rank); PMIX_DESTRUCT(&buf); // free's the msg data } /* done with the recv if it is a dynamic tag */ if (PMIX_PTL_TAG_DYNAMIC <= rcv->tag && UINT_MAX != rcv->tag) { pmix_list_remove_item(&pmix_ptl_base.posted_recvs, &rcv->super); PMIX_RELEASE(rcv); } PMIX_RELEASE(msg); return; } } /* we should never see an unexpected msg */ pmix_show_help("help-ptl-base.txt", "unexpected-message", true, PMIX_PEER_PRINT(msg->peer), msg->hdr.tag); PMIX_REPORT_EVENT(PMIX_ERROR, msg->peer, PMIX_RANGE_NAMESPACE, _notify_complete); PMIX_RELEASE(msg); } pmix-6.1.1~rc2/src/mca/ptl/base/ptl_base_connection_hdlr.c0000664000175000017500000013262015203536752023726 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "include/pmix_stdint.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #include "include/pmix_socket_errno.h" #include "src/client/pmix_client_ops.h" #include "src/common/pmix_pfexec.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_getid.h" #include "src/util/pmix_show_help.h" #include "src/util/pmix_strnlen.h" #include "src/mca/ptl/base/base.h" #include "src/mca/ptl/base/ptl_base_handshake.h" static void process_cbfunc(int sd, short args, void *cbdata); static void cnct_cbfunc(pmix_status_t status, pmix_proc_t *proc, void *cbdata); static void _check_cached_events(pmix_peer_t *peer); static pmix_status_t process_tool_request(pmix_pending_connection_t *pnd, char *mg, size_t cnt); // Local objects typedef struct { pmix_object_t super; pmix_event_t ev; pmix_status_t status; pmix_status_t reply; pmix_pending_connection_t *pnd; pmix_peer_t *peer; pmix_info_t *info; size_t ninfo; } cnct_hdlr_t; static void chcon(cnct_hdlr_t *p) { memset(&p->ev, 0, sizeof(pmix_event_t)); p->pnd = NULL; p->peer = NULL; p->info = NULL; p->ninfo = 0; } static void chdes(cnct_hdlr_t *p) { if (NULL != p->pnd) { PMIX_RELEASE(p->pnd); } if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->ninfo); } } static PMIX_CLASS_INSTANCE(cnct_hdlr_t, pmix_object_t, chcon, chdes); static void _cnct_complete(int sd, short args, void *cbdata) { cnct_hdlr_t *ch = (cnct_hdlr_t *) cbdata; uint32_t u32; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (PMIX_SUCCESS != ch->status) { goto error; } /* tell the client all is good */ u32 = htonl(ch->reply); rc = pmix_ptl_base_send_blocking(ch->pnd->sd, (char *) &u32, sizeof(uint32_t)); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } /* If needed, perform the handshake. The macro will update reply */ PMIX_PSEC_SERVER_HANDSHAKE_IFNEED(ch->reply, ch->peer); /* It is possible that connection validation failed */ if (PMIX_SUCCESS != ch->reply) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "validation of client connection failed"); goto error; } /* send the client's array index */ u32 = htonl(ch->peer->index); rc = pmix_ptl_base_send_blocking(ch->pnd->sd, (char *) &u32, sizeof(uint32_t)); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "connect-ack from client completed"); pmix_ptl_base_set_nonblocking(ch->pnd->sd); /* start the events for this client */ pmix_event_assign(&ch->peer->recv_event, pmix_globals.evbase, ch->pnd->sd, EV_READ | EV_PERSIST, pmix_ptl_base_recv_handler, ch->peer); pmix_event_add(&ch->peer->recv_event, NULL); ch->peer->recv_ev_active = true; pmix_event_assign(&ch->peer->send_event, pmix_globals.evbase, ch->pnd->sd, EV_WRITE | EV_PERSIST, pmix_ptl_base_send_handler, ch->peer); pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:server client %s:%u has connected on socket %d", ch->peer->info->pname.nspace, ch->peer->info->pname.rank, ch->peer->sd); /* check the cached events and update the client */ _check_cached_events(ch->peer); PMIX_RELEASE(ch); return; error: if (NULL != ch->peer) { pmix_pointer_array_set_item(&pmix_server_globals.clients, ch->peer->index, NULL); PMIX_RELEASE(ch->peer); } CLOSE_THE_SOCKET(ch->pnd->sd); PMIX_RELEASE(ch); } static void _connect_complete(pmix_status_t status, void *cbdata) { cnct_hdlr_t *ch = (cnct_hdlr_t *) cbdata; /* need to thread-shift this response */ ch->status = status; PMIX_THREADSHIFT(ch, _cnct_complete); } void pmix_ptl_base_connection_handler(int sd, short args, void *cbdata) { pmix_pending_connection_t *pnd = (pmix_pending_connection_t *) cbdata; pmix_ptl_hdr_t hdr; pmix_peer_t *peer = NULL; pmix_status_t rc, reply; char *msg = NULL, *mg, *p, *blob = NULL; size_t cnt, n, nblob = 0; size_t len = 0; int32_t i32; pmix_namespace_t *nptr, *tmp; pmix_rank_info_t *info = NULL, *iptr; pmix_proc_t proc; pmix_info_t ginfo, *iblob = NULL; pmix_byte_object_t cred; pmix_buffer_t buf; uint8_t major, minor, release; cnct_hdlr_t *ch; void *ilist; pmix_data_array_t darray; /* acquire the object */ PMIX_ACQUIRE_OBJECT(pnd); // must use sd, args to avoid -Werror PMIX_HIDE_UNUSED_PARAMS(sd, args); pmix_output_verbose(8, pmix_ptl_base_framework.framework_output, "ptl:base:connection_handler: new connection: %d", pnd->sd); /* ensure the socket is in blocking mode */ pmix_ptl_base_set_blocking(pnd->sd); /* ensure all is zero'd */ memset(&hdr, 0, sizeof(pmix_ptl_hdr_t)); /* get the header */ rc = pmix_ptl_base_recv_blocking(pnd->sd, (char *) &hdr, sizeof(pmix_ptl_hdr_t)); if (PMIX_SUCCESS != rc) { goto error; } /* get the id, authentication and version payload (and possibly * security credential) - to guard against potential attacks, * we'll set an arbitrary limit per a define */ if (PMIX_MAX_CRED_SIZE < hdr.nbytes) { goto error; } if (NULL == (msg = (char *) malloc(hdr.nbytes+1))) { goto error; } memset(msg, 0, hdr.nbytes + 1); // ensure NULL termination of result if (PMIX_SUCCESS != pmix_ptl_base_recv_blocking(pnd->sd, msg, hdr.nbytes)) { /* unable to complete the recv */ pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tool:connection_handler unable to complete recv of connect-ack " "with client ON SOCKET %d", pnd->sd); goto error; } cnt = hdr.nbytes; mg = msg; /* extract the name of the sec module they used */ PMIX_PTL_GET_STRING(pnd->psec); /* extract any credential so we can validate this connection * before doing anything else */ PMIX_PTL_GET_U32(pnd->len); if (PMIX_TAINT_UINT_LIMIT < pnd->len) { // arbitrary value to guard against tainted input PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); goto error; } /* if a credential is present, then create space and * extract it for processing */ PMIX_PTL_GET_BLOB(pnd->cred, pnd->len); /* get the process type of the connecting peer */ PMIX_PTL_GET_U8(pnd->flag); switch (pnd->flag) { case PMIX_SIMPLE_CLIENT: /* simple client process */ PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_CLIENT); /* get their identifier */ PMIX_PTL_GET_PROCID(pnd->proc); break; case PMIX_LEGACY_TOOL: /* legacy tool - may or may not have an identifier */ PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_TOOL); /* get their uid/gid */ PMIX_PTL_GET_U32(pnd->uid); PMIX_PTL_GET_U32(pnd->gid); break; case PMIX_LEGACY_LAUNCHER: /* legacy launcher - may or may not have an identifier */ PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_LAUNCHER); /* get their uid/gid */ PMIX_PTL_GET_U32(pnd->uid); PMIX_PTL_GET_U32(pnd->gid); break; case PMIX_TOOL_NEEDS_ID: case PMIX_LAUNCHER_NEEDS_ID: /* self-started tool/launcher process that needs an identifier */ if (PMIX_TOOL_NEEDS_ID == pnd->flag) { PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_TOOL); } else { PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_LAUNCHER); } /* get their uid/gid */ PMIX_PTL_GET_U32(pnd->uid); PMIX_PTL_GET_U32(pnd->gid); /* they need an id */ pnd->need_id = true; break; case PMIX_TOOL_GIVEN_ID: case PMIX_LAUNCHER_GIVEN_ID: case PMIX_SINGLETON_CLIENT: case PMIX_SCHEDULER_WITH_ID: /* self-started tool/launcher process that was given an identifier by caller */ if (PMIX_TOOL_GIVEN_ID == pnd->flag) { PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_TOOL); } else if (PMIX_LAUNCHER_GIVEN_ID == pnd->flag) { PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_LAUNCHER); } else if (PMIX_SCHEDULER_WITH_ID == pnd->flag) { PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_SCHEDULER); } else { PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_CLIENT); } /* get their uid/gid */ PMIX_PTL_GET_U32(pnd->uid); PMIX_PTL_GET_U32(pnd->gid); /* get their identifier */ PMIX_PTL_GET_PROCID(pnd->proc); break; case PMIX_TOOL_CLIENT: case PMIX_LAUNCHER_CLIENT: /* tool/launcher that was started by a PMIx server - identifier specified by server */ if (PMIX_TOOL_CLIENT == pnd->flag) { PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_TOOL); } else { PMIX_SET_PROC_TYPE(&pnd->proc_type, PMIX_PROC_LAUNCHER); } /* get their uid/gid */ PMIX_PTL_GET_U32(pnd->uid); PMIX_PTL_GET_U32(pnd->gid); /* get their identifier */ PMIX_PTL_GET_PROCID(pnd->proc); break; default: /* we don't know what they are! */ PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); goto error; } /* extract their VERSION */ PMIX_PTL_GET_STRING(pnd->version); major = strtoul(pnd->version, &p, 10); ++p; minor = strtoul(p, &p, 10); ++p; release = strtoul(p, NULL, 10); PMIX_SET_PROC_MAJOR(&pnd->proc_type, major); PMIX_SET_PROC_MINOR(&pnd->proc_type, minor); PMIX_SET_PROC_RELEASE(&pnd->proc_type, release); if (2 == major && 0 == minor) { /* the 2.0 release handshake ends with the version string */ pnd->bfrops = strdup("v20"); pnd->buffer_type = pmix_bfrops_globals.default_type; // we can't know any better pnd->gds = strdup("ds12,hash"); cnt = 0; } else { /* extract the name of the bfrops module they used */ PMIX_PTL_GET_STRING(pnd->bfrops); /* extract the type of buffer they used */ PMIX_PTL_GET_U8(pnd->buffer_type); /* extract the name of the gds module they used */ PMIX_PTL_GET_STRING(pnd->gds); /* extract the blob */ if (0 < cnt) { len = cnt; PMIX_PTL_GET_BLOB(blob, len); } } /* see if this is a tool connection request */ if (PMIX_SIMPLE_CLIENT != pnd->flag && PMIX_SINGLETON_CLIENT != pnd->flag) { /* nope, it's for a tool, so process it * separately - it is a 2-step procedure */ rc = process_tool_request(pnd, blob, len); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } if (NULL != blob) { free(blob); blob = NULL; } free(msg); return; } /* it is a client that is connecting, so it should have * been registered with us prior to being started. * See if we know this nspace */ nptr = NULL; PMIX_LIST_FOREACH (tmp, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(tmp->nspace, pnd->proc.nspace)) { nptr = tmp; break; } } if (NULL == nptr) { /* we don't know this namespace, reject it */ rc = PMIX_ERR_NOT_FOUND; goto error; } /* likewise, we should have this peer in our list */ info = NULL; PMIX_LIST_FOREACH (iptr, &nptr->ranks, pmix_rank_info_t) { if (iptr->pname.rank == pnd->proc.rank) { info = iptr; break; } } if (NULL == info) { /* rank unknown, reject it */ rc = PMIX_ERR_NOT_FOUND; goto error; } /* save the version in the namespace object */ if (0 == nptr->version.major) { nptr->version.major = pnd->proc_type.major; nptr->version.minor = pnd->proc_type.minor; nptr->version.release = pnd->proc_type.release; } /* a peer can connect on multiple sockets since it can fork/exec * a child that also calls PMIX_Init, so add it here if necessary. * Create the tracker for this peer */ peer = PMIX_NEW(pmix_peer_t); if (NULL == peer) { goto error; } /* Assign the upper half of the tag space for sendrecvs */ peer->dyn_tags_start = PMIX_PTL_TAG_DYNAMIC + (UINT32_MAX - PMIX_PTL_TAG_DYNAMIC)/2 + 1; peer->dyn_tags_end = UINT32_MAX; peer->dyn_tags_current = peer->dyn_tags_start; /* mark that this peer is a client of the given type */ memcpy(&peer->proc_type, &pnd->proc_type, sizeof(pmix_proc_type_t)); /* save the protocol */ peer->protocol = pnd->protocol; /* add in the nspace pointer */ PMIX_RETAIN(nptr); peer->nptr = nptr; PMIX_RETAIN(info); peer->info = info; /* update the epilog fields */ peer->epilog.uid = info->uid; peer->epilog.gid = info->gid; /* ensure the nspace epilog is updated too */ nptr->epilog.uid = info->uid; nptr->epilog.gid = info->gid; info->proc_cnt++; /* increase number of processes on this rank */ peer->sd = pnd->sd; if (0 > (peer->index = pmix_pointer_array_add(&pmix_server_globals.clients, peer))) { goto error; } info->peerid = peer->index; /* set the sec module to match this peer */ peer->nptr->compat.psec = pmix_psec_base_assign_module(pnd->psec); if (NULL == peer->nptr->compat.psec) { goto error; } /* set the bfrops module to match this peer */ peer->nptr->compat.bfrops = pmix_bfrops_base_assign_module(pnd->bfrops); if (NULL == peer->nptr->compat.bfrops) { goto error; } /* and the buffer type to match */ peer->nptr->compat.type = pnd->buffer_type; /* set the gds module to match this peer */ if (NULL != pnd->gds) { PMIX_INFO_LOAD(&ginfo, PMIX_GDS_MODULE, pnd->gds, PMIX_STRING); peer->nptr->compat.gds = pmix_gds_base_assign_module(&ginfo, 1); PMIX_INFO_DESTRUCT(&ginfo); } else { peer->nptr->compat.gds = pmix_gds_base_assign_module(NULL, 0); } if (NULL == peer->nptr->compat.gds) { goto error; } /* if we haven't previously stored the version for this * nspace, do so now */ if (!nptr->version_stored) { PMIX_INFO_LOAD(&ginfo, PMIX_BFROPS_MODULE, pnd->version, PMIX_STRING); PMIX_GDS_CACHE_JOB_INFO(rc, pmix_globals.mypeer, peer->nptr, &ginfo, 1); PMIX_INFO_DESTRUCT(&ginfo); nptr->version_stored = true; } ilist = PMIx_Info_list_start(); // if a blob was provided, then unpack it if (NULL != blob) { PMIX_CONSTRUCT(&buf, pmix_buffer_t); PMIX_LOAD_BUFFER_NON_DESTRUCT(peer, &buf, blob, len); // allocates no memory i32 = 1; PMIX_BFROPS_UNPACK(rc, peer, &buf, &nblob, &i32, PMIX_SIZE); if (0 < nblob) { PMIX_INFO_CREATE(iblob, nblob); i32 = nblob; PMIX_BFROPS_UNPACK(rc, peer, &buf, iblob, &i32, PMIX_INFO); // process the data for (n=0; n < nblob; n++) { if (PMIx_Check_key(iblob[n].key, PMIX_PROC_PID)) { info->pid = iblob[n].value.data.pid; PMIx_Info_list_add(ilist, PMIX_PROC_PID, &info->pid, PMIX_PID); } else if (PMIx_Check_key(iblob[n].key, PMIX_REALUID)) { info->realuid = iblob[n].value.data.uint32; PMIx_Info_list_add(ilist, PMIX_REALUID, &info->realuid, PMIX_UINT32); } else if (PMIx_Check_key(iblob[n].key, PMIX_USERID)) { // check if the client is claiming to be someone other // than what they were registered as if (info->uid != iblob[n].value.data.uint32) { // mismatch PMIx_Info_list_release(ilist); pmix_show_help("help-ptl-base.txt", "mismatch-id", true, "user", iblob[n].value.data.uint32, info->uid); goto error; } } else if (PMIx_Check_key(iblob[n].key, PMIX_REALGID)) { info->realgid = iblob[n].value.data.uint32; PMIx_Info_list_add(ilist, PMIX_REALGID, &info->realgid, PMIX_UINT32); } else if (PMIx_Check_key(iblob[n].key, PMIX_GRPID)) { // check if the client is claiming to be someone other // than what they were registered as if (info->gid != iblob[n].value.data.uint32) { // mismatch PMIx_Info_list_release(ilist); pmix_show_help("help-ptl-base.txt", "mismatch-id", true, "group", iblob[n].value.data.uint32, info->uid); goto error; } } } PMIX_INFO_FREE(iblob, nblob); iblob = NULL; nblob = 0; } free(blob); blob = NULL; } free(msg); // can now release the data buffer msg = NULL; /* validate the connection */ cred.bytes = pnd->cred; cred.size = pnd->len; PMIX_PSEC_VALIDATE_CONNECTION(reply, peer, NULL, 0, NULL, NULL, &cred); if (PMIX_SUCCESS != reply) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "validation of client connection failed"); PMIx_Info_list_release(ilist); goto error; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "client connection validated"); // prep for processing ch = PMIX_NEW(cnct_hdlr_t); ch->peer = peer; ch->pnd = pnd; ch->reply = reply; PMIx_Info_list_add(ilist, PMIX_USERID, &info->uid, PMIX_UINT32); PMIx_Info_list_add(ilist, PMIX_GRPID, &info->gid, PMIX_UINT32); PMIx_Info_list_convert(ilist, &darray); ch->info = (pmix_info_t*)darray.array; ch->ninfo = darray.size; PMIx_Info_list_release(ilist); /* let the host server know that this client has connected */ if (NULL != pmix_host_server.client_connected2) { PMIX_LOAD_PROCID(&proc, peer->info->pname.nspace, peer->info->pname.rank); rc = pmix_host_server.client_connected2(&proc, peer->info->server_object, ch->info, ch->ninfo, _connect_complete, ch); if (PMIX_OPERATION_SUCCEEDED == rc) { ch->status = PMIX_SUCCESS; _cnct_complete(0, 0, ch); return; } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(ch); goto error; } } else if (NULL != pmix_host_server.client_connected) { PMIX_LOAD_PROCID(&proc, peer->info->pname.nspace, peer->info->pname.rank); rc = pmix_host_server.client_connected(&proc, peer->info->server_object, _connect_complete, ch); if (PMIX_OPERATION_SUCCEEDED == rc) { ch->status = PMIX_SUCCESS; _cnct_complete(0, 0, ch); return; } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(ch); goto error; } } else { // if neither of those conditions are met, then we simply assume the host is ready ch->status = PMIX_SUCCESS; _cnct_complete(0, 0, ch); } return; error: if (NULL != info) { info->proc_cnt--; PMIX_RELEASE(info); } if (NULL != msg) { free(msg); } if (NULL != blob) { free(blob); } if (NULL != iblob) { PMIX_INFO_FREE(iblob, nblob); } if (NULL != peer) { pmix_pointer_array_set_item(&pmix_server_globals.clients, peer->index, NULL); PMIX_RELEASE(peer); } CLOSE_THE_SOCKET(pnd->sd); PMIX_RELEASE(pnd); return; } /* process the host's callback with tool connection info */ static void process_cbfunc(int sd, short args, void *cbdata) { pmix_setup_caddy_t *cd = (pmix_setup_caddy_t *) cbdata; pmix_pending_connection_t *pnd = (pmix_pending_connection_t *) cd->cbdata; pmix_namespace_t *nptr = NULL, *nptr2, *nptr3; pmix_rank_info_t *info; pmix_peer_t *peer = NULL, *pr2; pmix_status_t rc, reply; uint32_t u32; int n; pmix_info_t ginfo; pmix_byte_object_t cred; pmix_iof_req_t *req = NULL; /* acquire the object */ PMIX_ACQUIRE_OBJECT(cd); // must use sd, args to avoid -Werror PMIX_HIDE_UNUSED_PARAMS(sd, args); /* send this status so they don't hang */ u32 = ntohl(cd->status); rc = pmix_ptl_base_send_blocking(pnd->sd, (char *) &u32, sizeof(uint32_t)); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } /* if the request failed, then we are done */ if (PMIX_SUCCESS != cd->status) { goto error; } /* if we got an identifier, send it back to the tool */ if (pnd->need_id) { /* start with the nspace */ rc = pmix_ptl_base_send_blocking(pnd->sd, cd->proc.nspace, PMIX_MAX_NSLEN + 1); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } /* now the rank, suitably converted */ u32 = ntohl(cd->proc.rank); rc = pmix_ptl_base_send_blocking(pnd->sd, (char *) &u32, sizeof(uint32_t)); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } } /* send my nspace back to the tool */ rc = pmix_ptl_base_send_blocking(pnd->sd, pmix_globals.myid.nspace, PMIX_MAX_NSLEN + 1); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } /* send my rank back to the tool */ u32 = ntohl(pmix_globals.myid.rank); rc = pmix_ptl_base_send_blocking(pnd->sd, (char *) &u32, sizeof(uint32_t)); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto error; } /* shortcuts */ peer = (pmix_peer_t *) pnd->peer; nptr = peer->nptr; /* if this tool is a client, then check against our list of * local clients to verify they are the same */ if (PMIX_TOOL_CLIENT == pnd->flag || PMIX_LAUNCHER_CLIENT == pnd->flag) { for (n=0; n < pmix_server_globals.clients.size; n++) { pr2 = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, n); if (NULL == pr2) { continue; } if (PMIx_Check_nspace(pr2->info->pname.nspace, cd->proc.nspace) && pr2->info->pname.rank == cd->proc.rank) { // this matches the existing client record - check uid/gid if (pr2->info->uid != pnd->uid) { reply = PMIX_ERR_INVALID_CRED; u32 = htonl(reply); rc = pmix_ptl_base_send_blocking(pnd->sd, (char *) &u32, sizeof(uint32_t)); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } goto error; } } } } /* if this tool wasn't initially registered as a client, * then add some required structures */ if (PMIX_TOOL_CLIENT != pnd->flag && PMIX_LAUNCHER_CLIENT != pnd->flag) { if (NULL != nptr->nspace) { free(nptr->nspace); } nptr->nspace = strdup(cd->proc.nspace); info = PMIX_NEW(pmix_rank_info_t); info->pname.nspace = strdup(nptr->nspace); info->pname.rank = cd->proc.rank; info->uid = pnd->uid; info->gid = pnd->gid; pmix_list_append(&nptr->ranks, &info->super); PMIX_RETAIN(info); peer->info = info; pnd->rinfo_created = true; } else if (pnd->nspace_created) { // must add it to the global list - but check to ensure // it is unique as the host may have "registered" this // namespace, and so we would already have that record nptr3 = NULL; PMIX_LIST_FOREACH(nptr2, &pmix_globals.nspaces, pmix_namespace_t) { if (PMIx_Check_nspace(nptr->nspace, nptr2->nspace)) { nptr3 = nptr2; break; } } if (NULL == nptr3) { pmix_list_append(&pmix_globals.nspaces, &nptr->super); } else { // need to release this to avoid memory leak PMIX_RELEASE(nptr); nptr = nptr3; // reconnect the peer peer->nptr = nptr; } } /* mark the peer proc type */ memcpy(&peer->proc_type, &pnd->proc_type, sizeof(pmix_proc_type_t)); /* save the protocol */ peer->protocol = pnd->protocol; /* save the uid/gid */ peer->epilog.uid = peer->info->uid; peer->epilog.gid = peer->info->gid; nptr->epilog.uid = peer->info->uid; nptr->epilog.gid = peer->info->gid; peer->proc_cnt = 1; peer->sd = pnd->sd; /* get the appropriate compatibility modules based on the * info provided by the tool during the initial connection request */ peer->nptr->compat.psec = pmix_psec_base_assign_module(pnd->psec); if (NULL == peer->nptr->compat.psec) { goto error; } /* set the gds */ PMIX_INFO_LOAD(&ginfo, PMIX_GDS_MODULE, pnd->gds, PMIX_STRING); peer->nptr->compat.gds = pmix_gds_base_assign_module(&ginfo, 1); PMIX_INFO_DESTRUCT(&ginfo); if (NULL == peer->nptr->compat.gds) { goto error; } /* if we haven't previously stored the version for this * nspace, do so now */ if (!peer->nptr->version_stored) { PMIX_INFO_LOAD(&ginfo, PMIX_BFROPS_MODULE, pnd->version, PMIX_STRING); PMIX_GDS_CACHE_JOB_INFO(rc, pmix_globals.mypeer, peer->nptr, &ginfo, 1); PMIX_INFO_DESTRUCT(&ginfo); nptr->version_stored = true; } /* automatically setup to forward output to the tool */ req = PMIX_NEW(pmix_iof_req_t); if (NULL == req) { goto error; } PMIX_RETAIN(peer); req->requestor = peer; req->nprocs = 1; PMIX_PROC_CREATE(req->procs, req->nprocs); PMIX_LOAD_PROCID(&req->procs[0], pmix_globals.myid.nspace, pmix_globals.myid.rank); req->channels = PMIX_FWD_STDOUT_CHANNEL | PMIX_FWD_STDERR_CHANNEL | PMIX_FWD_STDDIAG_CHANNEL; // default to formatting output as we were directed to do req->flags = pmix_globals.iof_flags; req->remote_id = 0; // default ID for tool during init req->local_id = pmix_pointer_array_add(&pmix_globals.iof_requests, req); /* validate the connection */ cred.bytes = pnd->cred; cred.size = pnd->len; PMIX_PSEC_VALIDATE_CONNECTION(reply, peer, NULL, 0, NULL, NULL, &cred); if (PMIX_SUCCESS != reply) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "validation of tool credentials failed: %s", PMIx_Error_string(reply)); } /* communicate the result to the other side */ u32 = htonl(reply); rc = pmix_ptl_base_send_blocking(pnd->sd, (char *) &u32, sizeof(uint32_t)); if (PMIX_SUCCESS != rc || PMIX_SUCCESS != reply) { goto error; } /* If needed perform the handshake. The macro will update reply */ PMIX_PSEC_SERVER_HANDSHAKE_IFNEED(reply, peer); /* If verification wasn't successful - stop here */ if (PMIX_SUCCESS != reply) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "security handshake for tool failed: %s", PMIx_Error_string(reply)); goto error; } /* set the socket non-blocking for all further operations */ pmix_ptl_base_set_nonblocking(pnd->sd); if (0 > (peer->index = pmix_pointer_array_add(&pmix_server_globals.clients, peer))) { goto error; } peer->info->peerid = peer->index; /* start the events for this tool */ pmix_event_assign(&peer->recv_event, pmix_globals.evbase, peer->sd, EV_READ | EV_PERSIST, pmix_ptl_base_recv_handler, peer); pmix_event_add(&peer->recv_event, NULL); peer->recv_ev_active = true; pmix_event_assign(&peer->send_event, pmix_globals.evbase, peer->sd, EV_WRITE | EV_PERSIST, pmix_ptl_base_send_handler, peer); pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:server tool %s:%d has connected on socket %d", peer->info->pname.nspace, peer->info->pname.rank, peer->sd); /* check the cached events and update the tool */ _check_cached_events(peer); PMIX_RELEASE(pnd); PMIX_RELEASE(cd); return; error: CLOSE_THE_SOCKET(pnd->sd); if (NULL != peer) { if (NULL != peer->info && pnd->rinfo_created) { pmix_list_remove_item(&peer->nptr->ranks, &peer->info->super); // the info object will be released along with the peer } if (NULL != peer->nptr && pnd->nspace_created) { pmix_list_remove_item(&pmix_globals.nspaces, &peer->nptr->super); // the nptr will be released along with the peer } PMIX_RELEASE(peer); } PMIX_RELEASE(cd); if (NULL != req) { pmix_pointer_array_set_item(&pmix_globals.iof_requests, req->local_id, NULL); PMIX_RELEASE(req); } PMIX_RELEASE(pnd); } /* receive a callback from the host RM with an nspace * for a connecting tool */ static void cnct_cbfunc(pmix_status_t status, pmix_proc_t *proc, void *cbdata) { pmix_setup_caddy_t *cd; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "pmix:tool:cnct_cbfunc returning %s:%d %s", proc->nspace, proc->rank, PMIx_Error_string(status)); /* need to thread-shift this into our context */ cd = PMIX_NEW(pmix_setup_caddy_t); if (NULL == cd) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } cd->status = status; if (NULL != proc) { PMIX_LOAD_PROCID(&cd->proc, proc->nspace, proc->rank); } cd->cbdata = cbdata; PMIX_THREADSHIFT(cd, process_cbfunc); } static pmix_status_t process_tool_request(pmix_pending_connection_t *pnd, char *mg, size_t cnt) { pmix_peer_t *peer, *p2; pmix_namespace_t *nptr, *tmp; pmix_rank_info_t *info; bool found; size_t n, sz; pmix_buffer_t buf; pmix_status_t rc; void *ilist; pmix_info_t *iptr; pmix_data_array_t darray; pmix_pfexec_child_t *child; if (!pmix_ptl_base.allow_foreign_tools) { if (pnd->uid != pmix_globals.uid) { // reject this connection return PMIX_ERR_NOT_SUPPORTED; } } peer = PMIX_NEW(pmix_peer_t); if (NULL == peer) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } /* Assign the upper half of the tag space for sendrecvs */ peer->dyn_tags_start = PMIX_PTL_TAG_DYNAMIC + (UINT32_MAX - PMIX_PTL_TAG_DYNAMIC)/2 + 1; peer->dyn_tags_end = UINT32_MAX; peer->dyn_tags_current = peer->dyn_tags_start; pnd->peer = peer; /* see if we know this nspace - i.e., was it registered or did * another tool within it already connect */ nptr = NULL; PMIX_LIST_FOREACH (tmp, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(tmp->nspace, pnd->proc.nspace)) { nptr = tmp; break; } } /* if this is a tool we launched, then the host may * have already registered it as a client - so check * to see if we already have a peer for it */ if (PMIX_TOOL_CLIENT == pnd->flag || PMIX_LAUNCHER_CLIENT == pnd->flag) { if (NULL == nptr) { /* it is possible that this is a tool inside of * a job-script as part of a multi-spawn operation. * Since each tool invocation may have finalized and * terminated, the tool will appear to "terminate", thus * causing us to cleanup all references to it, and then * reappear. So we don't reject this connection request. * Instead, we create the nspace and rank objects for * it and let the RM/host decide if this behavior * is allowed */ nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); PMIX_RELEASE(peer); return PMIX_ERR_NOMEM; } nptr->nspace = strdup(pnd->proc.nspace); /* save the version */ nptr->version.major = pnd->proc_type.major; nptr->version.minor = pnd->proc_type.minor; nptr->version.release = pnd->proc_type.release; pnd->nspace_created = true; } /* now look for the rank */ info = NULL; found = false; PMIX_LIST_FOREACH (info, &nptr->ranks, pmix_rank_info_t) { if (info->pname.rank == pnd->proc.rank) { found = true; break; } } if (found) { /* check that the uid/gid of the connecting tool * matches the expected values */ if (info->uid != pnd->uid || info->gid != pnd->gid) { PMIX_RELEASE(peer); PMIX_ERROR_LOG(PMIX_ERR_INVALID_CRED); return PMIX_ERR_INVALID_CRED; } } else { /* see above note about not finding nspace */ info = PMIX_NEW(pmix_rank_info_t); info->pname.nspace = strdup(pnd->proc.nspace); info->pname.rank = pnd->proc.rank; info->uid = pnd->uid; info->gid = pnd->gid; pmix_list_append(&nptr->ranks, &info->super); pnd->rinfo_created = true; } PMIX_RETAIN(info); peer->info = info; PMIX_RETAIN(nptr); } else if (NULL != nptr) { /* this is an non-client tool/launcher that already * has a known nspace that wasn't defined by register_client. * We must therefore already have a rank for it that connected * (so we would know the nspace), and the uid/gid's of this proc * must match those already registered */ info = (pmix_rank_info_t*)pmix_list_get_first(&nptr->ranks); if (NULL == info) { /* this cannot happen - the nspace can only exist because * a prior instance of the tool already connected */ PMIX_RELEASE(peer); PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_SUPPORTED; } if (-1 == info->peerid) { /* the tool may be one we fork/exec'd ourselves - check * the local children to see */ found = false; PMIX_LIST_FOREACH(child, &pmix_pfexec_globals.children, pmix_pfexec_child_t) { if (PMIx_Check_nspace(child->proc.nspace, nptr->nspace)) { found = true; break; } } if (!found) { /* this proc is not a child of ours and has not connected - this * cannot happen for a tool as we otherwise would not know of it */ PMIX_RELEASE(peer); PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_SUPPORTED; } } else { p2 = (pmix_peer_t*)pmix_pointer_array_get_item(&pmix_server_globals.clients, info->peerid); if (NULL == p2) { // that's an error PMIX_RELEASE(peer); PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_FOUND; } if (!PMIX_PEER_IS_TOOL(p2)) { /* cannot happen - the entire nspace must be a tool if this proc claims * to be a member of that nspace and is a tool */ PMIX_RELEASE(peer); PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_SUPPORTED; } } /* all members of an nspace must be from the same uid and gid */ if (info->uid != pnd->uid || info->gid != pnd->gid) { PMIX_RELEASE(peer); PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED); return PMIX_ERR_NOT_SUPPORTED; } } else { nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); PMIX_RELEASE(peer); return PMIX_ERR_NOMEM; } if (!pnd->need_id) { // must have been given one nptr->nspace = strdup(pnd->proc.nspace); } /* save the version */ nptr->version.major = pnd->proc_type.major; nptr->version.minor = pnd->proc_type.minor; nptr->version.release = pnd->proc_type.release; pnd->nspace_created = true; /* must add the nspace to the global list after we return * from the host's upcall since they can/will assign the * tool with a namespace */ PMIX_RETAIN(nptr); } if (!pnd->nspace_created) { // this was already on the nspace list, so protect it PMIX_RETAIN(nptr); } peer->nptr = nptr; /* select their bfrops compat module so we can unpack * any provided pmix_info_t structs */ peer->nptr->compat.bfrops = pmix_bfrops_base_assign_module(pnd->bfrops); if (NULL == peer->nptr->compat.bfrops) { rc = PMIX_ERR_NOT_AVAILABLE; PMIX_ERROR_LOG(rc); goto cleanup; } /* set the buffer type */ peer->nptr->compat.type = pnd->buffer_type; n = 0; /* if info structs need to be passed along, then unpack them */ ilist = PMIx_Info_list_start(); if (0 < cnt) { int32_t foo; PMIX_CONSTRUCT(&buf, pmix_buffer_t); PMIX_LOAD_BUFFER_NON_DESTRUCT(peer, &buf, mg, cnt); // allocates no memory foo = 1; PMIX_BFROPS_UNPACK(rc, peer, &buf, &sz, &foo, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(peer); PMIx_Info_list_release(ilist); return rc; } foo = (int32_t) sz; PMIX_INFO_CREATE(iptr, sz); PMIX_BFROPS_UNPACK(rc, peer, &buf, iptr, &foo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(peer); PMIX_INFO_FREE(iptr, sz); PMIx_Info_list_release(ilist); return rc; } for (n=0; n < sz; n++) { PMIx_Info_list_xfer(ilist, &iptr[n]); } PMIX_INFO_FREE(iptr, sz); } /* does the server support tool connections? */ if (NULL == pmix_host_server.tool_connected && NULL == pmix_host_server.tool_connected2) { PMIx_Info_list_release(ilist); if (pnd->need_id) { /* we need someone to provide the tool with an * identifier and they aren't available */ /* send an error reply to the client */ rc = PMIX_ERR_NOT_SUPPORTED; goto cleanup; } else { /* just process it locally */ cnct_cbfunc(PMIX_SUCCESS, &pnd->proc, (void *) pnd); /* release the msg */ return PMIX_SUCCESS; } } /* setup the info array to pass the relevant info * to the server */ /* provide the version */ PMIx_Info_list_add_unique(ilist, PMIX_VERSION_INFO, pnd->version, PMIX_STRING, true); /* provide the user id */ PMIx_Info_list_add_unique(ilist, PMIX_USERID, &pnd->uid, PMIX_UINT32, false); /* and the group id */ PMIx_Info_list_add_unique(ilist, PMIX_GRPID, &pnd->gid, PMIX_UINT32, false); /* if we have it, pass along their ID */ if (!pnd->need_id) { PMIx_Info_list_add_unique(ilist, PMIX_NSPACE, pnd->proc.nspace, PMIX_STRING, true); PMIx_Info_list_add_unique(ilist, PMIX_RANK, &pnd->proc.rank, PMIX_PROC_RANK, true); } rc = PMIx_Info_list_convert(ilist, &darray); PMIx_Info_list_release(ilist); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } pnd->info = (pmix_info_t*)darray.array; pnd->ninfo = darray.size; /* pass it up for processing */ if (NULL != pmix_host_server.tool_connected2) { rc = pmix_host_server.tool_connected2(pnd->info, pnd->ninfo, cnct_cbfunc, pnd); if (PMIX_SUCCESS != rc) { goto cleanup; } return PMIX_SUCCESS; } else { pmix_host_server.tool_connected(pnd->info, pnd->ninfo, cnct_cbfunc, pnd); } return PMIX_SUCCESS; cleanup: if (pnd->rinfo_created) { pmix_list_remove_item(&nptr->ranks, &peer->info->super); PMIX_RELEASE(pnd->info); } else { peer->info = NULL; } if (pnd->nspace_created) { pmix_list_remove_item(&pmix_globals.nspaces, &nptr->super); PMIX_RELEASE(nptr); } else { peer->nptr = NULL; // protect it } PMIX_RELEASE(peer); return rc; } static void _check_cached_events(pmix_peer_t *peer) { pmix_notify_caddy_t *cd; int i; size_t n; pmix_range_trkr_t rngtrk; pmix_buffer_t *relay; pmix_proc_t proc; pmix_status_t ret; pmix_cmd_t cmd = PMIX_NOTIFY_CMD; bool matched, found; PMIX_LOAD_PROCID(&proc, peer->info->pname.nspace, peer->info->pname.rank); for (i = 0; i < pmix_globals.max_events; i++) { pmix_hotel_knock(&pmix_globals.notifications, i, (void **) &cd); if (NULL == cd) { continue; } /* check the range */ if (NULL == cd->targets) { rngtrk.procs = &cd->source; rngtrk.nprocs = 1; } else { rngtrk.procs = cd->targets; rngtrk.nprocs = cd->ntargets; } rngtrk.range = cd->range; if (!pmix_notify_check_range(&rngtrk, &proc)) { continue; } found = false; /* if we were given specific targets, check if this is one */ if (NULL != cd->targets) { matched = false; for (n = 0; n < cd->ntargets; n++) { if (PMIX_CHECK_PROCID(&proc, &cd->targets[n])) { matched = true; /* track the number of targets we have left to notify */ --cd->nleft; /* if this is the last one, then evict this event * from the cache */ if (0 == cd->nleft) { pmix_hotel_checkout(&pmix_globals.notifications, cd->room); found = true; // mark that we should release cd } break; } } if (!matched) { /* do not notify this one */ continue; } } /* all matches - notify */ relay = PMIX_NEW(pmix_buffer_t); if (NULL == relay) { /* nothing we can do */ PMIX_ERROR_LOG(PMIX_ERR_NOMEM); break; } /* pack the info data stored in the event */ PMIX_BFROPS_PACK(ret, peer, relay, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(relay); break; } PMIX_BFROPS_PACK(ret, peer, relay, &cd->status, 1, PMIX_STATUS); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(relay); break; } PMIX_BFROPS_PACK(ret, peer, relay, &cd->source, 1, PMIX_PROC); if (PMIX_SUCCESS != ret) { PMIX_RELEASE(relay); PMIX_ERROR_LOG(ret); break; } PMIX_BFROPS_PACK(ret, peer, relay, &cd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(relay); break; } if (0 < cd->ninfo) { PMIX_BFROPS_PACK(ret, peer, relay, cd->info, cd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != ret) { PMIX_ERROR_LOG(ret); PMIX_RELEASE(relay); break; } } PMIX_SERVER_QUEUE_REPLY(ret, peer, 0, relay); if (PMIX_SUCCESS != ret) { PMIX_RELEASE(relay); } if (found) { PMIX_RELEASE(cd); } } } pmix-6.1.1~rc2/src/mca/ptl/ptl_types.h0000664000175000017500000004361015203536752020023 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Buffer management types. */ #ifndef PMIX_PTL_TYPES_H_ #define PMIX_PTL_TYPES_H_ #include "src/include/pmix_config.h" #include "src/include/pmix_types.h" #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_NET_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "src/class/pmix_list.h" #include "src/include/pmix_stdatomic.h" #include "src/mca/bfrops/bfrops_types.h" #include "src/mca/ptl/base/ptl_base_handshake.h" #include "src/util/pmix_output.h" BEGIN_C_DECLS // forward declaration struct pmix_peer_t; struct pmix_ptl_module_t; /* define a process type */ typedef struct { uint32_t type; uint8_t major; uint8_t minor; uint8_t release; uint8_t flag; // see pmix_ptl_base_set_flag for definition of values } pmix_proc_type_t; #define PMIX_MAJOR_WILDCARD 255 #define PMIX_MINOR_WILDCARD 255 #define PMIX_RELEASE_WILDCARD 255 /* use 255 as WILDCARD for the release triplet values */ #define PMIX_PROC_TYPE_STATIC_INIT \ { \ .type = PMIX_PROC_UNDEF, \ .major = PMIX_MAJOR_WILDCARD, \ .minor = PMIX_MINOR_WILDCARD, \ .release = PMIX_RELEASE_WILDCARD, \ .flag = 0 \ } /* Define process types - we use a bit-mask as procs can * span multiple types */ #define PMIX_PROC_UNDEF 0x00000000 #define PMIX_PROC_CLIENT 0x00000001 // simple client process #define PMIX_PROC_SERVER 0x00000002 // simple server process #define PMIX_PROC_TOOL 0x00000004 // simple tool #define PMIX_PROC_SINGLETON_ACT 0x00000008 // self-started client process #define PMIX_PROC_SINGLETON (PMIX_PROC_CLIENT | PMIX_PROC_SINGLETON_ACT) #define PMIX_PROC_LAUNCHER_ACT 0x10000000 // process acting as launcher #define PMIX_PROC_LAUNCHER (PMIX_PROC_TOOL | PMIX_PROC_SERVER | PMIX_PROC_LAUNCHER_ACT) #define PMIX_PROC_CLIENT_LAUNCHER (PMIX_PROC_LAUNCHER | PMIX_PROC_CLIENT) #define PMIX_PROC_CLIENT_TOOL_ACT 0x20000000 #define PMIX_PROC_CLIENT_TOOL (PMIX_PROC_TOOL | PMIX_PROC_CLIENT | PMIX_PROC_CLIENT_TOOL_ACT) #define PMIX_PROC_GATEWAY_ACT 0x40000000 #define PMIX_PROC_GATEWAY (PMIX_PROC_SERVER | PMIX_PROC_GATEWAY_ACT) #define PMIX_PROC_SCHEDULER_ACT 0x80000000 #define PMIX_PROC_SCHEDULER (PMIX_PROC_SERVER | PMIX_PROC_SCHEDULER_ACT) #define PMIX_PROC_SYS_CTRLR_ACT 0x01000000 #define PMIX_PROC_SYS_CTRLR (PMIX_PROC_SERVER | PMIX_PROC_SYS_CTRLR_ACT) #define PMIX_SET_PEER_TYPE(a, b) (a)->proc_type.type |= (b) #define PMIX_SET_PROC_TYPE(a, b) (a)->type |= (b) /* define some convenience macros for testing proc type */ #define PMIX_PEER_IS_CLIENT(p) (PMIX_PROC_CLIENT & (p)->proc_type.type) #define PMIX_PEER_IS_SINGLETON(p) (PMIX_PROC_SINGLETON_ACT & (p)->proc_type.type) #define PMIX_PEER_IS_SERVER(p) (PMIX_PROC_SERVER & (p)->proc_type.type) #define PMIX_PEER_IS_TOOL(p) (PMIX_PROC_TOOL & (p)->proc_type.type) #define PMIX_PEER_IS_LAUNCHER(p) (PMIX_PROC_LAUNCHER_ACT & (p)->proc_type.type) #define PMIX_PEER_IS_CLIENT_LAUNCHER(p) \ ((PMIX_PROC_LAUNCHER_ACT & (p)->proc_type.type) && (PMIX_PROC_CLIENT & (p)->proc_type.type)) #define PMIX_PEER_IS_CLIENT_TOOL(p) \ ((PMIX_PROC_CLIENT_TOOL_ACT & (p)->proc_type.type) && (PMIX_PROC_CLIENT & (p)->proc_type.type)) #define PMIX_PEER_IS_GATEWAY(p) (PMIX_PROC_GATEWAY_ACT & (p)->proc_type.type) #define PMIX_PEER_IS_SCHEDULER(p) (PMIX_PROC_SCHEDULER_ACT & (p)->proc_type.type) #define PMIX_PEER_IS_SYS_CTRLR(p) (PMIX_PROC_SYS_CTRLR_ACT & (p)->proc_type.type) #define PMIX_PROC_IS_CLIENT(p) (PMIX_PROC_CLIENT & (p)->type) #define PMIX_PROC_IS_SERVER(p) (PMIX_PROC_SERVER & (p)->type) #define PMIX_PROC_IS_TOOL(p) (PMIX_PROC_TOOL & (p)->type) #define PMIX_PROC_IS_LAUNCHER(p) (PMIX_PROC_LAUNCHER_ACT & (p)->type) #define PMIX_PROC_IS_CLIENT_LAUNCHER(p) \ ((PMIX_PROC_LAUNCHER_ACT & (p)->type) && (PMIX_PROC_CLIENT & (p)->type)) #define PMIX_PROC_IS_CLIENT_TOOL(p) \ ((PMIX_PROC_CLIENT_TOOL_ACT & (p)->type) && (PMIX_PROC_CLIENT & (p)->type)) #define PMIX_PROC_IS_GATEWAY(p) (PMIX_PROC_GATEWAY_ACT & (p)->type) #define PMIX_PROC_IS_SCHEDULER(p) (PMIX_PROC_SCHEDULER_ACT & (p)->type) #define PMIX_PROC_IS_SYS_CTRLR(p) (PMIX_PROC_SYS_CTRLR_ACT & (p)->type) /* provide macros for setting the major, minor, and release values * just so people don't have to deal with the details of the struct */ #define PMIX_SET_PEER_VERSION(p, e, a, b) \ do { \ char *e2; \ unsigned long mj, mn, rl; \ if (NULL != e) { \ if ('v' == e[0]) { \ mj = strtoul(&e[1], &e2, 10); \ } else { \ mj = strtoul(e, &e2, 10); \ } \ ++e2; \ mn = strtoul(e2, &e2, 10); \ ++e2; \ rl = strtoul(e2, NULL, 10); \ PMIX_SET_PEER_MAJOR((p), mj); \ PMIX_SET_PEER_MINOR((p), mn); \ PMIX_SET_PEER_RELEASE((p), rl); \ } else { \ PMIX_SET_PEER_MAJOR((p), (a)); \ PMIX_SET_PEER_MINOR((p), (b)); \ } \ } while (0) #define PMIX_SET_PEER_MAJOR(p, a) (p)->proc_type.major = (a) #define PMIX_SET_PEER_MINOR(p, a) (p)->proc_type.minor = (a) #define PMIX_SET_PEER_RELEASE(p, a) (p)->proc_type.release = (a) #define PMIX_SET_PROC_MAJOR(p, a) (p)->major = (a) #define PMIX_SET_PROC_MINOR(p, a) (p)->minor = (a) #define PMIX_SET_PROC_RELEASE(p, a) (p)->release = (a) /* define some convenience macros for testing version */ #define PMIX_PEER_MAJOR_VERSION(p) (p)->proc_type.major #define PMIX_PEER_MINOR_VERSION(p) (p)->proc_type.minor #define PMIX_PEER_REL_VERSION(p) (p)->proc_type.release #define PMIX_PROC_MAJOR_VERSION(p) (p)->major #define PMIX_PROC_MINOR_VERSION(p) (p)->minor #define PMIX_PROC_REL_VERSION(p) (p)->release #define PMIX_PEER_IS_V1(p) ((p)->proc_type.major == 1) #define PMIX_PEER_IS_V20(p) ((p)->proc_type.major == 2 && (p)->proc_type.minor == 0) #define PMIX_PEER_IS_V21(p) ((p)->proc_type.major == 2 && (p)->proc_type.minor == 1) #define PMIX_PEER_IS_V3(p) ((p)->proc_type.major == 3) #define PMIX_PEER_IS_V40(p) ((p)->proc_type.major == 4 && (p)->proc_type.minor == 0) #define PMIX_PEER_IS_V41(p) ((p)->proc_type.major == 4 && (p)->proc_type.minor == 1) #define PMIX_PEER_TRIPLET(p, a, b, c) \ ((PMIX_PEER_MAJOR_VERSION(p) == PMIX_MAJOR_WILDCARD || (a) == PMIX_MAJOR_WILDCARD \ || PMIX_PEER_MAJOR_VERSION(p) == (a)) \ && (PMIX_PEER_MINOR_VERSION(p) == PMIX_MINOR_WILDCARD || (b) == PMIX_MINOR_WILDCARD \ || PMIX_PEER_MINOR_VERSION(p) == (b)) \ && (PMIX_PEER_REL_VERSION(p) == PMIX_RELEASE_WILDCARD || (c) == PMIX_RELEASE_WILDCARD \ || PMIX_PEER_REL_VERSION(p) == (c))) #define PMIX_PROC_TRIPLET(p, a, b, c) \ ((PMIX_PROC_MAJOR_VERSION(p) == PMIX_MAJOR_WILDCARD || PMIX_PROC_MAJOR_VERSION(p) == (a)) \ && (PMIX_PROC_MINOR_VERSION(p) == PMIX_MINOR_WILDCARD || PMIX_PROC_MINOR_VERSION(p) == (b)) \ && (PMIX_PROC_REL_VERSION(p) == PMIX_RELEASE_WILDCARD || PMIX_PROC_REL_VERSION(p) == (c))) #define PMIX_PEER_IS_EARLIER(p, a, b, c) pmix_ptl_base_peer_is_earlier(p, a, b, c) /**** MESSAGING STRUCTURES ****/ typedef uint32_t pmix_ptl_tag_t; /* define a range of "reserved" tags - these * are tags that are used for persistent recvs * within the system */ #define PMIX_PTL_TAG_NOTIFY 0 #define PMIX_PTL_TAG_HEARTBEAT 1 #define PMIX_PTL_TAG_IOF 2 /* define the start of dynamic tags that are * assigned for send/recv operations */ #define PMIX_PTL_TAG_DYNAMIC 100 /* header for messages */ typedef struct { int32_t pindex; pmix_ptl_tag_t tag; uint32_t nbytes; #if SIZEOF_SIZE_T == 8 uint32_t padding; #endif } pmix_ptl_hdr_t; /* define the messaging cbfunc */ typedef void (*pmix_ptl_cbfunc_t)(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); /* define a callback function for notifying that server connection * has completed */ typedef void (*pmix_ptl_connect_cbfunc_t)(pmix_status_t status, void *cbdata); /* define a callback function for processing pending connections */ typedef void (*pmix_ptl_pending_cbfunc_t)(int sd, short args, void *cbdata); /* structure for sending a message */ typedef struct { pmix_list_item_t super; pmix_event_t ev; pmix_ptl_hdr_t hdr; pmix_buffer_t *data; bool hdr_sent; char *sdptr; size_t sdbytes; } pmix_ptl_send_t; PMIX_CLASS_DECLARATION(pmix_ptl_send_t); /* structure for recving a message */ typedef struct { pmix_list_item_t super; pmix_event_t ev; struct pmix_peer_t *peer; int sd; pmix_ptl_hdr_t hdr; char *data; bool hdr_recvd; char *rdptr; size_t rdbytes; } pmix_ptl_recv_t; PMIX_CLASS_DECLARATION(pmix_ptl_recv_t); /* structure for tracking posted recvs */ typedef struct { pmix_list_item_t super; pmix_event_t ev; struct pmix_peer_t *peer; uint32_t tag; pmix_ptl_cbfunc_t cbfunc; void *cbdata; } pmix_ptl_posted_recv_t; PMIX_CLASS_DECLARATION(pmix_ptl_posted_recv_t); /* struct for posting send/recv request */ typedef struct { pmix_object_t super; volatile bool active; pmix_event_t ev; struct pmix_peer_t *peer; pmix_status_t status; pmix_buffer_t *bfr; pmix_ptl_cbfunc_t cbfunc; void *cbdata; } pmix_ptl_sr_t; PMIX_CLASS_DECLARATION(pmix_ptl_sr_t); typedef struct { pmix_object_t super; volatile bool active; pmix_event_t ev; struct pmix_peer_t *peer; pmix_buffer_t *buf; pmix_ptl_tag_t tag; } pmix_ptl_queue_t; PMIX_CLASS_DECLARATION(pmix_ptl_queue_t); /* define listener protocol types */ typedef uint16_t pmix_listener_protocol_t; #define PMIX_PROTOCOL_UNDEF 0 #define PMIX_PROTOCOL_V1 1 // legacy usock #define PMIX_PROTOCOL_V2 2 // tcp /* connection support */ typedef struct { pmix_object_t super; pmix_event_t ev; pmix_listener_protocol_t protocol; int sd; bool need_id; bool nspace_created; bool rinfo_created; pmix_rnd_flag_t flag; pmix_proc_t proc; pmix_info_t *info; size_t ninfo; pmix_status_t status; struct sockaddr_storage addr; struct pmix_peer_t *peer; char *version; char *bfrops; char *psec; char *gds; pmix_bfrop_buffer_type_t buffer_type; char *cred; size_t len; uid_t uid; gid_t gid; pmix_proc_type_t proc_type; } pmix_pending_connection_t; PMIX_CLASS_DECLARATION(pmix_pending_connection_t); /* listener objects */ typedef struct pmix_listener_t { pmix_list_item_t super; pmix_event_t ev; pmix_atomic_bool_t active; pmix_listener_protocol_t protocol; int socket; char *varname; char *uri; uint32_t owner; bool owner_given; uint32_t group; bool group_given; uint32_t mode; pmix_ptl_pending_cbfunc_t cbfunc; } pmix_listener_t; PMIX_CLASS_DECLARATION(pmix_listener_t); #define PMIX_LISTENER_STATIC_INIT \ { \ .super = PMIX_LIST_ITEM_STATIC_INIT, \ .active = false, \ .protocol = PMIX_PROTOCOL_UNDEF, \ .socket = 0, \ .varname = NULL, \ .uri = NULL, \ .owner = 0, \ .owner_given = false, \ .group = 0, \ .mode = 0, \ .cbfunc = NULL \ } /* provide a backdoor to the framework output for debugging */ PMIX_EXPORT extern int pmix_ptl_base_output; #define PMIX_ACTIVATE_POST_MSG(ms) \ do { \ pmix_event_assign(&((ms)->ev), pmix_globals.evbase, -1, EV_WRITE, \ pmix_ptl_base_process_msg, (ms)); \ PMIX_POST_OBJECT(ms); \ pmix_event_active(&((ms)->ev), EV_WRITE, 1); \ } while (0) #define PMIX_SND_CADDY(c, h, s) \ do { \ (c) = PMIX_NEW(pmix_server_caddy_t); \ (void) memcpy(&(c)->hdr, &(h), sizeof(pmix_ptl_hdr_t)); \ PMIX_RETAIN((s)); \ (c)->snd = (s); \ } while (0) /* queue a message to be sent to one of our procs - must * provide the following params: * p - pmix_peer_t of target recipient * t - tag to be sent to * b - buffer to be sent */ #define PMIX_SERVER_QUEUE_REPLY(r, p, t, b) \ do { \ pmix_ptl_send_t *snd; \ uint32_t nbytes; \ pmix_output_verbose(5, pmix_ptl_base_output, \ "[%s:%d] queue callback called: reply to %s:%d on tag %d size %d", \ __FILE__, __LINE__, (p)->info->pname.nspace, (p)->info->pname.rank, \ (t), (int) (b)->bytes_used); \ if ((p)->finalized) { \ (r) = PMIX_ERR_UNREACH; \ } else { \ snd = PMIX_NEW(pmix_ptl_send_t); \ snd->hdr.pindex = htonl(pmix_globals.pindex); \ snd->hdr.tag = htonl(t); \ nbytes = (b)->bytes_used; \ snd->hdr.nbytes = htonl(nbytes); \ snd->data = (b); \ /* always start with the header */ \ snd->sdptr = (char *) &snd->hdr; \ snd->sdbytes = sizeof(pmix_ptl_hdr_t); \ /* if there is no message on-deck, put this one there */ \ if (NULL == (p)->send_msg) { \ (p)->send_msg = snd; \ } else { \ /* add it to the queue */ \ pmix_list_append(&(p)->send_queue, &snd->super); \ } \ /* ensure the send event is active */ \ if (!(p)->send_ev_active && 0 <= (p)->sd) { \ (p)->send_ev_active = true; \ PMIX_POST_OBJECT(snd); \ pmix_event_add(&(p)->send_event, 0); \ } \ (r) = PMIX_SUCCESS; \ } \ } while (0) #define CLOSE_THE_SOCKET(s) \ do { \ if (0 <= (s)) { \ shutdown((s), 2); \ close((s)); \ (s) = -1; \ } \ } while (0) END_C_DECLS #endif /* PMIX_PTL_TYPES_H */ pmix-6.1.1~rc2/src/mca/ptl/Makefile.am0000664000175000017500000000255615203536752017667 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2016 Intel, Inc. All rights reserved # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(LTDLINCL) # main library setup noinst_LTLIBRARIES = libmca_ptl.la libmca_ptl_la_SOURCES = # local files headers = ptl.h ptl_types.h sources = # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.include libmca_ptl_la_SOURCES += $(headers) $(sources) distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/ptl/client/0000775000175000017500000000000015203536752017101 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/ptl/client/ptl_client_component.c0000664000175000017500000000576315203536752023477 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennptlee and The University * of Tennptlee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2017-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 IBM Corporation. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * These symbols are in a file by themselves to provide nice linker * semantics. Since linkers generally pull in symbols by object * files, keeping these symbols as the only symbols in this file * prevents utility programs such as "ompi_info" from having to import * entire components just to query their version and parameters. */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/mca/ptl/base/base.h" #include "src/mca/ptl/client/ptl_client.h" static int component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ PMIX_EXPORT pmix_ptl_base_component_t pmix_mca_ptl_client_component = { .base = { PMIX_PTL_BASE_VERSION_2_0_0, /* Component name and version */ .pmix_mca_component_name = "client", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_query_component = component_query }, .priority = 50 }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, ptl, client) static int component_query(pmix_mca_base_module_t **module, int *priority) { /* if I am not a client, then look elsewhere */ if (!PMIX_PEER_IS_CLIENT(pmix_globals.mypeer) || PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { *module = NULL; *priority = 0; return PMIX_ERR_TAKE_NEXT_OPTION; } *module = (pmix_mca_base_module_t *) &pmix_ptl_client_module; *priority = pmix_mca_ptl_client_component.priority; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/ptl/client/ptl_client.c0000664000175000017500000002063515203536752021410 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010-2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2011-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2018 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "src/include/pmix_globals.h" #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_DIRENT_H # include #endif #include "src/client/pmix_client_ops.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/gds.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_show_help.h" #include "ptl_client.h" #include "src/mca/ptl/base/base.h" static pmix_status_t connect_to_peer(struct pmix_peer_t *peer, pmix_info_t *info, size_t ninfo, char **suri); pmix_ptl_module_t pmix_ptl_client_module = { .name = "client", .connect_to_peer = connect_to_peer }; static pmix_status_t connect_to_peer(struct pmix_peer_t *pr, pmix_info_t *info, size_t ninfo, char **suriout) { char *evar = NULL, *suri = NULL; char *nspace = NULL; pmix_rank_t rank = PMIX_RANK_WILDCARD; char *rendfile = NULL; pmix_status_t rc; pmix_peer_t *peer = (pmix_peer_t *) pr; size_t m, n; char **tmp, *mycmd; void *ilist; pid_t mypid; pmix_info_t *iptr = NULL; size_t niptr = 0; pmix_data_array_t darray; pmix_list_t connections; pmix_connection_t *cn; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp: connecting to server"); /* see if we were given one */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SERVER_URI)) { /* separate out the server URI version(s) */ suri = strchr(info[n].value.data.string, ';'); if (NULL == suri) { return PMIX_ERR_BAD_PARAM; } *suri = '\0'; ++suri; evar = info[n].value.data.string; /* set the peer's module and type */ tmp = PMIx_Argv_split(evar, ':'); rc = PMIX_ERR_BAD_PARAM; for (m = 0; NULL != tmp[m]; m++) { rc = pmix_ptl_base_set_peer(peer, &tmp[m]); if (PMIX_SUCCESS == rc) { break; } } PMIx_Argv_free(tmp); if (PMIX_SUCCESS != rc) { return rc; } /* setup to process the URI */ evar = suri; break; } } /* provide our cmd line and PID */ PMIX_INFO_LIST_START(ilist); mypid = getpid(); PMIX_INFO_LIST_ADD(rc, ilist, PMIX_PROC_PID, &mypid, PMIX_PID); mycmd = pmix_ptl_base_get_cmd_line(); if (NULL != mycmd) { PMIX_INFO_LIST_ADD(rc, ilist, PMIX_CMD_LINE, mycmd, PMIX_STRING); free(mycmd); } PMIX_INFO_LIST_CONVERT(rc, ilist, &darray); if (PMIX_ERR_EMPTY == rc) { iptr = NULL; niptr = 0; } else if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_INFO_LIST_RELEASE(ilist); PMIX_LIST_DESTRUCT(&connections); return rc; } else { iptr = (pmix_info_t *) darray.array; niptr = darray.size; } PMIX_INFO_LIST_RELEASE(ilist); if (NULL == evar) { /* check the environment */ rc = pmix_ptl_base_set_peer(peer, &evar); if (PMIX_SUCCESS != rc) { /* we must be a singleton */ PMIX_SET_PEER_TYPE(pmix_globals.mypeer, PMIX_PROC_SINGLETON); /* if we weren't given one and don't have one * in the environment, we are allowed to check * for a system server */ pmix_globals.mypeer->nptr->compat.bfrops = pmix_bfrops_base_assign_module(NULL); pmix_client_globals.myserver->nptr->compat.bfrops = pmix_bfrops_base_assign_module(NULL); /* setup the system rendezvous file name */ if (0 > asprintf(&rendfile, "%s/pmix.sys.%s", pmix_ptl_base.system_tmpdir, pmix_globals.hostname)) { if (NULL != iptr) { PMIX_INFO_FREE(iptr, niptr); } return PMIX_ERR_NOMEM; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:client looking for system server at %s", rendfile); /* try to read the file */ PMIX_CONSTRUCT(&connections, pmix_list_t); rc = pmix_ptl_base_parse_uri_file(rendfile, true, &connections); free(rendfile); rendfile = NULL; if (PMIX_SUCCESS == rc && 0 < pmix_list_get_size(&connections)) { cn = (pmix_connection_t *) pmix_list_get_first(&connections); /* set our protocol to V2 as that is all we support */ pmix_globals.mypeer->protocol = PMIX_PROTOCOL_V2; peer->protocol = PMIX_PROTOCOL_V2; PMIX_SET_PEER_VERSION(peer, cn->version, 2, 0); /* go ahead and try to connect */ rc = pmix_ptl_base_make_connection(peer, cn->uri, iptr, niptr); if (PMIX_SUCCESS == rc) { /* don't free nspace - we will use it below */ nspace = cn->nspace; rank = cn->rank; suri = cn->uri; cn->nspace = NULL; cn->uri = NULL; PMIX_LIST_DESTRUCT(&connections); goto complete; } } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp:client is singleton"); PMIX_LIST_DESTRUCT(&connections); if (NULL != iptr) { PMIX_INFO_FREE(iptr, niptr); } return PMIX_ERR_UNREACH; } } /* the URI consists of the following elements: * - server nspace.rank * - ptl rendezvous URI */ rc = pmix_ptl_base_parse_uri(evar, &nspace, &rank, &suri); if (PMIX_SUCCESS != rc) { if (NULL != iptr) { PMIX_INFO_FREE(iptr, niptr); } return rc; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp:client attempt connect to %s:%u at %s", nspace, rank, suri); rc = pmix_ptl_base_make_connection(peer, suri, iptr, niptr); if (PMIX_SUCCESS != rc) { free(nspace); free(suri); if (NULL != iptr) { PMIX_INFO_FREE(iptr, niptr); } return rc; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "tcp_peer_try_connect: Connection across to peer %s:%u succeeded", nspace, rank); complete: /* mark the connection as made */ pmix_ptl_base_complete_connection(peer, nspace, rank); *suriout = suri; if (NULL != nspace) { free(nspace); } if (NULL != iptr) { PMIX_INFO_FREE(iptr, niptr); } return rc; } pmix-6.1.1~rc2/src/mca/ptl/client/ptl_client.h0000664000175000017500000000223115203536752021405 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2018 IBM Corporation. All rights reserved. * Copyright (c) 2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PTL_CLIENT_H #define PMIX_PTL_CLIENT_H #include "src/mca/ptl/ptl.h" BEGIN_C_DECLS extern pmix_ptl_base_component_t pmix_mca_ptl_client_component; extern pmix_ptl_module_t pmix_ptl_client_module; END_C_DECLS #endif /* PMIX_PTL_CLIENT_H */ pmix-6.1.1~rc2/src/mca/ptl/client/Makefile.am0000664000175000017500000000344515203536752021143 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = ptl_client.h sources = \ ptl_client_component.c \ ptl_client.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_ptl_client_DSO lib = lib_sources = component = pmix_mca_ptl_client.la component_sources = $(headers) $(sources) else lib = libpmix_mca_ptl_client.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_ptl_client_la_SOURCES = $(component_sources) pmix_mca_ptl_client_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_ptl_client_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_ptl_client_la_SOURCES = $(lib_sources) libpmix_mca_ptl_client_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/pmdl/0000775000175000017500000000000015203536752015760 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pmdl/ompi/0000775000175000017500000000000015203536752016724 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pmdl/ompi/pmdl_ompi_component.c0000664000175000017500000000655415203536752023144 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "pmdl_ompi.h" #include "src/mca/pmdl/pmdl.h" #include "src/util/pmix_argv.h" static pmix_status_t component_register(void); static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority); /* * Instantiate the public struct with all of our public information * and pointers to our public functions in it */ pmix_pmdl_ompi_component_t pmix_mca_pmdl_ompi_component = { .super = { PMIX_PMDL_BASE_VERSION_1_0_0, /* Component name and version */ .pmix_mca_component_name = "ompi", PMIX_MCA_BASE_MAKE_VERSION(component, PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION), /* Component open and close functions */ .pmix_mca_register_component_params = component_register, .pmix_mca_query_component = component_query, }, .include = NULL, .exclude = NULL }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pmdl, ompi) static pmix_status_t component_register(void) { pmix_mca_base_component_t *component = &pmix_mca_pmdl_ompi_component.super; pmix_mca_pmdl_ompi_component.incparms = "OMPI_*,OPAL_*"; (void) pmix_mca_base_component_var_register( component, "include_envars", "Comma-delimited list of envars to harvest (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pmdl_ompi_component.incparms); if (NULL != pmix_mca_pmdl_ompi_component.incparms) { pmix_mca_pmdl_ompi_component.include = PMIx_Argv_split(pmix_mca_pmdl_ompi_component.incparms, ','); } pmix_mca_pmdl_ompi_component.excparms = NULL; (void) pmix_mca_base_component_var_register( component, "exclude_envars", "Comma-delimited list of envars to exclude (\'*\' and \'?\' supported)", PMIX_MCA_BASE_VAR_TYPE_STRING, &pmix_mca_pmdl_ompi_component.excparms); if (NULL != pmix_mca_pmdl_ompi_component.excparms) { pmix_mca_pmdl_ompi_component.exclude = PMIx_Argv_split(pmix_mca_pmdl_ompi_component.excparms, ','); } return PMIX_SUCCESS; } static pmix_status_t component_query(pmix_mca_base_module_t **module, int *priority) { *priority = 55; *module = (pmix_mca_base_module_t *) &pmix_pmdl_ompi_module; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/mca/pmdl/ompi/pmdl_ompi.h0000664000175000017500000000132415203536752021055 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_PMDL_OMPI_H #define PMIX_PMDL_OMPI_H #include "src/include/pmix_config.h" #include "src/mca/pmdl/pmdl.h" BEGIN_C_DECLS typedef struct { pmix_pmdl_base_component_t super; char *incparms; char *excparms; char **include; char **exclude; } pmix_pmdl_ompi_component_t; /* the component must be visible data for the linker to find it */ PMIX_EXPORT extern pmix_pmdl_ompi_component_t pmix_mca_pmdl_ompi_component; extern pmix_pmdl_module_t pmix_pmdl_ompi_module; END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pmdl/ompi/pmdl_ompi.c0000664000175000017500000011157315203536752021060 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2026 Research Organization for Information Science * and Technology (RIST). All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_SYS_UTSNAME_H # include #endif #include #include "include/pmix.h" #include "src/class/pmix_list.h" #include "src/class/pmix_pointer_array.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_socket_errno.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/base/pmix_mca_base_vari.h" #include "src/mca/pinstalldirs/pinstalldirs.h" #include "src/mca/preg/preg.h" #include "src/util/pmix_alfg.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "pmdl_ompi.h" #include "src/mca/pmdl/base/base.h" #include "src/mca/pmdl/pmdl.h" static pmix_status_t ompi_init(void); static void ompi_finalize(void); static pmix_status_t harvest_envars(pmix_namespace_t *nptr, const pmix_info_t info[], size_t ninfo, pmix_list_t *ilist, char ***priors); static void parse_file_envars(pmix_list_t *ilist); static pmix_status_t setup_nspace(pmix_namespace_t *nptr, pmix_info_t *info); static pmix_status_t setup_nspace_kv(pmix_namespace_t *nptr, pmix_kval_t *kv); static pmix_status_t register_nspace(pmix_namespace_t *nptr); static pmix_status_t setup_fork(const pmix_proc_t *proc, char ***env, char ***priors); static void deregister_nspace(pmix_namespace_t *nptr); static void deregister_nspace(pmix_namespace_t *nptr); pmix_pmdl_module_t pmix_pmdl_ompi_module = { .name = "ompi", .init = ompi_init, .finalize = ompi_finalize, .harvest_envars = harvest_envars, .parse_file_envars = parse_file_envars, .setup_nspace = setup_nspace, .setup_nspace_kv = setup_nspace_kv, .register_nspace = register_nspace, .setup_fork = setup_fork, .deregister_nspace = deregister_nspace }; /* internal structures */ typedef struct { pmix_list_item_t super; pmix_nspace_t nspace; uint32_t univ_size; uint32_t job_size; uint32_t local_size; uint32_t num_apps; } pmdl_nspace_t; static void nscon(pmdl_nspace_t *p) { p->univ_size = UINT32_MAX; p->job_size = UINT32_MAX; p->local_size = UINT32_MAX; p->num_apps = UINT32_MAX; } static PMIX_CLASS_INSTANCE(pmdl_nspace_t, pmix_list_item_t, nscon, NULL); /* internal variables */ static pmix_list_t mynspaces; static pmix_list_t myenvars; static pmix_status_t ompi_init(void) { pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl: ompi init"); PMIX_CONSTRUCT(&mynspaces, pmix_list_t); PMIX_CONSTRUCT(&myenvars, pmix_list_t); return PMIX_SUCCESS; } static void ompi_finalize(void) { PMIX_LIST_DESTRUCT(&mynspaces); PMIX_LIST_DESTRUCT(&myenvars); } static bool checkus(const pmix_info_t info[], size_t ninfo) { bool takeus = false; size_t n; if (NULL == info) { return false; } /* check the directives */ for (n = 0; n < ninfo && !takeus; n++) { /* check the attribute */ if (PMIX_CHECK_KEY(&info[n], PMIX_PROGRAMMING_MODEL) || PMIX_CHECK_KEY(&info[n], PMIX_PERSONALITY)) { if (NULL != strstr(info[n].value.data.string, "ompi")) { takeus = true; break; } } } return takeus; } static pmix_status_t process_param_file(char *file, pmix_list_t *ilist) { pmix_list_t params; pmix_mca_base_var_file_value_t *fv; pmix_kval_t *kv; char *tmp; PMIX_CONSTRUCT(¶ms, pmix_list_t); pmix_mca_base_parse_paramfile(file, ¶ms); PMIX_LIST_FOREACH (fv, ¶ms, pmix_mca_base_var_file_value_t) { /* see if this param actually refers to a PMIx value */ if (pmix_pmdl_base_check_pmix_param(fv->mbvfv_var)) { kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { PMIX_LIST_DESTRUCT(¶ms); return PMIX_ERR_OUT_OF_RESOURCE; } kv->key = strdup(PMIX_SET_ENVAR); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); PMIX_LIST_DESTRUCT(¶ms); return PMIX_ERR_OUT_OF_RESOURCE; } kv->value->type = PMIX_ENVAR; pmix_asprintf(&tmp, "PMIX_MCA_%s", fv->mbvfv_var); PMIX_ENVAR_LOAD(&kv->value->data.envar, tmp, fv->mbvfv_value, ':'); free(tmp); pmix_list_append(ilist, &kv->super); continue; } /* see of this param actually refers to an old ORTE * or PRRTE value */ if (pmix_pmdl_base_check_prte_param(fv->mbvfv_var)) { kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { PMIX_LIST_DESTRUCT(¶ms); return PMIX_ERR_OUT_OF_RESOURCE; } kv->key = strdup(PMIX_SET_ENVAR); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); PMIX_LIST_DESTRUCT(¶ms); return PMIX_ERR_OUT_OF_RESOURCE; } kv->value->type = PMIX_ENVAR; pmix_asprintf(&tmp, "PRTE_MCA_%s", fv->mbvfv_var); PMIX_ENVAR_LOAD(&kv->value->data.envar, tmp, fv->mbvfv_value, ':'); free(tmp); pmix_list_append(ilist, &kv->super); continue; } /* assume this is an OMPI param - need to prefix the param name */ kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { PMIX_LIST_DESTRUCT(¶ms); return PMIX_ERR_OUT_OF_RESOURCE; } kv->key = strdup(PMIX_SET_ENVAR); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); PMIX_LIST_DESTRUCT(¶ms); return PMIX_ERR_OUT_OF_RESOURCE; } kv->value->type = PMIX_ENVAR; pmix_asprintf(&tmp, "OMPI_MCA_%s", fv->mbvfv_var); PMIX_ENVAR_LOAD(&kv->value->data.envar, tmp, fv->mbvfv_value, ':'); free(tmp); pmix_list_append(ilist, &kv->super); } PMIX_LIST_DESTRUCT(¶ms); return PMIX_SUCCESS; } static pmix_status_t harvest_envars(pmix_namespace_t *nptr, const pmix_info_t info[], size_t ninfo, pmix_list_t *ilist, char ***priors) { pmdl_nspace_t *ns, *ns2; pmix_status_t rc; uint32_t uid = UINT32_MAX; const char *home; pmix_mca_base_var_file_value_t *fv; pmix_kval_t *kv, *kptr; size_t n; char *file, *evar, *tmp; pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:ompi:harvest envars"); if (!checkus(info, ninfo)) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* don't do OMPI again if already done */ if (NULL != *priors) { char **t2 = *priors; for (n = 0; NULL != t2[n]; n++) { if (0 == strncmp(t2[n], "ompi", strlen("ompi"))) { return PMIX_ERR_TAKE_NEXT_OPTION; } } } /* flag that we worked on this */ PMIx_Argv_append_nosize(priors, "ompi"); pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:ompi:harvest envars active"); /* are we to harvest envars? */ for (n=0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_SETUP_APP_ENVARS)) { goto harvest; } } pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:ompi:harvest envars: NO"); return PMIX_ERR_TAKE_NEXT_OPTION; harvest: if (NULL != nptr) { /* see if we already have this nspace */ ns = NULL; PMIX_LIST_FOREACH (ns2, &mynspaces, pmdl_nspace_t) { if (PMIX_CHECK_NSPACE(ns2->nspace, nptr->nspace)) { ns = ns2; break; } } if (NULL == ns) { ns = PMIX_NEW(pmdl_nspace_t); PMIX_LOAD_NSPACE(ns->nspace, nptr->nspace); pmix_list_append(&mynspaces, &ns->super); } } /* check if the user has set OMPIHOME in their environment */ if (NULL != (evar = getenv("OMPIHOME"))) { /* look for the default MCA param file */ file = pmix_os_path(false, evar, "etc", "openmpi-mca-params.conf", NULL); rc = process_param_file(file, ilist); free(file); if (PMIX_SUCCESS != rc) { return rc; } /* add an envar indicating that we did this so the OMPI * processes won't duplicate it */ kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { return PMIX_ERR_OUT_OF_RESOURCE; } kv->key = strdup(PMIX_SET_ENVAR); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_OUT_OF_RESOURCE; } kv->value->type = PMIX_ENVAR; PMIX_ENVAR_LOAD(&kv->value->data.envar, "OPAL_SYS_PARAMS_GIVEN", "1", ':'); pmix_list_append(ilist, &kv->super); } /* see if the user has a default MCA param file */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_USERID)) { rc = PMIx_Value_get_number(&info[n].value, &uid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { return rc; } break; } } if (UINT32_MAX == uid) { uid = geteuid(); } /* try to get their home directory */ home = pmix_home_directory(uid); if (NULL != home) { file = pmix_os_path(false, home, ".openmpi", "mca-params.conf", NULL); rc = process_param_file(file, ilist); free(file); if (PMIX_SUCCESS != rc) { return rc; } /* add an envar indicating that we did this so the OMPI * processes won't duplicate it */ kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { return PMIX_ERR_OUT_OF_RESOURCE; } kv->key = strdup(PMIX_SET_ENVAR); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_OUT_OF_RESOURCE; } kv->value->type = PMIX_ENVAR; PMIX_ENVAR_LOAD(&kv->value->data.envar, "OPAL_USER_PARAMS_GIVEN", "1", ':'); pmix_list_append(ilist, &kv->super); } /* harvest our local envars */ if (NULL != pmix_mca_pmdl_ompi_component.include) { pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl: ompi harvesting envars %s excluding %s", (NULL == pmix_mca_pmdl_ompi_component.incparms) ? "NONE" : pmix_mca_pmdl_ompi_component.incparms, (NULL == pmix_mca_pmdl_ompi_component.excparms) ? "NONE" : pmix_mca_pmdl_ompi_component.excparms); rc = pmix_util_harvest_envars(pmix_mca_pmdl_ompi_component.include, pmix_mca_pmdl_ompi_component.exclude, ilist); if (PMIX_SUCCESS != rc) { return rc; } } /* check if one of the envars is OPAL_PREFIX as we need to * do more to set that up */ PMIX_LIST_FOREACH(kptr, ilist, pmix_kval_t) { if (0 == strcmp(kptr->value->data.envar.envar, "OPAL_PREFIX")) { // need to modify LD_LIBRARY_PATH as well - can only assume // that they used the same libdir name as we did evar = pmix_basename(pmix_pinstall_dirs.libdir); PMIX_KVAL_NEW(kv, PMIX_PREPEND_ENVAR); kv->value->type = PMIX_ENVAR; pmix_asprintf(&tmp, "%s/%s", kptr->value->data.envar.value, evar); free(evar); PMIX_ENVAR_LOAD(&kv->value->data.envar, "LD_LIBRARY_PATH", tmp, ':'); free(tmp); pmix_list_append(ilist, &kv->super); break; } } /* add in any OMPI-specific envars that were in an MCA * base paramfile since PMIx overlaps in that area */ PMIX_LIST_FOREACH(fv, &myenvars, pmix_mca_base_var_file_value_t) { kv = PMIX_NEW(pmix_kval_t); if (NULL == kv) { return PMIX_ERR_OUT_OF_RESOURCE; } kv->key = strdup(PMIX_SET_ENVAR); kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_OUT_OF_RESOURCE; } kv->value->type = PMIX_ENVAR; // the OMPI_MCA_ has already been prefixed PMIX_ENVAR_LOAD(&kv->value->data.envar, fv->mbvfv_var, fv->mbvfv_value, ':'); pmix_list_append(ilist, &kv->super); } return PMIX_SUCCESS; } // These frameworks are current as of 16 Sep, 2022, and are the list // of frameworks that are planned to be in Open MPI v5.0.0. static char *ompi_frameworks_static_5_0_0[] = { // Generic prefixes used by OMPI "mca", "opal", "ompi", /* OPAL frameworks */ "allocator", "backtrace", "btl", "dl", "hwloc", "if", "installdirs", "memchecker", "memcpy", "memory", "mpool", "patcher", "pmix", "rcache", "reachable", "shmem", "smsc", "threads", "timer", /* OMPI frameworks */ "mpi", /* global options set in runtime/ompi_mpi_params.c */ "bml", "coll", "fbtl", "fcoll", "fs", "hook", "io", "mtl", "op", "osc", "part", "pml", "sharedfp", "topo", "vprotocol", /* OSHMEM frameworks */ "memheap", "scoll", "spml", "sshmem", NULL, }; static char **ompi_frameworks = ompi_frameworks_static_5_0_0; static bool ompi_frameworks_setup = false; static void setup_ompi_frameworks(void) { if (ompi_frameworks_setup) { return; } ompi_frameworks_setup = true; char *env = getenv("OMPI_MCA_PREFIXES"); if (NULL == env) { return; } // If we found the env variable, it will be a comma-delimited list // of values. Split it into an argv-style array. char **tmp = PMIx_Argv_split(env, ','); if (NULL != tmp) { ompi_frameworks = tmp; } } static void parse_file_envars(pmix_list_t *ilist) { pmix_mca_base_var_file_value_t *fv, *fvsave; char *tmp; // ensure we have the current list of frameworks setup_ompi_frameworks(); // scan the list for values directed at OMPI // frameworks/components PMIX_LIST_FOREACH_SAFE (fv, fvsave, ilist, pmix_mca_base_var_file_value_t) { for (int j = 0; NULL != ompi_frameworks[j]; j++) { if (0 == strncmp(fv->mbvfv_var, ompi_frameworks[j], strlen(ompi_frameworks[j]))) { pmix_list_remove_item(ilist, &fv->super); pmix_asprintf(&tmp, "OMPI_MCA_%s", fv->mbvfv_var); free(fv->mbvfv_var); fv->mbvfv_var = tmp; pmix_list_append(&myenvars, &fv->super); break; } } } } static pmix_status_t setup_nspace(pmix_namespace_t *nptr, pmix_info_t *info) { pmdl_nspace_t *ns, *ns2; pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:ompi: setup nspace for nspace %s with %s", nptr->nspace, info->value.data.string); if (!checkus(info, 1)) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* see if we already have this nspace */ ns = NULL; PMIX_LIST_FOREACH (ns2, &mynspaces, pmdl_nspace_t) { if (PMIX_CHECK_NSPACE(ns2->nspace, nptr->nspace)) { ns = ns2; break; } } if (NULL == ns) { ns = PMIX_NEW(pmdl_nspace_t); PMIX_LOAD_NSPACE(ns->nspace, nptr->nspace); pmix_list_append(&mynspaces, &ns->super); } return PMIX_SUCCESS; } static pmix_status_t setup_nspace_kv(pmix_namespace_t *nptr, pmix_kval_t *kv) { pmdl_nspace_t *ns, *ns2; char **tmp, *ptr; size_t m; uint vers; bool takeus = false; pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:ompi: setup nspace_kv for nspace %s with %s", nptr->nspace, kv->value->data.string); /* check the attribute */ if (PMIX_CHECK_KEY(kv, PMIX_PROGRAMMING_MODEL) || PMIX_CHECK_KEY(kv, PMIX_PERSONALITY)) { tmp = PMIx_Argv_split(kv->value->data.string, ','); for (m = 0; NULL != tmp[m]; m++) { if (0 == strcmp(tmp[m], "ompi")) { /* they didn't specify a level, so we will service * them just in case */ takeus = true; break; } if (0 == strncmp(tmp[m], "ompi", 4)) { /* if they specifically requested an ompi level greater * than or equal to us, then we service it */ ptr = &tmp[m][4]; vers = strtoul(ptr, NULL, 10); if (vers >= 5) { takeus = true; } break; } } PMIx_Argv_free(tmp); } if (!takeus) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* see if we already have this nspace */ ns = NULL; PMIX_LIST_FOREACH (ns2, &mynspaces, pmdl_nspace_t) { if (PMIX_CHECK_NSPACE(ns2->nspace, nptr->nspace)) { ns = ns2; break; } } if (NULL == ns) { ns = PMIX_NEW(pmdl_nspace_t); PMIX_LOAD_NSPACE(ns->nspace, nptr->nspace); pmix_list_append(&mynspaces, &ns->super); } return PMIX_SUCCESS; } static pmix_status_t register_nspace(pmix_namespace_t *nptr) { pmdl_nspace_t *ns, *ns2; char *ev1, **tmp; pmix_proc_t wildcard, undef; pmix_status_t rc; pmix_kval_t *kv; pmix_info_t info[2]; uint32_t n; pmix_cb_t cb; pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:ompi: register_nspace for %s", nptr->nspace); /* see if we already have this nspace */ ns = NULL; PMIX_LIST_FOREACH (ns2, &mynspaces, pmdl_nspace_t) { if (PMIX_CHECK_NSPACE(ns2->nspace, nptr->nspace)) { ns = ns2; break; } } if (NULL == ns) { /* we don't know anything about this one or * it doesn't have any ompi-based apps */ return PMIX_ERR_TAKE_NEXT_OPTION; } /* do we already have the data we need here? Servers are * allowed to call register_nspace multiple times with * different info, so we really need to recheck those * values that haven't already been filled */ PMIX_LOAD_PROCID(&wildcard, nptr->nspace, PMIX_RANK_WILDCARD); /* fetch the universe size */ if (UINT32_MAX == ns->univ_size) { PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &wildcard; cb.copy = true; cb.key = PMIX_UNIV_SIZE; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); cb.key = NULL; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); ns->univ_size = kv->value->data.uint32; PMIX_DESTRUCT(&cb); } /* fetch the job size */ if (UINT32_MAX == ns->job_size) { PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &wildcard; cb.copy = true; cb.key = PMIX_JOB_SIZE; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); cb.key = NULL; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); ns->job_size = kv->value->data.uint32; PMIX_DESTRUCT(&cb); } /* fetch the number of apps */ if (UINT32_MAX == ns->num_apps) { PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &wildcard; cb.copy = true; cb.key = PMIX_JOB_NUM_APPS; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); cb.key = NULL; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); ns->num_apps = kv->value->data.uint32; PMIX_DESTRUCT(&cb); } /* fetch the number of local peers */ if (UINT32_MAX == ns->local_size) { PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &wildcard; cb.copy = true; cb.key = PMIX_LOCAL_SIZE; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); cb.key = NULL; /* it is okay if there are no local procs */ if (PMIX_SUCCESS == rc) { /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); ns->local_size = kv->value->data.uint32; PMIX_DESTRUCT(&cb); } } if (1 == ns->num_apps) { return PMIX_SUCCESS; } /* construct the list of app sizes */ PMIX_LOAD_PROCID(&undef, nptr->nspace, PMIX_RANK_UNDEF); PMIX_INFO_LOAD(&info[0], PMIX_APP_INFO, NULL, PMIX_BOOL); tmp = NULL; for (n = 0; n < ns->num_apps; n++) { PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &undef; cb.copy = true; cb.info = info; cb.ninfo = 2; cb.key = PMIX_APP_SIZE; PMIX_INFO_LOAD(&info[1], PMIX_APPNUM, &n, PMIX_UINT32); PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); PMIX_INFO_DESTRUCT(&info[1]); cb.key = NULL; cb.info = NULL; cb.ninfo = 0; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); pmix_asprintf(&ev1, "%u", kv->value->data.uint32); PMIx_Argv_append_nosize(&tmp, ev1); free(ev1); PMIX_DESTRUCT(&cb); } PMIX_INFO_DESTRUCT(&info[0]); if (NULL != tmp) { ev1 = PMIx_Argv_join(tmp, ' '); PMIx_Argv_free(tmp); PMIX_INFO_LOAD(&info[0], "OMPI_APP_SIZES", ev1, PMIX_STRING); free(ev1); PMIX_GDS_CACHE_JOB_INFO(rc, pmix_globals.mypeer, nptr, info, 1); PMIX_INFO_DESTRUCT(&info[0]); } /* construct the list of app leaders */ PMIX_INFO_LOAD(&info[0], PMIX_APP_INFO, NULL, PMIX_BOOL); tmp = NULL; for (n = 0; n < ns->num_apps; n++) { PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &undef; cb.copy = true; cb.info = info; cb.ninfo = 2; cb.key = PMIX_APPLDR; PMIX_INFO_LOAD(&info[1], PMIX_APPNUM, &n, PMIX_UINT32); PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); PMIX_INFO_DESTRUCT(&info[1]); cb.key = NULL; cb.info = NULL; cb.ninfo = 0; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); pmix_asprintf(&ev1, "%u", kv->value->data.uint32); PMIx_Argv_append_nosize(&tmp, ev1); free(ev1); PMIX_DESTRUCT(&cb); } PMIX_INFO_DESTRUCT(&info[0]); if (NULL != tmp) { ev1 = PMIx_Argv_join(tmp, ' '); PMIx_Argv_free(tmp); tmp = NULL; PMIX_INFO_LOAD(&info[0], "OMPI_FIRST_RANKS", ev1, PMIX_STRING); free(ev1); PMIX_GDS_CACHE_JOB_INFO(rc, pmix_globals.mypeer, nptr, info, 1); PMIX_INFO_DESTRUCT(&info[0]); } return PMIX_SUCCESS; } static pmix_status_t setup_fork(const pmix_proc_t *proc, char ***env, char ***priors) { pmdl_nspace_t *ns, *ns2; char *param; char *ev1, **tmp; pmix_proc_t wildcard, undef; pmix_status_t rc; uint16_t u16; pmix_kval_t *kv; pmix_info_t info[2]; uint32_t n; pmix_cb_t cb; pmix_mca_base_var_file_value_t *fv; pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:ompi: setup fork for %s", PMIX_NAME_PRINT(proc)); /* don't do OMPI again if already done */ if (NULL != *priors) { char **t2 = *priors; for (n = 0; NULL != t2[n]; n++) { if (0 == strncmp(t2[n], "ompi", 4)) { return PMIX_ERR_TAKE_NEXT_OPTION; } } } /* flag that we worked on this */ PMIx_Argv_append_nosize(priors, "ompi"); /* see if we already have this nspace */ ns = NULL; PMIX_LIST_FOREACH (ns2, &mynspaces, pmdl_nspace_t) { if (PMIX_CHECK_NSPACE(ns2->nspace, proc->nspace)) { ns = ns2; break; } } if (NULL == ns) { /* we don't know anything about this one or * it doesn't have any ompi-based apps */ return PMIX_ERR_TAKE_NEXT_OPTION; } PMIX_LOAD_PROCID(&wildcard, proc->nspace, PMIX_RANK_WILDCARD); PMIX_LOAD_PROCID(&undef, proc->nspace, PMIX_RANK_UNDEF); /* pass universe size */ if (0 > asprintf(¶m, "%u", ns->univ_size)) { return PMIX_ERR_NOMEM; } PMIx_Setenv("OMPI_UNIVERSE_SIZE", param, true, env); free(param); /* pass the comm_world size in various formats */ if (0 > asprintf(¶m, "%u", ns->job_size)) { return PMIX_ERR_NOMEM; } PMIx_Setenv("OMPI_COMM_WORLD_SIZE", param, true, env); PMIx_Setenv("OMPI_WORLD_SIZE", param, true, env); PMIx_Setenv("OMPI_MCA_num_procs", param, true, env); free(param); /* pass the local size in various formats */ if (0 > asprintf(¶m, "%u", ns->local_size)) { return PMIX_ERR_NOMEM; } PMIx_Setenv("OMPI_COMM_WORLD_LOCAL_SIZE", param, true, env); PMIx_Setenv("OMPI_WORLD_LOCAL_SIZE", param, true, env); free(param); /* pass the number of apps in the job */ if (0 > asprintf(¶m, "%u", ns->num_apps)) { return PMIX_ERR_NOMEM; } PMIx_Setenv("OMPI_NUM_APP_CTX", param, true, env); free(param); /* pass an envar so the proc can find any files it had prepositioned */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = (pmix_proc_t *) proc; cb.copy = true; cb.key = PMIX_PROCDIR; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); cb.key = NULL; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); PMIx_Setenv("OMPI_FILE_LOCATION", kv->value->data.string, true, env); PMIX_DESTRUCT(&cb); /* pass the cwd */ PMIX_INFO_LOAD(&info[0], PMIX_APP_INFO, NULL, PMIX_BOOL); PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &undef; cb.copy = true; cb.info = info; cb.ninfo = 2; cb.key = PMIX_WDIR; PMIX_INFO_LOAD(&info[1], PMIX_APPNUM, &pmix_globals.appnum, PMIX_UINT32); PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); PMIX_INFO_DESTRUCT(&info[1]); cb.key = NULL; cb.info = NULL; cb.ninfo = 0; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); PMIx_Setenv("OMPI_MCA_initial_wdir", kv->value->data.string, true, env); PMIX_DESTRUCT(&cb); PMIX_INFO_DESTRUCT(&info[0]); /* pass its command. */ PMIX_INFO_LOAD(&info[0], PMIX_APP_INFO, NULL, PMIX_BOOL); PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &undef; cb.copy = true; cb.info = info; cb.ninfo = 2; cb.key = PMIX_APP_ARGV; PMIX_INFO_LOAD(&info[1], PMIX_APPNUM, &pmix_globals.appnum, PMIX_UINT32); PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); PMIX_INFO_DESTRUCT(&info[1]); cb.key = NULL; cb.info = NULL; cb.ninfo = 0; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); tmp = PMIx_Argv_split(kv->value->data.string, ' '); PMIX_DESTRUCT(&cb); PMIX_INFO_DESTRUCT(&info[0]); PMIx_Setenv("OMPI_COMMAND", tmp[0], true, env); ev1 = PMIx_Argv_join(&tmp[1], ' '); PMIx_Setenv("OMPI_ARGV", ev1, true, env); free(ev1); PMIx_Argv_free(tmp); /* pass the arch - if available */ #ifdef HAVE_SYS_UTSNAME_H struct utsname sysname; memset(&sysname, 0, sizeof(sysname)); if (-1 < uname(&sysname)) { if (sysname.machine[0] != '\0') { PMIx_Setenv("OMPI_MCA_cpu_type", (const char *) &sysname.machine, true, env); } } #endif /* pass the rank */ if (0 > asprintf(¶m, "%lu", (unsigned long) proc->rank)) { return PMIX_ERR_NOMEM; } PMIx_Setenv("OMPI_COMM_WORLD_RANK", param, true, env); free(param); /* done with this now */ /* get the proc's local rank */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = (pmix_proc_t *) proc; cb.copy = true; cb.key = PMIX_LOCAL_RANK; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); cb.key = NULL; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); u16 = kv->value->data.uint16; PMIX_DESTRUCT(&cb); if (0 > asprintf(¶m, "%lu", (unsigned long) u16)) { return PMIX_ERR_NOMEM; } PMIx_Setenv("OMPI_COMM_WORLD_LOCAL_RANK", param, true, env); free(param); /* get the proc's node rank */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = (pmix_proc_t *) proc; cb.copy = true; cb.key = PMIX_NODE_RANK; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); cb.key = NULL; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); u16 = kv->value->data.uint16; PMIX_DESTRUCT(&cb); if (0 > asprintf(¶m, "%lu", (unsigned long) u16)) { return PMIX_ERR_NOMEM; } PMIx_Setenv("OMPI_COMM_WORLD_NODE_RANK", param, true, env); free(param); if (1 == ns->num_apps) { return PMIX_SUCCESS; } PMIX_LOAD_PROCID(&undef, proc->nspace, PMIX_RANK_UNDEF); PMIX_INFO_LOAD(&info[0], PMIX_APP_INFO, NULL, PMIX_BOOL); tmp = NULL; for (n = 0; n < ns->num_apps; n++) { PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &undef; cb.copy = true; cb.info = info; cb.ninfo = 2; cb.key = PMIX_APP_SIZE; PMIX_INFO_LOAD(&info[1], PMIX_APPNUM, &n, PMIX_UINT32); PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); PMIX_INFO_DESTRUCT(&info[1]); cb.key = NULL; cb.info = NULL; cb.ninfo = 0; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); pmix_asprintf(&ev1, "%u", kv->value->data.uint32); PMIx_Argv_append_nosize(&tmp, ev1); free(ev1); PMIX_DESTRUCT(&cb); } PMIX_INFO_DESTRUCT(&info[0]); if (NULL != tmp) { ev1 = PMIx_Argv_join(tmp, ' '); PMIx_Argv_free(tmp); PMIx_Setenv("OMPI_APP_CTX_NUM_PROCS", ev1, true, env); free(ev1); } PMIX_INFO_LOAD(&info[0], PMIX_APP_INFO, NULL, PMIX_BOOL); tmp = NULL; for (n = 0; n < ns->num_apps; n++) { PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &undef; cb.copy = true; cb.info = info; cb.ninfo = 2; cb.key = PMIX_APPLDR; PMIX_INFO_LOAD(&info[1], PMIX_APPNUM, &n, PMIX_UINT32); PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); PMIX_INFO_DESTRUCT(&info[1]); cb.key = NULL; cb.info = NULL; cb.ninfo = 0; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); pmix_asprintf(&ev1, "%u", kv->value->data.uint32); PMIx_Argv_append_nosize(&tmp, ev1); free(ev1); PMIX_DESTRUCT(&cb); } PMIX_INFO_DESTRUCT(&info[0]); if (NULL != tmp) { ev1 = PMIx_Argv_join(tmp, ' '); PMIx_Argv_free(tmp); tmp = NULL; PMIx_Setenv("OMPI_FIRST_RANKS", ev1, true, env); free(ev1); } /* provide the reincarnation number */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = (pmix_proc_t *) proc; cb.copy = true; cb.key = PMIX_REINCARNATION; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb); cb.key = NULL; if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* the data is the first value on the cb.kvs list */ if (1 != pmix_list_get_size(&cb.kvs)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); PMIX_DESTRUCT(&cb); return PMIX_ERR_BAD_PARAM; } kv = (pmix_kval_t *) pmix_list_get_first(&cb.kvs); pmix_asprintf(&ev1, "%u", kv->value->data.uint32); PMIx_Setenv("OMPI_MCA_num_restarts", ev1, true, env); free(ev1); PMIX_DESTRUCT(&cb); /* add any envars we collected from param files */ PMIX_LIST_FOREACH(fv, &myenvars, pmix_mca_base_var_file_value_t) { PMIx_Setenv(fv->mbvfv_var, fv->mbvfv_value, true, env); } return PMIX_SUCCESS; } static void deregister_nspace(pmix_namespace_t *nptr) { pmdl_nspace_t *ns; /* find our tracker for this nspace */ PMIX_LIST_FOREACH (ns, &mynspaces, pmdl_nspace_t) { if (PMIX_CHECK_NSPACE(ns->nspace, nptr->nspace)) { pmix_list_remove_item(&mynspaces, &ns->super); PMIX_RELEASE(ns); return; } } } pmix-6.1.1~rc2/src/mca/pmdl/ompi/Makefile.am0000664000175000017500000000365015203536752020764 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers = pmdl_ompi.h sources = \ pmdl_ompi_component.c \ pmdl_ompi.c # Make the output library in this directory, and name it either # mca__.la (for DSO builds) or libmca__.la # (for static builds). if MCA_BUILD_pmix_pmdl_ompi_DSO lib = lib_sources = component = pmix_mca_pmdl_ompi.la component_sources = $(headers) $(sources) else lib = libpmix_mca_pmdl_ompi.la lib_sources = $(headers) $(sources) component = component_sources = endif mcacomponentdir = $(pmixlibdir) mcacomponent_LTLIBRARIES = $(component) pmix_mca_pmdl_ompi_la_SOURCES = $(component_sources) pmix_mca_pmdl_ompi_la_LDFLAGS = -module -avoid-version if NEED_LIBPMIX pmix_mca_pmdl_ompi_la_LIBADD = $(top_builddir)/src/libpmix.la endif noinst_LTLIBRARIES = $(lib) libpmix_mca_pmdl_ompi_la_SOURCES = $(lib_sources) libpmix_mca_pmdl_ompi_la_LDFLAGS = -module -avoid-version pmix-6.1.1~rc2/src/mca/pmdl/base/0000775000175000017500000000000015203536752016672 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pmdl/base/pmdl_base_select.c0000664000175000017500000001142115203536752022322 0ustar alastairalastair/* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/mca/pmdl/base/base.h" /* Function for selecting a prioritized list of components * from all those that are available. */ int pmix_pmdl_base_select(void) { pmix_mca_base_component_list_item_t *cli = NULL; pmix_mca_base_component_t *component = NULL; pmix_mca_base_module_t *module = NULL; pmix_pmdl_module_t *nmodule; pmix_pmdl_base_active_module_t *newmodule, *mod; int rc, priority; bool inserted; if (pmix_pmdl_globals.selected) { /* ensure we don't do this twice */ return PMIX_SUCCESS; } pmix_pmdl_globals.selected = true; /* Query all available components and ask if they have a module */ PMIX_LIST_FOREACH (cli, &pmix_pmdl_base_framework.framework_components, pmix_mca_base_component_list_item_t) { component = (pmix_mca_base_component_t *) cli->cli_component; pmix_output_verbose(5, pmix_pmdl_base_framework.framework_output, "mca:pmdl:select: checking available component %s", component->pmix_mca_component_name); /* If there's no query function, skip it */ if (NULL == component->pmix_mca_query_component) { pmix_output_verbose( 5, pmix_pmdl_base_framework.framework_output, "mca:pmdl:select: Skipping component [%s]. It does not implement a query function", component->pmix_mca_component_name); continue; } /* Query the component */ pmix_output_verbose(5, pmix_pmdl_base_framework.framework_output, "mca:pmdl:select: Querying component [%s]", component->pmix_mca_component_name); rc = component->pmix_mca_query_component(&module, &priority); /* If no module was returned, then skip component */ if (PMIX_SUCCESS != rc || NULL == module) { pmix_output_verbose( 5, pmix_pmdl_base_framework.framework_output, "mca:pmdl:select: Skipping component [%s]. Query failed to return a module", component->pmix_mca_component_name); continue; } /* If we got a module, keep it */ nmodule = (pmix_pmdl_module_t *) module; /* let it initialize */ if (NULL != nmodule->init && PMIX_SUCCESS != nmodule->init()) { continue; } /* add to the list of selected modules */ newmodule = PMIX_NEW(pmix_pmdl_base_active_module_t); newmodule->pri = priority; newmodule->module = nmodule; newmodule->component = (pmix_pmdl_base_component_t *) cli->cli_component; /* maintain priority order */ inserted = false; PMIX_LIST_FOREACH (mod, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { if (priority > mod->pri) { pmix_list_insert_pos(&pmix_pmdl_globals.actives, (pmix_list_item_t *) mod, &newmodule->super); inserted = true; break; } } if (!inserted) { /* must be lowest priority - add to end */ pmix_list_append(&pmix_pmdl_globals.actives, &newmodule->super); } } if (4 < pmix_output_get_verbosity(pmix_pmdl_base_framework.framework_output)) { pmix_output(0, "Final pmdl priorities"); /* show the prioritized list */ PMIX_LIST_FOREACH (mod, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { pmix_output(0, "\tpmdl: %s Priority: %d", mod->component->pmix_mca_component_name, mod->pri); } } return PMIX_SUCCESS; ; } pmix-6.1.1~rc2/src/mca/pmdl/base/base.h0000664000175000017500000000652415203536752017764 0ustar alastairalastair/* -*- C -*- * * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PMDL_BASE_H_ #define PMIX_PMDL_BASE_H_ #include "src/include/pmix_config.h" #ifdef HAVE_SYS_TIME_H # include /* for struct timeval */ #endif #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/class/pmix_pointer_array.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/mca.h" #include "src/mca/pmdl/pmdl.h" BEGIN_C_DECLS /* * MCA Framework */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_pmdl_base_framework; /** * PMDL select function * * Cycle across available components and construct the list * of active modules */ PMIX_EXPORT pmix_status_t pmix_pmdl_base_select(void); /** * Track an active component / module */ struct pmix_pmdl_base_active_module_t { pmix_list_item_t super; int pri; pmix_pmdl_module_t *module; pmix_pmdl_base_component_t *component; }; typedef struct pmix_pmdl_base_active_module_t pmix_pmdl_base_active_module_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_pmdl_base_active_module_t); /* framework globals */ struct pmix_pmdl_globals_t { pmix_lock_t lock; pmix_list_t actives; bool initialized; bool selected; }; typedef struct pmix_pmdl_globals_t pmix_pmdl_globals_t; PMIX_EXPORT extern pmix_pmdl_globals_t pmix_pmdl_globals; PMIX_EXPORT pmix_status_t pmix_pmdl_base_harvest_envars(char *nspace, const pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); PMIX_EXPORT void pmix_pmdl_base_parse_file_envars(pmix_list_t *ilist); PMIX_EXPORT bool pmix_pmdl_base_check_prte_param(char *param); PMIX_EXPORT bool pmix_pmdl_base_check_pmix_param(char *param); PMIX_EXPORT pmix_status_t pmix_pmdl_base_setup_nspace(pmix_namespace_t *nptr, pmix_info_t *info); PMIX_EXPORT pmix_status_t pmix_pmdl_base_setup_nspace_kv(pmix_namespace_t *nptr, pmix_kval_t *kv); PMIX_EXPORT pmix_status_t pmix_pmdl_base_register_nspace(pmix_namespace_t *nptr); PMIX_EXPORT pmix_status_t pmix_pmdl_base_setup_client(pmix_namespace_t *nptr, pmix_rank_t rank, uint32_t appnum); PMIX_EXPORT pmix_status_t pmix_pmdl_base_setup_fork(const pmix_proc_t *peer, char ***env); PMIX_EXPORT void pmix_pmdl_base_deregister_nspace(const char *nptr); END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pmdl/base/pmdl_base_frame.c0000664000175000017500000001214715203536752022143 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2009 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2020 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file: * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_STRING_H # include #endif #include "src/class/pmix_list.h" #include "src/mca/base/pmix_base.h" #include "src/mca/base/pmix_mca_base_alias.h" #include "src/mca/pmdl/base/base.h" /* * The following file was created by configure. It contains extern * statements and the definition of an array of pointers to each * component's public mca_base_component_t struct. */ #include "src/mca/pmdl/base/static-components.h" /* Instantiate the global vars */ pmix_pmdl_globals_t pmix_pmdl_globals = { .lock = PMIX_LOCK_STATIC_INIT, .actives = PMIX_LIST_STATIC_INIT, .initialized = false, .selected = false }; pmix_pmdl_API_module_t pmix_pmdl = { .harvest_envars = pmix_pmdl_base_harvest_envars, .parse_file_envars = pmix_pmdl_base_parse_file_envars, .setup_nspace = pmix_pmdl_base_setup_nspace, .setup_nspace_kv = pmix_pmdl_base_setup_nspace_kv, .register_nspace = pmix_pmdl_base_register_nspace, .setup_client = pmix_pmdl_base_setup_client, .setup_fork = pmix_pmdl_base_setup_fork, .deregister_nspace = pmix_pmdl_base_deregister_nspace}; static int pmix_pmdl_register(pmix_mca_base_register_flag_t flags) { if (PMIX_MCA_BASE_REGISTER_STATIC_ONLY == flags) { return PMIX_SUCCESS; } /* Note that we break abstraction rules here by listing a specific PMDL here in the base. This is necessary, however, due to extraordinary circumstances: 1. In PMIx v4.0.1, we want to unify the "ompi5" and "ompi4" components to be "ompi" to more closely represent its usage. 2. The MCA aliasing mechanism was therefore ported from OMPI for this purpose. Both the component itself and all of its MCA vars are aliased. 3. However -- at least as currently implemented -- by the time individual components are registered, it's too late to make aliases. Hence, if we want to preserve the prior names for some semblance of backwards compatibility (and we do!), we have to register "ompi" as an "alias for xxx" up here in the PMDL base, before any PMDL components are registered. This is why we tolerate this abstraction break up here in the PMDL component base. */ (void) pmix_mca_base_alias_register("pmix", "pmdl", "ompi", "ompi5", PMIX_MCA_BASE_ALIAS_FLAG_NONE); (void) pmix_mca_base_alias_register("pmix", "pmdl", "ompi", "ompi4", PMIX_MCA_BASE_ALIAS_FLAG_NONE); return PMIX_SUCCESS; } static pmix_status_t pmix_pmdl_close(void) { pmix_pmdl_base_active_module_t *active, *prev; if (!pmix_pmdl_globals.initialized) { return PMIX_SUCCESS; } pmix_pmdl_globals.initialized = false; pmix_pmdl_globals.selected = false; PMIX_LIST_FOREACH_SAFE (active, prev, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { pmix_list_remove_item(&pmix_pmdl_globals.actives, &active->super); if (NULL != active->module->finalize) { active->module->finalize(); } PMIX_RELEASE(active); } PMIX_DESTRUCT(&pmix_pmdl_globals.actives); PMIX_DESTRUCT_LOCK(&pmix_pmdl_globals.lock); return pmix_mca_base_framework_components_close(&pmix_pmdl_base_framework, NULL); } static pmix_status_t pmix_pmdl_open(pmix_mca_base_open_flag_t flags) { /* initialize globals */ pmix_pmdl_globals.initialized = true; PMIX_CONSTRUCT_LOCK(&pmix_pmdl_globals.lock); pmix_pmdl_globals.lock.active = false; PMIX_CONSTRUCT(&pmix_pmdl_globals.actives, pmix_list_t); /* Open up all available components */ return pmix_mca_base_framework_components_open(&pmix_pmdl_base_framework, flags); } PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, pmdl, "PMIx Network Operations", pmix_pmdl_register, pmix_pmdl_open, pmix_pmdl_close, pmix_mca_pmdl_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_DEFAULT); PMIX_CLASS_INSTANCE(pmix_pmdl_base_active_module_t, pmix_list_item_t, NULL, NULL); pmix-6.1.1~rc2/src/mca/pmdl/base/Makefile.include0000664000175000017500000000232315203536752021754 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.am does not stand on its own - it is included from # src/Makefile.am headers += \ base/base.h sources += \ base/pmdl_base_frame.c \ base/pmdl_base_select.c \ base/pmdl_base_stubs.c pmix-6.1.1~rc2/src/mca/pmdl/base/pmdl_base_stubs.c0000664000175000017500000002737415203536752022221 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_SYS_UTSNAME_H # include #endif #include #include "pmix_common.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_frameworks.h" #include "src/class/pmix_list.h" #include "src/mca/base/pmix_mca_base_vari.h" #include "src/mca/preg/preg.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "src/mca/pmdl/base/base.h" pmix_status_t pmix_pmdl_base_harvest_envars(char *nspace, const pmix_info_t info[], size_t ninfo, pmix_list_t *ilist) { pmix_pmdl_base_active_module_t *active; pmix_status_t rc; pmix_namespace_t *nptr = NULL, *ns; char *params[2] = {"PMIX_MCA_", NULL}; char **priors = NULL, *tmp; pmix_kval_t *kv; pmix_mca_base_var_file_value_t *fv; if (!pmix_pmdl_globals.initialized) { return PMIX_ERR_INIT; } pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:harvest envars called"); /* protect against bozo inputs */ if (NULL == ilist) { return PMIX_ERR_BAD_PARAM; } /* start by adding in the vars found in the default param * files, if any - this will allow the model-specific * components to override those values, if necessary */ PMIX_LIST_FOREACH(fv, &pmix_mca_base_var_file_values, pmix_mca_base_var_file_value_t) { PMIX_KVAL_NEW(kv, PMIX_SET_ENVAR); if (NULL == kv) { return PMIX_ERR_NOMEM; } if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_ENVAR; pmix_asprintf(&tmp, "PMIX_MCA_%s", fv->mbvfv_var); PMIX_ENVAR_LOAD(&kv->value->data.envar, tmp, fv->mbvfv_value, ':'); free(tmp); pmix_list_append(ilist, &kv->super); } PMIX_LIST_FOREACH(fv, &pmix_mca_base_var_override_values, pmix_mca_base_var_file_value_t) { PMIX_KVAL_NEW(kv, PMIX_SET_ENVAR); if (NULL == kv) { return PMIX_ERR_NOMEM; } if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_ENVAR; pmix_asprintf(&tmp, "PMIX_MCA_%s", fv->mbvfv_var); PMIX_ENVAR_LOAD(&kv->value->data.envar, tmp, fv->mbvfv_value, ':'); free(tmp); pmix_list_append(ilist, &kv->super); } if (NULL != nspace && 0 < strlen(nspace)) { /* find this nspace - note that it may not have * been registered yet */ PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strcmp(ns->nspace, nspace)) { nptr = ns; break; } } if (NULL == nptr) { /* add it */ nptr = PMIX_NEW(pmix_namespace_t); if (NULL == nptr) { return PMIX_ERR_NOMEM; } nptr->nspace = strdup(nspace); pmix_list_append(&pmix_globals.nspaces, &nptr->super); } } /* process the request */ PMIX_LIST_FOREACH (active, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { if (NULL != active->module->harvest_envars) { rc = active->module->harvest_envars(nptr, info, ninfo, ilist, &priors); if (PMIX_SUCCESS != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { /* true error */ PMIx_Argv_free(priors); return rc; } } } PMIx_Argv_free(priors); /* add any local PMIx MCA params */ rc = pmix_util_harvest_envars(params, NULL, ilist); // mark that we are passing the PMIx envars PMIX_KVAL_NEW(kv, PMIX_SET_ENVAR); if (NULL == kv) { return PMIX_ERR_NOMEM; } if (NULL == kv->value) { PMIX_RELEASE(kv); return PMIX_ERR_NOMEM; } kv->value->type = PMIX_ENVAR; PMIX_ENVAR_LOAD(&kv->value->data.envar, "PMIX_PARAM_FILE_PASSED", "1", ':'); pmix_list_append(ilist, &kv->super); return PMIX_SUCCESS; } static char *prte_frameworks_static_3_0_1[] = { "errmgr", "ess", "filem", "grpcomm", "iof", "odls", "oob", "plm", "prtebacktrace", "prtedl", "prteinstalldirs", "prtereachable", "ras", "rmaps", "rml", "routed", "rtc", "schizo", "state", // inherited from OPAL "hwloc", "if", "reachable", NULL, }; static char **prte_frameworks = prte_frameworks_static_3_0_1; static bool prte_frameworks_setup = false; static void setup_prte_frameworks(void) { if (prte_frameworks_setup) { return; } prte_frameworks_setup = true; char *env = getenv("PRTE_MCA_PREFIXES"); if (NULL == env) { return; } // If we found the env variable, it will be a comma-delimited list // of values. Split it into an argv-style array. char **tmp = PMIx_Argv_split(env, ','); if (NULL != tmp) { prte_frameworks = tmp; } } bool pmix_pmdl_base_check_prte_param(char *param) { char *p; size_t n; int len, len2; setup_prte_frameworks(); p = strchr(param, '_'); if (NULL == p) { len = strlen(param); } else { len = (int)(p - param); } if (0 == strncmp(param, "prte", len)) { return true; } for (n=0; NULL != prte_frameworks[n]; n++) { len2 = strlen(prte_frameworks[n]); if (len != len2) { continue; } if (0 == strncmp(param, prte_frameworks[n], len)) { return true; } } return false; } bool pmix_pmdl_base_check_pmix_param(char *param) { char *p; size_t n; int len, len2; p = strchr(param, '_'); if (NULL == p) { len = strlen(param); } else { len = (int)(p - param); } if (0 == strncmp(param, "pmix", len)) { return true; } for (n=0; NULL != pmix_framework_names[n]; n++) { len2 = strlen(pmix_framework_names[n]); if (len != len2) { continue; } if (0 == strncmp(param, pmix_framework_names[n], len)) { return true; } } return false; } void pmix_pmdl_base_parse_file_envars(pmix_list_t *ilist) { pmix_pmdl_base_active_module_t *active; /* process the request */ PMIX_LIST_FOREACH (active, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { if (NULL != active->module->parse_file_envars) { active->module->parse_file_envars(ilist); } } } pmix_status_t pmix_pmdl_base_setup_nspace(pmix_namespace_t *nptr, pmix_info_t *info) { pmix_pmdl_base_active_module_t *active; pmix_status_t rc; if (!pmix_pmdl_globals.initialized) { return PMIX_ERR_INIT; } pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:setup_nspace called"); /* process the request */ PMIX_LIST_FOREACH (active, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { if (NULL != active->module->setup_nspace) { rc = active->module->setup_nspace(nptr, info); if (PMIX_SUCCESS != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { /* true error */ return rc; } } } return PMIX_SUCCESS; } pmix_status_t pmix_pmdl_base_setup_nspace_kv(pmix_namespace_t *nptr, pmix_kval_t *kv) { pmix_pmdl_base_active_module_t *active; pmix_status_t rc; if (!pmix_pmdl_globals.initialized) { return PMIX_ERR_INIT; } pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:setup_nspace called"); /* process the request */ PMIX_LIST_FOREACH (active, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { if (NULL != active->module->setup_nspace_kv) { rc = active->module->setup_nspace_kv(nptr, kv); if (PMIX_SUCCESS != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { /* true error */ return rc; } } } return PMIX_SUCCESS; } pmix_status_t pmix_pmdl_base_register_nspace(pmix_namespace_t *nptr) { pmix_pmdl_base_active_module_t *active; pmix_status_t rc; if (!pmix_pmdl_globals.initialized) { return PMIX_ERR_INIT; } pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl:register_nspace called"); /* process the request */ PMIX_LIST_FOREACH (active, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { if (NULL != active->module->register_nspace) { rc = active->module->register_nspace(nptr); if (PMIX_SUCCESS != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { /* true error */ return rc; } } } return PMIX_SUCCESS; } /* can only be called by a server */ pmix_status_t pmix_pmdl_base_setup_client(pmix_namespace_t *nptr, pmix_rank_t rank, uint32_t appnum) { pmix_pmdl_base_active_module_t *active; pmix_status_t rc; if (!pmix_pmdl_globals.initialized) { return PMIX_ERR_INIT; } pmix_output_verbose(2, pmix_pmdl_base_framework.framework_output, "pmdl: setup_client called"); PMIX_LIST_FOREACH (active, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { if (NULL != active->module->setup_client) { rc = active->module->setup_client(nptr, rank, appnum); if (PMIX_SUCCESS != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { /* true error */ return rc; } } } return PMIX_SUCCESS; } /* can only be called by a server */ pmix_status_t pmix_pmdl_base_setup_fork(const pmix_proc_t *proc, char ***env) { pmix_pmdl_base_active_module_t *active; pmix_status_t rc; char **priors = NULL; if (!pmix_pmdl_globals.initialized) { return PMIX_ERR_INIT; } PMIX_LIST_FOREACH (active, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { if (NULL != active->module->setup_fork) { rc = active->module->setup_fork(proc, env, &priors); if (PMIX_SUCCESS != rc && PMIX_ERR_TAKE_NEXT_OPTION != rc) { /* true error */ PMIx_Argv_free(priors); return rc; } } } PMIx_Argv_free(priors); return PMIX_SUCCESS; } void pmix_pmdl_base_deregister_nspace(const char *ns) { pmix_pmdl_base_active_module_t *active; pmix_namespace_t *nptr, *n2; if (!pmix_pmdl_globals.initialized) { return; } /* search for the namespace */ nptr = NULL; PMIX_LIST_FOREACH (n2, &pmix_globals.nspaces, pmix_namespace_t) { if (0 == strncmp(ns, n2->nspace, PMIX_MAX_NSLEN)) { nptr = n2; break; } } if (NULL == nptr) { return; } PMIX_LIST_FOREACH (active, &pmix_pmdl_globals.actives, pmix_pmdl_base_active_module_t) { if (NULL != active->module->deregister_nspace) { active->module->deregister_nspace(nptr); } } } pmix-6.1.1~rc2/src/mca/pmdl/pmdl.h0000664000175000017500000001402715203536752017071 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved. * * Copyright (c) 2015-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * This interface is for use by PMIx servers to obtain network-related info * such as security keys that need to be shared across applications, and to * setup network support for applications prior to launch * * Available plugins may be defined at runtime via the typical MCA parameter * syntax. */ #ifndef PMIX_PMDL_H #define PMIX_PMDL_H #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/base/pmix_mca_base_var.h" #include "src/mca/mca.h" #include "src/server/pmix_server_ops.h" BEGIN_C_DECLS /****** MODULE DEFINITION ******/ /** * Initialize the module. Returns an error if the module cannot * run, success if it can and wants to be used. */ typedef pmix_status_t (*pmix_pmdl_base_module_init_fn_t)(void); /** * Finalize the module. Tear down any allocated storage, disconnect * from any system support (e.g., LDAP server) */ typedef void (*pmix_pmdl_base_module_fini_fn_t)(void); /* Harvest envars for this programming model so they can be forwarded * to backend processes */ typedef pmix_status_t (*pmix_pmdl_base_module_harvest_envars_fn_t)(pmix_namespace_t *nptr, const pmix_info_t info[], size_t ninfo, pmix_list_t *ilist, char ***priors); /* Check a list of pmix_mca_base_var_file_value_t items that were * read from a file to see if any belong to this programming * model - if they do, then cache them for passing to any nspaces * during harvest_envars */ typedef void (*pmix_pmdl_base_module_parse_file_envars_fn_t)(pmix_list_t *ilist); /** * Setup any programming model specific support for the given nspace */ typedef pmix_status_t (*pmix_pmdl_base_module_setup_ns_fn_t)(pmix_namespace_t *nptr, pmix_info_t *info); typedef pmix_status_t (*pmix_pmdl_base_module_setup_ns_kv_fn_t)(pmix_namespace_t *nptr, pmix_kval_t *kv); /* Allow programming models to add key-value pairs to the job-info - they * can directly cache them in the GDS */ typedef pmix_status_t (*pmix_pmdl_base_module_reg_nspace_fn_t)(pmix_namespace_t *nptr); /** * Setup any programming model specific support for the given client */ typedef pmix_status_t (*pmix_pmdl_base_module_setup_client_fn_t)(pmix_namespace_t *nptr, pmix_rank_t rank, uint32_t apppnum); /** * Give the plugins an opportunity to add any envars to the * environment of a local application process prior to fork/exec */ typedef pmix_status_t (*pmix_pmdl_base_module_setup_fork_fn_t)(const pmix_proc_t *peer, char ***env, char ***priors); /** * Provide an opportunity for the fabric components to cleanup any * resources they may have created to track the nspace */ typedef void (*pmix_pmdl_base_module_dregister_nspace_fn_t)(pmix_namespace_t *nptr); /** * Base structure for a PMDL module. Each component should malloc a * copy of the module structure for each fabric plane they support. */ typedef struct { char *name; pmix_pmdl_base_module_init_fn_t init; pmix_pmdl_base_module_fini_fn_t finalize; pmix_pmdl_base_module_harvest_envars_fn_t harvest_envars; pmix_pmdl_base_module_parse_file_envars_fn_t parse_file_envars; pmix_pmdl_base_module_setup_ns_fn_t setup_nspace; pmix_pmdl_base_module_setup_ns_kv_fn_t setup_nspace_kv; pmix_pmdl_base_module_reg_nspace_fn_t register_nspace; pmix_pmdl_base_module_setup_client_fn_t setup_client; pmix_pmdl_base_module_setup_fork_fn_t setup_fork; pmix_pmdl_base_module_dregister_nspace_fn_t deregister_nspace; } pmix_pmdl_module_t; /* define a public API */ typedef pmix_status_t (*pmix_pmdl_base_API_harvest_envars_fn_t)(char *nspace, const pmix_info_t info[], size_t ninfo, pmix_list_t *ilist); typedef pmix_status_t (*pmix_pmdl_base_API_setup_fork_fn_t)(const pmix_proc_t *peer, char ***env); typedef void (*pmix_pmdl_base_API_dregister_nspace_fn_t)(const char *nptr); typedef struct { char *name; pmix_pmdl_base_module_init_fn_t init; pmix_pmdl_base_module_fini_fn_t finalize; pmix_pmdl_base_API_harvest_envars_fn_t harvest_envars; pmix_pmdl_base_module_parse_file_envars_fn_t parse_file_envars; pmix_pmdl_base_module_setup_ns_fn_t setup_nspace; pmix_pmdl_base_module_setup_ns_kv_fn_t setup_nspace_kv; pmix_pmdl_base_module_reg_nspace_fn_t register_nspace; pmix_pmdl_base_module_setup_client_fn_t setup_client; pmix_pmdl_base_API_setup_fork_fn_t setup_fork; pmix_pmdl_base_API_dregister_nspace_fn_t deregister_nspace; } pmix_pmdl_API_module_t; /* declare the global APIs */ PMIX_EXPORT extern pmix_pmdl_API_module_t pmix_pmdl; /* * the standard component data structure */ typedef pmix_mca_base_component_t pmix_pmdl_base_component_t; /* * Macro for use in components that are of type pmdl */ #define PMIX_PMDL_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("pmdl", 1, 0, 0) END_C_DECLS #endif pmix-6.1.1~rc2/src/mca/pmdl/Makefile.am0000664000175000017500000000255015203536752020016 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2019 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = $(LTDLINCL) # main library setup noinst_LTLIBRARIES = libmca_pmdl.la libmca_pmdl_la_SOURCES = # local files headers = pmdl.h sources = # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.include libmca_pmdl_la_SOURCES += $(headers) $(sources) distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/pinstalldirs/0000775000175000017500000000000015203536752017534 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pinstalldirs/env/0000775000175000017500000000000015203536752020324 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pinstalldirs/env/configure.m40000664000175000017500000000166315203536752022555 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2006 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2016-2017 Intel, Inc. All rights reserved. # Copyright (c) 2016 Research Organization for Information Science # and Technology (RIST). All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AC_DEFUN([MCA_pmix_pinstalldirs_env_PRIORITY], [10]) AC_DEFUN([MCA_pmix_pinstalldirs_env_COMPILE_MODE], [ AC_MSG_CHECKING([for MCA component $1:$2 compile mode]) $3="static" AC_MSG_RESULT([$$3]) ]) # MCA_pinstalldirs_config_CONFIG(action-if-can-compile, # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pinstalldirs_env_CONFIG], [ AC_CONFIG_FILES([src/mca/pinstalldirs/env/Makefile]) ]) pmix-6.1.1~rc2/src/mca/pinstalldirs/env/Makefile.am0000664000175000017500000000100015203536752022347 0ustar alastairalastair# # Copyright (c) 2006 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # noinst_LTLIBRARIES = libpmix_mca_pinstalldirs_env.la libpmix_mca_pinstalldirs_env_la_SOURCES = \ pmix_pinstalldirs_env.c pmix-6.1.1~rc2/src/mca/pinstalldirs/env/pmix_pinstalldirs_env.c0000664000175000017500000000650115203536752025107 0ustar alastairalastair/* * Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include "pmix_common.h" #include "src/mca/pinstalldirs/pinstalldirs.h" static void pinstalldirs_env_init(pmix_info_t info[], size_t ninfo); pmix_pinstalldirs_base_component_t pmix_mca_pinstalldirs_env_component = { /* First, the mca_component_t struct containing meta information about the component itself */ .component = { PMIX_PINSTALLDIRS_BASE_VERSION_1_0_0, /* Component name and version */ "env", PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION, }, /* Next the pmix_pinstall_dirs_t install_dirs_data information */ .install_dirs_data = { .prefix = NULL, .exec_prefix = NULL, .bindir = NULL, .sbindir = NULL, .libexecdir = NULL, .datarootdir = NULL, .datadir = NULL, .sysconfdir = NULL, .sharedstatedir = NULL, .localstatedir = NULL, .libdir = NULL, .includedir = NULL, .infodir = NULL, .mandir = NULL, .pmixdatadir = NULL, .pmixlibdir = NULL, .pmixincludedir = NULL }, .init = pinstalldirs_env_init }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pinstalldirs, env) #define SET_FIELD(field, envname) \ do { \ char *tmp = getenv(envname); \ if (NULL != tmp && 0 == strlen(tmp)) { \ tmp = NULL; \ } \ pmix_mca_pinstalldirs_env_component.install_dirs_data.field = tmp; \ } while (0) static void pinstalldirs_env_init(pmix_info_t info[], size_t ninfo) { size_t n; bool prefix_given = false; /* check for a prefix value */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_PREFIX)) { pmix_mca_pinstalldirs_env_component.install_dirs_data.prefix = info[n].value.data.string; prefix_given = true; break; } } if (!prefix_given) { SET_FIELD(prefix, "PMIX_PREFIX"); } SET_FIELD(exec_prefix, "PMIX_EXEC_PREFIX"); SET_FIELD(bindir, "PMIX_BINDIR"); SET_FIELD(sbindir, "PMIX_SBINDIR"); SET_FIELD(libexecdir, "PMIX_LIBEXECDIR"); SET_FIELD(datarootdir, "PMIX_DATAROOTDIR"); SET_FIELD(datadir, "PMIX_DATADIR"); SET_FIELD(sysconfdir, "PMIX_SYSCONFDIR"); SET_FIELD(sharedstatedir, "PMIX_SHAREDSTATEDIR"); SET_FIELD(localstatedir, "PMIX_LOCALSTATEDIR"); SET_FIELD(libdir, "PMIX_LIBDIR"); SET_FIELD(includedir, "PMIX_INCLUDEDIR"); SET_FIELD(infodir, "PMIX_INFODIR"); SET_FIELD(mandir, "PMIX_MANDIR"); SET_FIELD(pmixdatadir, "PMIX_PKGDATADIR"); SET_FIELD(pmixlibdir, "PMIX_PKGLIBDIR"); SET_FIELD(pmixincludedir, "PMIX_PKGINCLUDEDIR"); } pmix-6.1.1~rc2/src/mca/pinstalldirs/configure.m40000664000175000017500000000046515203536752021764 0ustar alastairalastairdnl -*- shell-script -*- dnl dnl Copyright (c) 2006-2010 Sandia National Laboratories. All rights reserved. dnl Copyright (c) 2016 Intel, Inc. All rights reserved. dnl $COPYRIGHT$ dnl dnl Additional copyrights may follow dnl dnl $HEADER$ dnl AC_DEFUN([MCA_pmix_pinstalldirs_CONFIGURE_MODE], [PRIORITY]) pmix-6.1.1~rc2/src/mca/pinstalldirs/base/0000775000175000017500000000000015203536752020446 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pinstalldirs/base/pinstalldirs_base_expand.c0000664000175000017500000001553415203536752025663 0ustar alastairalastair/* * Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2007-2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2007 Sun Microsystem, Inc. All rights reserved. * Copyright (c) 2010 Sandia National Laboratories. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include #include "src/mca/pinstalldirs/base/base.h" #include "src/mca/pinstalldirs/pinstalldirs.h" #include "src/util/pmix_os_path.h" /* Support both ${name} and @{name} forms. The latter allows us to pass values through AC_SUBST without being munged by m4 (e.g., if we want to pass "@{libdir}" and not have it replaced by m4 to be whatever the actual value of the shell variable is. */ #define EXPAND_STRING(name) EXPAND_STRING2(name, name) #define EXPAND_STRING2(ompiname, fieldname) \ do { \ if (NULL != (start_pos = strstr(retval, "${" #fieldname "}"))) { \ tmp = retval; \ *start_pos = '\0'; \ end_pos = start_pos + strlen("${" #fieldname "}"); \ if (0 > asprintf(&retval, "%s%s%s", tmp, pmix_pinstall_dirs.ompiname + destdir_offset, \ end_pos)) { \ pmix_output(0, "NOMEM"); \ } \ free(tmp); \ changed = true; \ } else if (NULL != (start_pos = strstr(retval, "@{" #fieldname "}"))) { \ tmp = retval; \ *start_pos = '\0'; \ end_pos = start_pos + strlen("@{" #fieldname "}"); \ if (0 > asprintf(&retval, "%s%s%s", tmp, pmix_pinstall_dirs.ompiname + destdir_offset, \ end_pos)) { \ pmix_output(0, "NOMEM"); \ } \ free(tmp); \ changed = true; \ } \ } while (0) /* * Read the lengthy comment below to understand the value of the * is_setup parameter. */ static char *pmix_pinstall_dirs_expand_internal(const char *input, bool is_setup) { size_t len, i; bool needs_expand = false; char *retval = NULL; char *destdir = NULL; size_t destdir_offset = 0; /* This is subtle, and worth explaining. If we substitute in any ${FIELD} values, we need to prepend it with the value of the $PMIX_DESTDIR environment variable -- if it is set. We need to handle at least three cases properly (assume that configure was invoked with --prefix=/opt/pmix and no other directory specifications, and PMIX_DESTDIR is set to /tmp/buildroot): 1. Individual directories, such as libdir. These need to be prepended with DESTDIR. I.e., return /tmp/buildroot/opt/pmix/lib. 2. Compiler flags that have ${FIELD} values embedded in them. For example, consider if a wrapper compiler data file contains the line: preprocessor_flags=-DMYFLAG="${prefix}/share/randomthingy/" The value we should return is: -DMYFLAG="/tmp/buildroot/opt/pmix/share/randomthingy/" 3. Compiler flags that do not have any ${FIELD} values. For example, consider if a wrapper compiler data file contains the line: preprocessor_flags=-pthread The value we should return is: -pthread Note, too, that this PMIX_DESTDIR futzing only needs to occur during pmix_init(). By the time pmix_init() has completed, all values should be substituted in that need substituting. Hence, we take an extra parameter (is_setup) to know whether we should do this futzing or not. */ if (is_setup) { destdir = getenv("PMIX_DESTDIR"); if (NULL != destdir && strlen(destdir) > 0) { destdir_offset = strlen(destdir); } } len = strlen(input); for (i = 0; i < len; ++i) { if ('$' == input[i] || '@' == input[i]) { needs_expand = true; break; } } retval = strdup(input); if (NULL == retval) return NULL; if (needs_expand) { bool changed = false; char *start_pos, *end_pos, *tmp; do { changed = false; EXPAND_STRING(prefix); EXPAND_STRING(exec_prefix); EXPAND_STRING(bindir); EXPAND_STRING(sbindir); EXPAND_STRING(libexecdir); EXPAND_STRING(datarootdir); EXPAND_STRING(datadir); EXPAND_STRING(sysconfdir); EXPAND_STRING(sharedstatedir); EXPAND_STRING(localstatedir); EXPAND_STRING(libdir); EXPAND_STRING(includedir); EXPAND_STRING(infodir); EXPAND_STRING(mandir); EXPAND_STRING2(pmixdatadir, pkgdatadir); EXPAND_STRING2(pmixlibdir, pkglibdir); EXPAND_STRING2(pmixincludedir, pkgincludedir); } while (changed); } if (NULL != destdir) { char *tmp = retval; retval = pmix_os_path(false, destdir, tmp, NULL); free(tmp); } return retval; } char *pmix_pinstall_dirs_expand(const char *input) { /* We do NOT want PMIX_DESTDIR expansion in this case. */ return pmix_pinstall_dirs_expand_internal(input, false); } char *pmix_pinstall_dirs_expand_setup(const char *input) { /* We DO want PMIX_DESTDIR expansion in this case. */ return pmix_pinstall_dirs_expand_internal(input, true); } pmix-6.1.1~rc2/src/mca/pinstalldirs/base/pinstalldirs_base_components.c0000664000175000017500000002041415203536752026562 0ustar alastairalastair/* * Copyright (c) 2006-2012 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 Sandia National Laboratories. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/mca/mca.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/mca/pinstalldirs/base/static-components.h" #include "src/mca/pinstalldirs/pinstalldirs.h" pmix_pinstall_dirs_t pmix_pinstall_dirs = { .prefix = NULL, .exec_prefix = NULL, .bindir = NULL, .sbindir = NULL, .libexecdir = NULL, .datarootdir = NULL, .datadir = NULL, .sysconfdir = NULL, .sharedstatedir = NULL, .localstatedir = NULL, .libdir = NULL, .includedir = NULL, .infodir = NULL, .mandir = NULL, .pmixdatadir = NULL, .pmixlibdir = NULL, .pmixincludedir = NULL }; #define CONDITIONAL_COPY(target, origin, field) \ do { \ if (origin.field != NULL && target.field == NULL) { \ target.field = origin.field; \ } \ } while (0) static int pmix_pinstalldirs_base_open(pmix_mca_base_open_flag_t flags) { return pmix_mca_base_framework_components_open(&pmix_pinstalldirs_base_framework, flags); } int pmix_pinstall_dirs_base_init(pmix_info_t info[], size_t ninfo) { pmix_mca_base_component_list_item_t *component_item; PMIX_LIST_FOREACH (component_item, &pmix_pinstalldirs_base_framework.framework_components, pmix_mca_base_component_list_item_t) { const pmix_pinstalldirs_base_component_t *component = (const pmix_pinstalldirs_base_component_t *) component_item->cli_component; if (NULL != component->init) { component->init(info, ninfo); } /* copy over the data, if something isn't already there */ CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, prefix); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, exec_prefix); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, bindir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, sbindir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, libexecdir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, datarootdir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, datadir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, sysconfdir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, sharedstatedir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, localstatedir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, libdir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, includedir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, infodir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, mandir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, pmixdatadir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, pmixlibdir); CONDITIONAL_COPY(pmix_pinstall_dirs, component->install_dirs_data, pmixincludedir); } /* expand out all the fields */ pmix_pinstall_dirs.prefix = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.prefix); pmix_pinstall_dirs.exec_prefix = pmix_pinstall_dirs_expand_setup( pmix_pinstall_dirs.exec_prefix); pmix_pinstall_dirs.bindir = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.bindir); pmix_pinstall_dirs.sbindir = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.sbindir); pmix_pinstall_dirs.libexecdir = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.libexecdir); pmix_pinstall_dirs.datarootdir = pmix_pinstall_dirs_expand_setup( pmix_pinstall_dirs.datarootdir); pmix_pinstall_dirs.datadir = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.datadir); pmix_pinstall_dirs.sysconfdir = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.sysconfdir); pmix_pinstall_dirs.sharedstatedir = pmix_pinstall_dirs_expand_setup( pmix_pinstall_dirs.sharedstatedir); pmix_pinstall_dirs.localstatedir = pmix_pinstall_dirs_expand_setup( pmix_pinstall_dirs.localstatedir); pmix_pinstall_dirs.libdir = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.libdir); pmix_pinstall_dirs.includedir = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.includedir); pmix_pinstall_dirs.infodir = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.infodir); pmix_pinstall_dirs.mandir = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.mandir); pmix_pinstall_dirs.pmixdatadir = pmix_pinstall_dirs_expand_setup( pmix_pinstall_dirs.pmixdatadir); pmix_pinstall_dirs.pmixlibdir = pmix_pinstall_dirs_expand_setup(pmix_pinstall_dirs.pmixlibdir); pmix_pinstall_dirs.pmixincludedir = pmix_pinstall_dirs_expand_setup( pmix_pinstall_dirs.pmixincludedir); #if 0 fprintf(stderr, "prefix: %s\n", pmix_pinstall_dirs.prefix); fprintf(stderr, "exec_prefix: %s\n", pmix_pinstall_dirs.exec_prefix); fprintf(stderr, "bindir: %s\n", pmix_pinstall_dirs.bindir); fprintf(stderr, "sbindir: %s\n", pmix_pinstall_dirs.sbindir); fprintf(stderr, "libexecdir: %s\n", pmix_pinstall_dirs.libexecdir); fprintf(stderr, "datarootdir: %s\n", pmix_pinstall_dirs.datarootdir); fprintf(stderr, "datadir: %s\n", pmix_pinstall_dirs.datadir); fprintf(stderr, "sysconfdir: %s\n", pmix_pinstall_dirs.sysconfdir); fprintf(stderr, "sharedstatedir: %s\n", pmix_pinstall_dirs.sharedstatedir); fprintf(stderr, "localstatedir: %s\n", pmix_pinstall_dirs.localstatedir); fprintf(stderr, "libdir: %s\n", pmix_pinstall_dirs.libdir); fprintf(stderr, "includedir: %s\n", pmix_pinstall_dirs.includedir); fprintf(stderr, "infodir: %s\n", pmix_pinstall_dirs.infodir); fprintf(stderr, "mandir: %s\n", pmix_pinstall_dirs.mandir); fprintf(stderr, "pkgdatadir: %s\n", pmix_pinstall_dirs.pkgdatadir); fprintf(stderr, "pkglibdir: %s\n", pmix_pinstall_dirs.pkglibdir); fprintf(stderr, "pkgincludedir: %s\n", pmix_pinstall_dirs.pkgincludedir); #endif /* NTH: Is it ok not to close the components? If not we can add a flag to mca_base_framework_components_close to indicate not to deregister variable groups */ return PMIX_SUCCESS; } static int pmix_pinstalldirs_base_close(void) { free(pmix_pinstall_dirs.prefix); free(pmix_pinstall_dirs.exec_prefix); free(pmix_pinstall_dirs.bindir); free(pmix_pinstall_dirs.sbindir); free(pmix_pinstall_dirs.libexecdir); free(pmix_pinstall_dirs.datarootdir); free(pmix_pinstall_dirs.datadir); free(pmix_pinstall_dirs.sysconfdir); free(pmix_pinstall_dirs.sharedstatedir); free(pmix_pinstall_dirs.localstatedir); free(pmix_pinstall_dirs.libdir); free(pmix_pinstall_dirs.includedir); free(pmix_pinstall_dirs.infodir); free(pmix_pinstall_dirs.mandir); free(pmix_pinstall_dirs.pmixdatadir); free(pmix_pinstall_dirs.pmixlibdir); free(pmix_pinstall_dirs.pmixincludedir); memset(&pmix_pinstall_dirs, 0, sizeof(pmix_pinstall_dirs)); return pmix_mca_base_framework_components_close(&pmix_pinstalldirs_base_framework, NULL); } /* Declare the pinstalldirs framework */ PMIX_MCA_BASE_FRAMEWORK_DECLARE(pmix, pinstalldirs, NULL, NULL, pmix_pinstalldirs_base_open, pmix_pinstalldirs_base_close, pmix_mca_pinstalldirs_base_static_components, PMIX_MCA_BASE_FRAMEWORK_FLAG_NOREGISTER | PMIX_MCA_BASE_FRAMEWORK_FLAG_NO_DSO); pmix-6.1.1~rc2/src/mca/pinstalldirs/base/base.h0000664000175000017500000000246315203536752021536 0ustar alastairalastair/* * Copyright (c) 2006-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2007-2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 Sandia National Laboratories. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_PINSTALLDIRS_BASE_H #define PMIX_PINSTALLDIRS_BASE_H #include "src/include/pmix_config.h" #include "src/mca/base/pmix_mca_base_framework.h" #include "src/mca/pinstalldirs/pinstalldirs.h" /* * Global functions for MCA overall pinstalldirs open and close */ BEGIN_C_DECLS /** * Framework structure declaration */ PMIX_EXPORT extern pmix_mca_base_framework_t pmix_pinstalldirs_base_framework; /* Just like pmix_pinstall_dirs_expand() (see pinstalldirs.h), but will also insert the value of the environment variable $PMIX_DESTDIR, if it exists/is set. This function should *only* be used during the setup routines of pinstalldirs. */ PMIX_EXPORT char *pmix_pinstall_dirs_expand_setup(const char *input); PMIX_EXPORT int pmix_pinstall_dirs_base_init(pmix_info_t info[], size_t ninfo); END_C_DECLS #endif /* PMIX_BASE_PINSTALLDIRS_H */ pmix-6.1.1~rc2/src/mca/pinstalldirs/base/Makefile.am0000664000175000017500000000051615203536752022504 0ustar alastairalastair# # Copyright (c) 2006 Los Alamos National Security, LLC. All rights # reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers += \ base/base.h libmca_pinstalldirs_la_SOURCES += \ base/pinstalldirs_base_components.c \ base/pinstalldirs_base_expand.c pmix-6.1.1~rc2/src/mca/pinstalldirs/config/0000775000175000017500000000000015203536752021001 5ustar alastairalastairpmix-6.1.1~rc2/src/mca/pinstalldirs/config/configure.m40000664000175000017500000000177715203536752023240 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2006 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2016-2017 Intel, Inc. All rights reserved. # Copyright (c) 2016 Research Organization for Information Science # and Technology (RIST). All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AC_DEFUN([MCA_pmix_pinstalldirs_config_PRIORITY], [0]) AC_DEFUN([MCA_pmix_pinstalldirs_config_COMPILE_MODE], [ AC_MSG_CHECKING([for MCA component $1:$2 compile mode]) $3="static" AC_MSG_RESULT([$$3]) ]) # MCA_pinstalldirs_config_CONFIG(action-if-can-compile, # [action-if-cant-compile]) # ------------------------------------------------ AC_DEFUN([MCA_pmix_pinstalldirs_config_CONFIG],[ AC_CONFIG_FILES([src/mca/pinstalldirs/config/Makefile src/mca/pinstalldirs/config/pinstall_dirs.h]) ]) pmix-6.1.1~rc2/src/mca/pinstalldirs/config/pinstall_dirs.h.in0000664000175000017500000001217515203536752024434 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2016 Intel, Inc. All rights reserved * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * This file should be included by any file that needs the * installation directories hard-coded into the object file. This * should be avoided if at all possible, but there are some places * (like the wrapper compilers) where it is infinitely easier to have * the paths stored. * * If you have questions about which directory to use, we try as best * we can to follow the GNU coding standards on this issue. The * description of each directory can be found at the following URL: * * http://www.gnu.org/prep/standards/html_node/Directory-Variables.html * * The line below is to shut AC 2.60 up about datarootdir. Don't remove. * datarootdir=foo */ #ifndef PMIX_INST_DIRS_H #define PMIX_INST_DIRS_H #define PMIX_INSTALL_PREFIX "@prefix@" #define PMIX_EXEC_PREFIX "@exec_prefix@" /* The directory for installing executable programs that users can run. */ #define PMIX_BINDIR "@bindir@" /* The directory for installing executable programs that can be run from the shell, but are only generally useful to system administrators. */ #define PMIX_SBINDIR "@sbindir@" /* The directory for installing executable programs to be run by other programs rather than by users. The definition of ‘libexecdir’ is the same for all packages, so you should install your data in a subdirectory thereof. Most packages install their data under $(libexecdir)/package-name/, possibly within additional subdirectories thereof, such as $(libexecdir)/package-name/machine/version. */ #define PMIX_LIBEXECDIR "@libexecdir@" /* The root of the directory tree for read-only architecture-independent data files. See not about PMIX_DATADIR. And you probably want that one, not this one. This is one of those "building block" paths, that is really only used for defining other paths. */ #define PMIX_DATAROOTDIR "@datarootdir@" /* The directory for installing idiosyncratic read-only architecture-independent data files for this program. The definition of ‘datadir’ is the same for all packages, so you should install your data in a subdirectory thereof. Most packages install their data under $(datadir)/package-name/. */ #define PMIX_DATADIR "@datadir@" /* $(datadir)/package-name/. You probably want to use this instead of PMIX_DATADIR */ #define PMIX_PKGDATADIR "@pmixdatadir@" /* The directory for installing read-only data files that pertain to a single machine–that is to say, files for configuring a host. Mailer and network configuration files, /etc/passwd, and so forth belong here. All the files in this directory should be ordinary ASCII text files. Do not install executables here in this directory (they probably belong in $(libexecdir) or $(sbindir)). Also do not install files that are modified in the normal course of their use (programs whose purpose is to change the configuration of the system excluded). Those probably belong in $(localstatedir). */ #define PMIX_SYSCONFDIR "@sysconfdir@" /* The directory for installing architecture-independent data files which the programs modify while they run. */ #define PMIX_SHAREDSTATEDIR "@sharedstatedir@" /* The directory for installing data files which the programs modify while they run, and that pertain to one specific machine. Users should never need to modify files in this directory to configure the package's operation; put such configuration information in separate files that go in $(datadir) or $(sysconfdir). */ #define PMIX_LOCALSTATEDIR "@localstatedir@" /* The directory for object files and libraries of object code. Do not install executables here, they probably ought to go in $(libexecdir) instead. */ #define PMIX_LIBDIR "@libdir@" /* $(libdir)/package-name/. This is where components should go */ #define PMIX_PKGLIBDIR "@pmixlibdir@" /* The directory for installing header files to be included by user programs with the C ‘#include’ preprocessor directive. */ #define PMIX_INCLUDEDIR "@includedir@" /* $(includedir)/package-name/. The devel headers go in here */ #define PMIX_PKGINCLUDEDIR "@pmixincludedir@" /* The directory for installing the Info files for this package. */ #define PMIX_INFODIR "@infodir@" /* The top-level directory for installing the man pages (if any) for this package. */ #define PMIX_MANDIR "@mandir@" #endif pmix-6.1.1~rc2/src/mca/pinstalldirs/config/Makefile.am0000664000175000017500000000144515203536752023041 0ustar alastairalastair# # Copyright (c) 2006 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2016-2018 Intel, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # noinst_LTLIBRARIES = libpmix_mca_pinstalldirs_config.la libpmix_mca_pinstalldirs_config_la_SOURCES = \ pmix_pinstalldirs_config.c # This file is generated; we do not want to include it in the tarball nodist_libpmix_mca_pinstalldirs_config_la_SOURCES = \ pinstall_dirs.h pmix-6.1.1~rc2/src/mca/pinstalldirs/config/pmix_pinstalldirs_config.c0000664000175000017500000000316115203536752026240 0ustar alastairalastair/* * Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/mca/pinstalldirs/config/pinstall_dirs.h" #include "src/mca/pinstalldirs/pinstalldirs.h" const pmix_pinstalldirs_base_component_t pmix_mca_pinstalldirs_config_component = { /* First, the mca_component_t struct containing meta information about the component itself */ .component = { PMIX_PINSTALLDIRS_BASE_VERSION_1_0_0, /* Component name and version */ "config", PMIX_MAJOR_VERSION, PMIX_MINOR_VERSION, PMIX_RELEASE_VERSION, /* Component open and close functions */ NULL, NULL }, .install_dirs_data = { .prefix = PMIX_INSTALL_PREFIX, .exec_prefix = PMIX_EXEC_PREFIX, .bindir = PMIX_BINDIR, .sbindir = PMIX_SBINDIR, .libexecdir = PMIX_LIBEXECDIR, .datarootdir = PMIX_DATAROOTDIR, .datadir = PMIX_DATADIR, .sysconfdir = PMIX_SYSCONFDIR, .sharedstatedir = PMIX_SHAREDSTATEDIR, .localstatedir = PMIX_LOCALSTATEDIR, .libdir = PMIX_LIBDIR, .includedir = PMIX_INCLUDEDIR, .infodir = PMIX_INFODIR, .mandir = PMIX_MANDIR, .pmixdatadir = PMIX_PKGDATADIR, .pmixlibdir = PMIX_PKGLIBDIR, .pmixincludedir = PMIX_PKGINCLUDEDIR } }; PMIX_MCA_BASE_COMPONENT_INIT(pmix, pinstalldirs, config) pmix-6.1.1~rc2/src/mca/pinstalldirs/Makefile.am0000664000175000017500000000135615203536752021575 0ustar alastairalastair# # Copyright (c) 2006 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2016 Intel, Inc. All rights reserved # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # main library setup noinst_LTLIBRARIES = libmca_pinstalldirs.la libmca_pinstalldirs_la_SOURCES = # local files headers = pinstalldirs.h pinstalldirs_types.h libmca_pinstalldirs_la_SOURCES += $(headers) # install the header files pmixdir = $(pmixincludedir)/$(subdir) nobase_pmix_HEADERS = $(headers) include base/Makefile.am distclean-local: rm -f base/static-components.h pmix-6.1.1~rc2/src/mca/pinstalldirs/pinstalldirs_types.h0000664000175000017500000000331515203536752023643 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2006-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_MCA_PINSTALLDIRS_PINSTALLDIRS_TYPES_H #define PMIX_MCA_PINSTALLDIRS_PINSTALLDIRS_TYPES_H #include "src/include/pmix_config.h" #include "pmix_common.h" BEGIN_C_DECLS /* * Most of this file is just for pmix_info. The only public interface * once pmix_init has been called is the pmix_pinstall_dirs structure * and the pmix_pinstall_dirs_expand() call */ struct pmix_pinstall_dirs_t { char *prefix; char *exec_prefix; char *bindir; char *sbindir; char *libexecdir; char *datarootdir; char *datadir; char *sysconfdir; char *sharedstatedir; char *localstatedir; char *libdir; char *includedir; char *infodir; char *mandir; /* Rather than using pkg{data,lib,includedir}, use our own pmix{data,lib,includedir}, which is always set to {datadir,libdir,includedir}/pmix. Note that these field names match macros set by configure that are used in Makefile.am files. E.g., project help files are installed into $(pmixdatadir). */ char *pmixdatadir; char *pmixlibdir; char *pmixincludedir; }; typedef struct pmix_pinstall_dirs_t pmix_pinstall_dirs_t; /* Install directories. Only available after pmix_init() */ PMIX_EXPORT extern pmix_pinstall_dirs_t pmix_pinstall_dirs; END_C_DECLS #endif /* PMIX_MCA_PINSTALLDIRS_PINSTALLDIRS_TYPES_H */ pmix-6.1.1~rc2/src/mca/pinstalldirs/pinstalldirs.h0000664000175000017500000000322015203536752022412 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2006-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_MCA_PINSTALLDIRS_PINSTALLDIRS_H #define PMIX_MCA_PINSTALLDIRS_PINSTALLDIRS_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/mca/base/pmix_base.h" #include "src/mca/mca.h" #include "src/mca/pinstalldirs/pinstalldirs_types.h" BEGIN_C_DECLS /** * Expand out path variables (such as ${prefix}) in the input string * using the current pmix_pinstall_dirs structure */ PMIX_EXPORT char *pmix_pinstall_dirs_expand(const char *input); /* optional initialization function */ typedef void (*pmix_install_dirs_init_fn_t)(pmix_info_t info[], size_t ninfo); /** * Structure for pinstalldirs components. */ struct pmix_pinstalldirs_base_component_2_0_0_t { /** MCA base component */ pmix_mca_base_component_t component; /** install directories provided by the given component */ pmix_pinstall_dirs_t install_dirs_data; /* optional init function */ pmix_install_dirs_init_fn_t init; }; /** * Convenience typedef */ typedef struct pmix_pinstalldirs_base_component_2_0_0_t pmix_pinstalldirs_base_component_t; /* * Macro for use in components that are of type pinstalldirs */ #define PMIX_PINSTALLDIRS_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("pinstalldirs", 1, 0, 0) END_C_DECLS #endif /* PMIX_MCA_PINSTALLDIRS_PINSTALLDIRS_H */ pmix-6.1.1~rc2/src/tools/0000775000175000017500000000000015203536752015424 5ustar alastairalastairpmix-6.1.1~rc2/src/tools/wrapper/0000775000175000017500000000000015203536752017104 5ustar alastairalastairpmix-6.1.1~rc2/src/tools/wrapper/pmixcc-wrapper-data.txt.in0000664000175000017500000000154015203536752024122 0ustar alastairalastair# There can be multiple blocks of configuration data, chosen by # compiler flags (using the compiler_args key to chose which block # should be activated. This can be useful for multilib builds. See the # multilib page at: # https://github.com/open-mpi/ompi/wiki/compilerwrapper3264 # for more information. project=PMI-Exascale (PMIx) project_short=PMIX version=@PMIX_VERSION@ language=C compiler_env=CC compiler_flags_env=CFLAGS compiler=@WRAPPER_CC@ includedir=${includedir} libdir=${libdir} preprocessor_flags=@PMIX_WRAPPER_CPPFLAGS@ compiler_flags_prefix=@PMIX_WRAPPER_CFLAGS_PREFIX@ compiler_flags=@PMIX_WRAPPER_CFLAGS@ linker_flags=@PMIX_WRAPPER_LDFLAGS@ linker_flags_static=@PMIX_WRAPPER_LDFLAGS_STATIC@ libs=@PMIX_WRAPPER_LIBS@ libs_static=@PMIX_WRAPPER_LIBS_STATIC@ dyn_lib_file=libpmix.@PMIX_DYN_LIB_SUFFIX@ static_lib_file=libpmix.a required_file= pmix-6.1.1~rc2/src/tools/wrapper/pmixcc.c0000664000175000017500000011633515203536752020544 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2007-2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018 Amazon.com, Inc. or its affiliates. All Rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include #include #ifdef HAVE_SYS_STAT_H # include #endif /* HAVE_SYS_STAT_H */ #ifdef HAVE_SYS_TYPES_H # include #endif /* HAVE_SYS_TYPES_H */ #ifdef HAVE_REGEX_H # include #endif #ifdef HAVE_SYS_WAIT_H # include #endif /* HAVE_SYS_WAIT_H */ #include #include "pmix_common.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/mca/pinstalldirs/pinstalldirs.h" #include "src/runtime/pmix_rte.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_error.h" #include "src/util/pmix_few.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_os_path.h" #include "src/util/pmix_path.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #define PMIX_INCLUDE_FLAG "-I" #define PMIX_LIBDIR_FLAG "-L" static const char * filtered_args[] = { "-I/usr/include", "-L/usr/lb", "-L/usr/lib64", NULL }; /* This structure is used to represent the config file read in during * initialization. A single file may have multiple options_data * structures, with the compiler_args keying on which section to * use in returning results. */ struct options_data_t { /* compiler_args is a key to chose the right block in the case * that there are multiple blocks in a single file. All * arguments in compiler_args in must appear in the compiler's argv * in order for this block to be selected. */ char **compiler_args; /* language for this compiler. This field is only used for * pretty-printing messages. It does not have any impact on the * behavior of the wrapper compiler. */ char *language; /* project name. This field is only used for pretty-printing * messages. It does not have any impact on the behavior of the * wrapper compiler. */ char *project; /* project short name. The environment variables to influence * setting of compiler flags are named _{CPPFLAGS, * LDFLAGS, LIBS}. */ char *project_short; /* project release version. Used to pretty-print help strings. */ char *version; /* Second part of the variable name to change the underlying * compiler the wrapper compiler invokes. For example, for C, * compiler_env should be CC, resulting in _CC * being the environment variable used to change the underlying * compiler that is invoked. */ char *compiler_env; /* Second part of the variable name to change the compiler flags * passed to the underlying compiler. For example, for C, * compiler_flags_env should be CFLAGS, resulting in * _CFLAGS being the environment variable used to * change the CFLAGS passed to the underlying compiler. */ char *compiler_flags_env; /* Default underlying compiler to invoke */ char *compiler; /* Default preprocessor (ie, CPPFLAGS) to pass to underlying * compiler. These are only passed to the underlying compiler * when it looks like we are compiling (ie, not in a link-only * situation). */ char **preproc_flags; /* Default compiler flags (ie, CFLAGS) to pass to the underlying * compiler. */ char **comp_flags; /* Compiler flags to pass to the underlying compiler before * comp_flags. These args are generally passed directly from * configure options provided from the user. */ char **comp_flags_prefix; /* Linker flags to pass to to the underlying compiler when it * appears that we are linking. These flags will be passed to the * underlying compiler whether or not we see -static (or friends) in * the arguments. */ char **link_flags; /* Linker flags to pass to to the underlying compiler when it * appears that we are linking. These flags ONLY will be passed * to the underlying compiler when we see -static (or friends) in * the arguments. */ char **link_flags_static; /* Libs flags to pass to to the underlying compiler when it * appears that we are linking. These flags will be passed to the * underlying compiler whether or not we see -static (or friends) * in the arguments. */ char **libs; /* Libs flags to pass to to the underlying compiler when it * appears that we are linking. These flags ONLY will be passed * to the underlying compiler when we see -static (or friends) in * the arguments. */ char **libs_static; /* Name of a file that should exist in ${libdir} if shared * libraries were properly installed. Historically, this was * used to determine what flags should be added to the compiler. * Now it is not used. */ char *dyn_lib_file; /* Name of a file that should exist in ${libdir} if static * libraries were properly installed. Historically, this was * used to determine what flags should be added to the compiler. * Now it is not used. */ char *static_lib_file; /* A (full path) of a file that must exist for the wrapper * compiler to succeed. A common use case is to specify a * language-binding specific file (for example, a C++ header file) * when invoking an optional language binding. */ char *req_file; /* Default includedir, before variable expansion. Almost always * set as ${includedir} outside of multilib situations. */ char *path_includedir; /* Default libdir, before variable expansion. Almost always set as ${libdir} outside of multilib situations */ char *path_libdir; }; static struct options_data_t *options_data = NULL; /* index used by parser */ static int parse_options_idx = -1; /* index of options specified by user */ static int user_data_idx = -1; /* index of options to use by default */ static int default_data_idx = -1; #define COMP_DRY_RUN 0x001 #define COMP_SHOW_ERROR 0x002 #define COMP_WANT_COMMAND 0x004 #define COMP_WANT_PREPROC 0x008 #define COMP_WANT_COMPILE 0x010 #define COMP_WANT_LINK 0x020 #define COMP_WANT_PMPI 0x040 #define COMP_WANT_STATIC 0x080 static void options_data_init(struct options_data_t *data) { data->compiler_args = (char **) malloc(sizeof(char *)); data->compiler_args[0] = NULL; data->language = NULL; data->compiler = NULL; data->project = NULL; data->project_short = NULL; data->version = NULL; data->compiler_env = NULL; data->compiler_flags_env = NULL; data->preproc_flags = (char **) malloc(sizeof(char *)); data->preproc_flags[0] = NULL; data->comp_flags = (char **) malloc(sizeof(char *)); data->comp_flags[0] = NULL; data->comp_flags_prefix = (char **) malloc(sizeof(char *)); data->comp_flags_prefix[0] = NULL; data->link_flags = (char **) malloc(sizeof(char *)); data->link_flags[0] = NULL; data->link_flags_static = (char **) malloc(sizeof(char *)); data->link_flags_static[0] = NULL; data->libs = (char **) malloc(sizeof(char *)); data->libs[0] = NULL; data->libs_static = (char **) malloc(sizeof(char *)); data->libs_static[0] = NULL; data->dyn_lib_file = NULL; data->static_lib_file = NULL; data->req_file = NULL; data->path_includedir = NULL; data->path_libdir = NULL; } static void options_data_free(struct options_data_t *data) { if (NULL != data->compiler_args) { PMIx_Argv_free(data->compiler_args); } if (NULL != data->language) free(data->language); if (NULL != data->compiler) free(data->compiler); if (NULL != data->project) free(data->project); if (NULL != data->project_short) free(data->project_short); if (NULL != data->version) free(data->version); if (NULL != data->compiler_env) free(data->compiler_env); if (NULL != data->compiler_flags_env) free(data->compiler_flags_env); PMIx_Argv_free(data->preproc_flags); PMIx_Argv_free(data->comp_flags); PMIx_Argv_free(data->comp_flags_prefix); PMIx_Argv_free(data->link_flags); PMIx_Argv_free(data->link_flags_static); PMIx_Argv_free(data->libs); PMIx_Argv_free(data->libs_static); if (NULL != data->dyn_lib_file) free(data->dyn_lib_file); if (NULL != data->static_lib_file) free(data->static_lib_file); if (NULL != data->req_file) free(data->req_file); if (NULL != data->path_includedir) free(data->path_includedir); if (NULL != data->path_libdir) free(data->path_libdir); } static void options_data_expand(const char *value) { /* make space for the new set of args */ parse_options_idx++; options_data = (struct options_data_t *) realloc(options_data, sizeof(struct options_data_t) * (parse_options_idx + 1)); options_data_init(&(options_data[parse_options_idx])); /* if there are values, this is not the default case. Otherwise, it's the default case... */ if (NULL != value && 0 != strcmp(value, "")) { char **values = PMIx_Argv_split(value, ';'); pmix_argv_insert(&(options_data[parse_options_idx].compiler_args), PMIx_Argv_count(options_data[parse_options_idx].compiler_args), values); PMIx_Argv_free(values); } else { free(options_data[parse_options_idx].compiler_args); options_data[parse_options_idx].compiler_args = NULL; /* this is a default */ default_data_idx = parse_options_idx; } } static int find_options_index(const char *arg) { int i, j; #ifdef HAVE_REGEXEC int args_count; regex_t res; #endif for (i = 0; i <= parse_options_idx; ++i) { if (NULL == options_data[i].compiler_args) { continue; } #ifdef HAVE_REGEXEC args_count = PMIx_Argv_count(options_data[i].compiler_args); for (j = 0; j < args_count; ++j) { if (0 != regcomp(&res, options_data[i].compiler_args[j], REG_NOSUB)) { return -1; } if (0 == regexec(&res, arg, (size_t) 0, NULL, 0)) { regfree(&res); return i; } regfree(&res); } #else for (j = 0; j < PMIx_Argv_count(options_data[i].compiler_args); ++j) { if (0 == strcmp(arg, options_data[i].compiler_args[j])) { return i; } } #endif } return -1; } static void expand_flags(char **argv) { int i; char *tmp; for (i = 0; argv[i] != NULL; ++i) { tmp = pmix_pinstall_dirs_expand(argv[i]); if (tmp != argv[i]) { free(argv[i]); argv[i] = tmp; } } } static void filter_flags(char*** argvp) { int argc; int idx; argc = PMIx_Argv_count(*argvp); idx = 0; while (idx < argc) { char *arg = (*argvp)[idx]; size_t j = 0; bool found = false; while (filtered_args[j] != NULL) { if (0 == strcmp(arg, filtered_args[j])) { pmix_argv_delete(&argc, argvp, idx, 1); found = true; break; } j++; } if (!found) { /* skip moving the idx pointer if we found an entry (since * the previous idx + 1 entry is the new idx pointer). Note * that argc might have moved, so the outer while loop make still * give a different answer to its conditional. */ idx++; } } } static void data_callback(const char *file, int lineno, const char *key, const char *value) { PMIX_HIDE_UNUSED_PARAMS(file, lineno); /* handle case where text file does not contain any special compiler options field */ if (parse_options_idx < 0 && 0 != strcmp(key, "compiler_args")) { options_data_expand(NULL); } if (0 == strcmp(key, "compiler_args")) { options_data_expand(value); } else if (0 == strcmp(key, "language")) { if (NULL != value) options_data[parse_options_idx].language = strdup(value); } else if (0 == strcmp(key, "compiler")) { if (NULL != value) options_data[parse_options_idx].compiler = strdup(value); } else if (0 == strcmp(key, "project")) { if (NULL != value) options_data[parse_options_idx].project = strdup(value); } else if (0 == strcmp(key, "version")) { if (NULL != value) options_data[parse_options_idx].version = strdup(value); } else if (0 == strcmp(key, "preprocessor_flags")) { char **values = PMIx_Argv_split(value, ' '); pmix_argv_insert(&options_data[parse_options_idx].preproc_flags, PMIx_Argv_count(options_data[parse_options_idx].preproc_flags), values); expand_flags(options_data[parse_options_idx].preproc_flags); filter_flags(&options_data[parse_options_idx].preproc_flags); PMIx_Argv_free(values); } else if (0 == strcmp(key, "compiler_flags")) { char **values = PMIx_Argv_split(value, ' '); pmix_argv_insert(&options_data[parse_options_idx].comp_flags, PMIx_Argv_count(options_data[parse_options_idx].comp_flags), values); expand_flags(options_data[parse_options_idx].comp_flags); filter_flags(&options_data[parse_options_idx].comp_flags); PMIx_Argv_free(values); } else if (0 == strcmp(key, "compiler_flags_prefix")) { char **values = PMIx_Argv_split(value, ' '); pmix_argv_insert(&options_data[parse_options_idx].comp_flags_prefix, PMIx_Argv_count(options_data[parse_options_idx].comp_flags_prefix), values); expand_flags(options_data[parse_options_idx].comp_flags_prefix); PMIx_Argv_free(values); } else if (0 == strcmp(key, "linker_flags")) { char **values = PMIx_Argv_split(value, ' '); pmix_argv_insert(&options_data[parse_options_idx].link_flags, PMIx_Argv_count(options_data[parse_options_idx].link_flags), values); expand_flags(options_data[parse_options_idx].link_flags); filter_flags(&options_data[parse_options_idx].link_flags); PMIx_Argv_free(values); } else if (0 == strcmp(key, "linker_flags_static")) { char **values = PMIx_Argv_split(value, ' '); pmix_argv_insert(&options_data[parse_options_idx].link_flags_static, PMIx_Argv_count(options_data[parse_options_idx].link_flags_static), values); expand_flags(options_data[parse_options_idx].link_flags_static); filter_flags(&options_data[parse_options_idx].link_flags_static); PMIx_Argv_free(values); } else if (0 == strcmp(key, "libs")) { char **values = PMIx_Argv_split(value, ' '); pmix_argv_insert(&options_data[parse_options_idx].libs, PMIx_Argv_count(options_data[parse_options_idx].libs), values); PMIx_Argv_free(values); } else if (0 == strcmp(key, "libs_static")) { char **values = PMIx_Argv_split(value, ' '); pmix_argv_insert(&options_data[parse_options_idx].libs_static, PMIx_Argv_count(options_data[parse_options_idx].libs_static), values); PMIx_Argv_free(values); } else if (0 == strcmp(key, "dyn_lib_file")) { if (NULL != value) options_data[parse_options_idx].dyn_lib_file = strdup(value); } else if (0 == strcmp(key, "static_lib_file")) { if (NULL != value) options_data[parse_options_idx].static_lib_file = strdup(value); } else if (0 == strcmp(key, "required_file")) { if (NULL != value) options_data[parse_options_idx].req_file = strdup(value); } else if (0 == strcmp(key, "project_short")) { if (NULL != value) options_data[parse_options_idx].project_short = strdup(value); } else if (0 == strcmp(key, "compiler_env")) { if (NULL != value) options_data[parse_options_idx].compiler_env = strdup(value); } else if (0 == strcmp(key, "compiler_flags_env")) { if (NULL != value) options_data[parse_options_idx].compiler_flags_env = strdup(value); } else if (0 == strcmp(key, "includedir")) { if (NULL != value) { options_data[parse_options_idx].path_includedir = pmix_pinstall_dirs_expand(value); } } else if (0 == strcmp(key, "libdir")) { if (NULL != value) { options_data[parse_options_idx].path_libdir = pmix_pinstall_dirs_expand(value); } } } static int data_init(void) { int ret; char *datafile; /* now load the data */ pmix_asprintf(&datafile, "%s%spmixcc-wrapper-data.txt", pmix_pinstall_dirs.pmixdatadir, PMIX_PATH_SEP); if (NULL == datafile) return PMIX_ERR_OUT_OF_RESOURCE; ret = pmix_util_keyval_parse(datafile, data_callback); if (PMIX_SUCCESS != ret) { fprintf(stderr, "Cannot open configuration file %s\n", datafile); } free(datafile); return ret; } static int data_finalize(void) { int i; for (i = 0; i <= parse_options_idx; ++i) { options_data_free(&(options_data[i])); } free(options_data); return PMIX_SUCCESS; } /* * Print the flags in args, stripping off pattern (which must be a * simple exact match string, no regex) from the front of every * argument in args. */ static void print_flags(char **args, char *pattern) { int i; bool found = false; for (i = 0; args[i] != NULL; ++i) { if (0 == strncmp(args[i], pattern, strlen(pattern))) { if (found) printf(" "); printf("%s", args[i] + strlen(pattern)); found = true; } } if (found) printf("\n"); } static void load_env_data(const char *project, const char *flag, char **data) { char *envname; char *envvalue; if (NULL == project || NULL == flag) return; pmix_asprintf(&envname, "%s_%s", project, flag); if (NULL == (envvalue = getenv(envname))) { free(envname); return; } free(envname); if (NULL != *data) { free(*data); } *data = strdup(envvalue); } static void load_env_data_argv(const char *project, const char *flag, char ***data) { char *envname; char *envvalue; if (NULL == project || NULL == flag) return; pmix_asprintf(&envname, "%s_%s", project, flag); if (NULL == (envvalue = getenv(envname))) { free(envname); return; } free(envname); if (NULL != *data) PMIx_Argv_free(*data); *data = PMIx_Argv_split(envvalue, ' '); } // include these definitions so convert-help is happy #define PMIX_CLI_SHOWME_CMD "showme:command" #define PMIX_CLI_SHOWME_CMPILE "showme:compile" #define PMIX_CLI_SHOWME_LINK "showme:link" #define PMIX_CLI_SHOWME_INC "showme:incdirs" #define PMIX_CLI_SHOWME_LIBD "showme:libdirs" #define PMIX_CLI_SHOWME_LIBDS "showme:libdirs_static" #define PMIX_CLI_SHOWME_LIB "showme:libs" #define PMIX_CLI_SHOWME_LIBS "showme:libs_static" #define PMIX_CLI_SHOWME_VERS "showme:version" #define PMIX_CLI_SHOWME_HELP "showme:help" static struct option options[] = { PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_HELP, PMIX_ARG_OPTIONAL, 'h'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERSION, PMIX_ARG_NONE, 'V'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERBOSE, PMIX_ARG_NONE, 'v'), PMIX_OPTION_DEFINE(PMIX_CLI_SHOWME_CMD, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SHOWME_CMPILE, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SHOWME_LINK, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SHOWME_INC, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SHOWME_LIBD, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SHOWME_LIBDS, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SHOWME_LIB, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SHOWME_LIBS, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SHOWME_VERS, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SHOWME_HELP, PMIX_ARG_NONE), PMIX_OPTION_END }; int main(int argc, char *argv[]) { int exit_status = 0, ret, flags = 0, i; int exec_argc = 0, user_argc = 0; char **exec_argv = NULL, **user_argv = NULL; char *exec_command, *base_argv0 = NULL; bool disable_flags = true; bool real_flag = false; char hostname[PMIX_PATH_MAX]; char *str; PMIX_HIDE_UNUSED_PARAMS(options); /* init globals */ pmix_tool_basename = "pmixcc"; gethostname(hostname, sizeof(hostname)); // setup the base infrastructure if (PMIX_SUCCESS != pmix_init_util(NULL, 0, NULL)) { return PMIX_ERROR; } /**************************************************** * * Setup compiler information * ****************************************************/ base_argv0 = pmix_basename(argv[0]); #if defined(EXEEXT) if (0 != strlen(EXEEXT)) { char extension[] = EXEEXT; char *temp = strstr(base_argv0, extension); char *old_match = temp; while (NULL != temp) { old_match = temp; temp = strstr(temp + 1, extension); } /* Only if there was a match of .exe, erase the last occurrence of .exe */ if (NULL != old_match) { *old_match = '\0'; } } #endif /* defined(EXEEXT) */ if (PMIX_SUCCESS != (ret = data_init())) { fprintf(stderr, "Error parsing data file %s: %s\n", base_argv0, PMIx_Error_string(ret)); return ret; } for (i = 1; i < argc && user_data_idx < 0; ++i) { user_data_idx = find_options_index(argv[i]); } /* if we didn't find a match, look for the NULL (base case) options */ if (user_data_idx < 0) { user_data_idx = default_data_idx; } /* if we still didn't find a match, abort */ if (user_data_idx < 0) { char *flat = PMIx_Argv_join(argv, ' '); pmix_show_help("help-pmixcc.txt", "no-options-support", true, base_argv0, flat, NULL); free(flat); exit(1); } /* compiler */ load_env_data(options_data[user_data_idx].project_short, options_data[user_data_idx].compiler_env, &options_data[user_data_idx].compiler); /* preprocessor flags */ load_env_data_argv(options_data[user_data_idx].project_short, "CPPFLAGS", &options_data[user_data_idx].preproc_flags); /* compiler flags */ load_env_data_argv(options_data[user_data_idx].project_short, options_data[user_data_idx].compiler_flags_env, &options_data[user_data_idx].comp_flags); /* linker flags */ load_env_data_argv(options_data[user_data_idx].project_short, "LDFLAGS", &options_data[user_data_idx].link_flags); /* libs */ load_env_data_argv(options_data[user_data_idx].project_short, "LIBS", &options_data[user_data_idx].libs); /**************************************************** * * Sanity Checks * ****************************************************/ if (NULL != options_data[user_data_idx].req_file) { /* make sure the language is supported */ if (0 == strcmp(options_data[user_data_idx].req_file, "not supported")) { pmix_show_help("help-pmixcc.txt", "no-language-support", true, options_data[user_data_idx].language, base_argv0, NULL); exit_status = 1; goto cleanup; } if (options_data[user_data_idx].req_file[0] != '\0') { char *filename; struct stat buf; filename = pmix_os_path(false, options_data[user_data_idx].path_libdir, options_data[user_data_idx].req_file, NULL); if (0 != stat(filename, &buf)) { pmix_show_help("help-pmixcc.txt", "file-not-found", true, base_argv0, options_data[user_data_idx].req_file, options_data[user_data_idx].language, NULL); } } } /**************************************************** * * Parse user flags * ****************************************************/ flags = COMP_WANT_COMMAND | COMP_WANT_PREPROC | COMP_WANT_COMPILE | COMP_WANT_LINK; user_argv = PMIx_Argv_copy(argv + 1); user_argc = PMIx_Argv_count(user_argv); for (i = 0; i < user_argc; ++i) { if (0 == strncmp(user_argv[i], "-showme", strlen("-showme")) || 0 == strncmp(user_argv[i], "--showme", strlen("--showme")) || 0 == strncmp(user_argv[i], "-show", strlen("-show")) || 0 == strncmp(user_argv[i], "--show", strlen("--show"))) { bool done_now = false; /* check for specific things we want to see. First three still invoke all the building routines. Last set want to parse out certain flags, so we don't go through the normal build routine - skip to cleanup. */ if (0 == strncmp(user_argv[i], "-showme:command", strlen("-showme:command")) || 0 == strncmp(user_argv[i], "--showme:command", strlen("--showme:command"))) { flags = COMP_WANT_COMMAND; /* we know what we want, so don't process any more args */ done_now = true; } else if (0 == strncmp(user_argv[i], "-showme:compile", strlen("-showme:compile")) || 0 == strncmp(user_argv[i], "--showme:compile", strlen("--showme:compile"))) { flags = COMP_WANT_PREPROC | COMP_WANT_COMPILE; /* we know what we want, so don't process any more args */ done_now = true; } else if (0 == strncmp(user_argv[i], "-showme:link", strlen("-showme:link")) || 0 == strncmp(user_argv[i], "--showme:link", strlen("--showme:link"))) { flags = COMP_WANT_COMPILE | COMP_WANT_LINK; /* we know what we want, so don't process any more args */ done_now = true; } else if (0 == strncmp(user_argv[i], "-showme:incdirs", strlen("-showme:incdirs")) || 0 == strncmp(user_argv[i], "--showme:incdirs", strlen("--showme:incdirs"))) { print_flags(options_data[user_data_idx].preproc_flags, PMIX_INCLUDE_FLAG); goto cleanup; } else if (0 == strncmp(user_argv[i], "-showme:libdirs_static", strlen("-showme:libdirs_static")) || 0 == strncmp(user_argv[i], "--showme:libdirs_static", strlen("--showme:libdirs_static"))) { char **all_args = NULL; int args_count; all_args = PMIx_Argv_copy(options_data[user_data_idx].link_flags); args_count = PMIx_Argv_count(all_args); pmix_argv_insert(&all_args, args_count, options_data[user_data_idx].link_flags_static); print_flags(all_args, PMIX_LIBDIR_FLAG); PMIx_Argv_free(all_args); goto cleanup; } else if (0 == strncmp(user_argv[i], "-showme:libdirs", strlen("-showme:libdirs")) || 0 == strncmp(user_argv[i], "--showme:libdirs", strlen("--showme:libdirs"))) { print_flags(options_data[user_data_idx].link_flags, PMIX_LIBDIR_FLAG); goto cleanup; } else if (0 == strncmp(user_argv[i], "-showme:libs_static", strlen("-showme:libs_static")) || 0 == strncmp(user_argv[i], "--showme:libs_static", strlen("--showme:libs_static"))) { char **all_args = NULL; int args_count; all_args = PMIx_Argv_copy(options_data[user_data_idx].libs); args_count = PMIx_Argv_count(all_args); pmix_argv_insert(&all_args, args_count, options_data[user_data_idx].libs_static); print_flags(all_args, "-l"); PMIx_Argv_free(all_args); goto cleanup; } else if (0 == strncmp(user_argv[i], "-showme:libs", strlen("-showme:libs")) || 0 == strncmp(user_argv[i], "--showme:libs", strlen("--showme:libs"))) { print_flags(options_data[user_data_idx].libs, "-l"); goto cleanup; } else if (0 == strncmp(user_argv[i], "-showme:version", strlen("-showme:version")) || 0 == strncmp(user_argv[i], "--showme:version", strlen("--showme:version"))) { str = pmix_show_help_string("help-pmixcc.txt", "version", false, base_argv0, options_data[user_data_idx].project, options_data[user_data_idx].version, options_data[user_data_idx].language); if (NULL != str) { printf("%s", str); free(str); } goto cleanup; } else if (0 == strncmp(user_argv[i], "-showme:help", strlen("-showme:help")) || 0 == strncmp(user_argv[i], "--showme:help", strlen("--showme:help"))) { str = pmix_show_help_string("help-pmixcc.txt", "usage", false, base_argv0, options_data[user_data_idx].project, options_data[user_data_idx].version, base_argv0, pmix_tool_msg); if (NULL != str) { printf("%s", str); free(str); } exit_status = 0; goto cleanup; } else if (0 == strncmp(user_argv[i], "-showme:", strlen("-showme:")) || 0 == strncmp(user_argv[i], "--showme:", strlen("--showme:"))) { fprintf(stderr, "%s: unrecognized option: %s\n", argv[0], user_argv[i]); fprintf(stderr, "Type '%s --showme:help' for usage.\n", argv[0]); exit_status = 1; goto cleanup; } flags |= (COMP_DRY_RUN | COMP_SHOW_ERROR); /* remove element from user_argv */ pmix_argv_delete(&user_argc, &user_argv, i, 1); --i; if (done_now) { disable_flags = false; break; } } else if (0 == strcmp(user_argv[i], "-c")) { flags &= ~COMP_WANT_LINK; real_flag = true; } else if (0 == strcmp(user_argv[i], "-E") || 0 == strcmp(user_argv[i], "-M")) { flags &= ~(COMP_WANT_COMPILE | COMP_WANT_LINK); real_flag = true; } else if (0 == strcmp(user_argv[i], "-S")) { flags &= ~COMP_WANT_LINK; real_flag = true; } else if (0 == strcmp(user_argv[i], "-static") || 0 == strcmp(user_argv[i], "--static") || 0 == strcmp(user_argv[i], "-Bstatic") || 0 == strcmp(user_argv[i], "-Wl,-static") || 0 == strcmp(user_argv[i], "-Wl,--static") || 0 == strcmp(user_argv[i], "-Wl,-Bstatic")) { flags |= COMP_WANT_STATIC; } else if (0 == strcmp(user_argv[i], "-dynamic") || 0 == strcmp(user_argv[i], "--dynamic") || 0 == strcmp(user_argv[i], "-Bdynamic") || 0 == strcmp(user_argv[i], "-Wl,-dynamic") || 0 == strcmp(user_argv[i], "-Wl,--dynamic") || 0 == strcmp(user_argv[i], "-Wl,-Bdynamic")) { flags &= ~COMP_WANT_STATIC; } else if ('-' != user_argv[i][0]) { disable_flags = false; flags |= COMP_SHOW_ERROR; real_flag = true; } else { /* if the option flag is one that we use to determine which set of compiler data to use, don't count it as a real option */ if (find_options_index(user_argv[i]) < 0) { real_flag = true; } } } /* clear out the want_flags if we got no arguments not starting with a - (dash) and -showme wasn't given OR -showme was given and we had at least one more non-showme argument that started with a - (dash) and no other non-dash arguments. Some examples: pmix_wrapper : clear our flags pmix_wrapper -v : clear our flags pmix_wrapper -E a.c : don't clear our flags pmix_wrapper a.c : don't clear our flags pmix_wrapper -showme : don't clear our flags pmix_wrapper -showme -v : clear our flags pmix_wrapper -showme -E a.c : don't clear our flags pmix_wrapper -showme a.c : don't clear our flags */ if (disable_flags && !((flags & COMP_DRY_RUN) && !real_flag)) { flags &= ~(COMP_WANT_PREPROC | COMP_WANT_COMPILE | COMP_WANT_LINK); } /**************************************************** * * Assemble the command line * ****************************************************/ /* compiler (may be multiple arguments, so split) */ if (flags & COMP_WANT_COMMAND) { exec_argv = PMIx_Argv_split(options_data[user_data_idx].compiler, ' '); exec_argc = PMIx_Argv_count(exec_argv); } else { exec_argv = (char **) malloc(sizeof(char *)); exec_argv[0] = NULL; exec_argc = 0; } /* This error would normally not happen unless the user edits the wrapper data files manually */ if (NULL == exec_argv) { pmix_show_help("help-pmixcc.txt", "no-compiler-specified", true); return 1; } if (flags & COMP_WANT_COMPILE) { pmix_argv_insert(&exec_argv, exec_argc, options_data[user_data_idx].comp_flags_prefix); exec_argc = PMIx_Argv_count(exec_argv); } /* Per https://svn.open-mpi.org/trac/ompi/ticket/2201, add all the user arguments before anything else. */ pmix_argv_insert(&exec_argv, exec_argc, user_argv); exec_argc = PMIx_Argv_count(exec_argv); /* preproc flags */ if (flags & COMP_WANT_PREPROC) { pmix_argv_insert(&exec_argv, exec_argc, options_data[user_data_idx].preproc_flags); exec_argc = PMIx_Argv_count(exec_argv); } /* compiler flags */ if (flags & COMP_WANT_COMPILE) { pmix_argv_insert(&exec_argv, exec_argc, options_data[user_data_idx].comp_flags); exec_argc = PMIx_Argv_count(exec_argv); } /* link flags and libs */ if (flags & COMP_WANT_LINK) { /* Configure will set the libs, libs_static, link_flags, and link_flags_static based on whether or not shared and static libraries are enabled (see the large comment in pmix_setup_wrappers.m4). The wrapper will always add libs and link_flags in a link situation, and should add the _static variants if -static was seen. */ pmix_argv_insert(&exec_argv, exec_argc, options_data[user_data_idx].link_flags); exec_argc = PMIx_Argv_count(exec_argv); if (flags & COMP_WANT_STATIC) { pmix_argv_insert(&exec_argv, exec_argc, options_data[user_data_idx].link_flags_static); exec_argc = PMIx_Argv_count(exec_argv); } pmix_argv_insert(&exec_argv, exec_argc, options_data[user_data_idx].libs); exec_argc = PMIx_Argv_count(exec_argv); if (flags & COMP_WANT_STATIC) { pmix_argv_insert(&exec_argv, exec_argc, options_data[user_data_idx].libs_static); exec_argc = PMIx_Argv_count(exec_argv); } } /**************************************************** * * Execute the command * ****************************************************/ if (flags & COMP_DRY_RUN) { exec_command = PMIx_Argv_join(exec_argv, ' '); printf("%s\n", exec_command); } else { char *tmp; #if 0 exec_command = PMIx_Argv_join(exec_argv, ' '); printf("command: %s\n", exec_command); #endif tmp = pmix_path_findv(exec_argv[0], 0, environ, NULL); if (NULL == tmp) { pmix_show_help("help-pmixcc.txt", "no-compiler-found", true, exec_argv[0], NULL); errno = 0; exit_status = 1; } else { int status; free(exec_argv[0]); exec_argv[0] = tmp; ret = pmix_few(exec_argv, &status); exit_status = WIFEXITED(status) ? WEXITSTATUS(status) : (WIFSIGNALED(status) ? WTERMSIG(status) : (WIFSTOPPED(status) ? WSTOPSIG(status) : 255)); if ((PMIX_SUCCESS != ret) || ((0 != exit_status) && (flags & COMP_SHOW_ERROR))) { char *myexec_command = PMIx_Argv_join(exec_argv, ' '); if (PMIX_SUCCESS != ret) { pmix_show_help("help-pmixcc.txt", "spawn-failed", true, exec_argv[0], strerror(status), myexec_command, NULL); } else { #if 0 pmix_show_help("help-pmixcc.txt", "compiler-failed", true, exec_argv[0], exit_status, myexec_command, NULL); #endif } free(myexec_command); } } } /**************************************************** * * Cleanup * ****************************************************/ cleanup: PMIx_Argv_free(exec_argv); PMIx_Argv_free(user_argv); if (NULL != base_argv0) free(base_argv0); if (PMIX_SUCCESS != (ret = data_finalize())) { return ret; } /* keyval lex-based parser */ pmix_util_keyval_parse_finalize(); (void) pmix_mca_base_framework_close(&pmix_pinstalldirs_base_framework); pmix_mca_base_close(); /* finalize the show_help system */ pmix_show_help_finalize(); /* finalize the output system. This has to come *after* the malloc code, as the malloc code needs to call into this, but the malloc code turning off doesn't affect pmix_output that much */ pmix_output_finalize(); return exit_status; } pmix-6.1.1~rc2/src/tools/wrapper/help-pmixcc.txt0000664000175000017500000000707715203536752022071 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2006-2010 Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2012-2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2019-2020 Intel, Inc. All rights reserved. # Copyright (c) 2025-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for Open MPI wrapper compiler error # messages. # [usage] %s (%s) %s Usage: %s [OPTION] PMIx wrapper compiler /***** General Options *****/ --showme:command Show command used to invoke real compiler --showme:compile Show flags added when compiling --showme:link Show flags added when linking --showme:incdirs Show list of include dirs added when compiling --showme:libdirs Show list of library dirs added when linking --showme:libdirs_static Show list of static library dirs added when linking --showme:libs Show list of libraries added when linking --showme:libs_static Show list of static libraries added when linking --showme:version Show version of PMIx library --showme:help This help message where "args" consists of compiler flags and sources that are to be compiled Report bugs to %s # [version] %s: %s %s (Language: %s) # [no-language-support] Unfortunately, this installation of PMIx was not compiled with %s support. As such, the %s compiler is non-functional. # [no-compiler-specified] No underlying compiler was specified in the wrapper compiler data file (e.g., pmixcc-wrapper-data.txt) # [no-compiler-found] The PMIx wrapper compiler was unable to find the specified compiler %s in your PATH. Note that this compiler was either specified at configure time or in one of several possible environment variables. # [showme:command] Show command used to invoke real compiler # [showme:compile] Show flags added when compiling # [showme:link] Show flags added when linking # [showme:incdirs] Show list of include dirs added when compiling # [showme:libdirs] Show list of library dirs added when linking # [showme:libdirs_static] Show list of static library dirs added when linking # [showme:libs] Show list of libraries added when linking # [showme:libs_static] Show list of static libraries added when linking # [showme:version] Show version of wrapper compiler # [showme:help] Show usage message # [file-not-found] %s could not find the file %s, needed for %s support. This may indicate an incomplete install and linking will likely fail. # [spawn-failed] Unable to call the compiler (%s). The failure return the error %s. The failed command was [%s]. # [compiler-failed] The child process (%s) exit with error %d. The failed command was [%s]. # [no-options-support] The %s wrapper compiler was unable to find a block of options in its configuration to support your compiler mode. Your application was not compiled. or linked. The wrapper compiler command line was: %s pmix-6.1.1~rc2/src/tools/wrapper/Makefile.am0000664000175000017500000000300115203536752021132 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2006 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2006-2020 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2014 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2019-2020 Intel, Inc. All rights reserved. # Copyright (c) 2020 IBM Corporation. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_LDFLAGS = $(pmix_hwloc_LDFLAGS) $(pmix_libevent_LDFLAGS) if PMIX_INSTALL_BINARIES bin_PROGRAMS = pmixcc nodist_pmixdata_DATA = pmixcc-wrapper-data.txt EXTRA_DIST = help-pmixcc.txt pmixcc_SOURCES = \ pmixcc.c pmixcc_LDADD = \ $(pmix_libevent_LIBS) \ $(pmix_hwloc_LIBS) \ $(top_builddir)/src/libpmix.la endif # PMIX_INSTALL_BINARIES pmix-6.1.1~rc2/src/tools/wrapper/.gitignore0000664000175000017500000000000415203536752021066 0ustar alastairalastair*.1 pmix-6.1.1~rc2/src/tools/pevent/0000775000175000017500000000000015203536752016725 5ustar alastairalastairpmix-6.1.1~rc2/src/tools/pevent/pevent.c0000664000175000017500000003371015203536752020376 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "pmix_config.h" #include "pmix_common.h" #include #include #include #include #include #include "include/pmix_tool.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/runtime/pmix_rte.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" typedef struct { pmix_lock_t lock; pmix_status_t status; } mylock_t; static pmix_proc_t myproc; /* this is the event notification function we pass down below * when registering for general events - i.e.,, the default * handler. We don't technically need to register one, but it * is usually good practice to catch any events that occur */ static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, info, ninfo, results, nresults); /* this example doesn't do anything with default events */ if (NULL != cbfunc) { cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } /* event handler registration is done asynchronously because it * may involve the PMIx server registering with the host RM for * external events. So we provide a callback function that returns * the status of the request (success or an error), plus a numerical index * to the registered event. The index is used later on to deregister * an event handler - if we don't explicitly deregister it, then the * PMIx server will do so when it see us exit */ static void evhandler_reg_callbk(pmix_status_t status, size_t evhandler_ref, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(evhandler_ref); if (PMIX_SUCCESS != status) { fprintf(stderr, "Client %s:%d EVENT HANDLER REGISTRATION FAILED WITH STATUS %d, ref=%lu\n", myproc.nspace, myproc.rank, status, (unsigned long) evhandler_ref); } lock->status = status; PMIX_WAKEUP_THREAD(&lock->lock); } #define PMIX_CLI_RANGE "range" static struct option peventoptions[] = { PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_HELP, PMIX_ARG_OPTIONAL, 'h'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERSION, PMIX_ARG_NONE, 'V'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERBOSE, PMIX_ARG_NONE, 'v'), PMIX_OPTION_DEFINE(PMIX_CLI_PMIXMCA, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_SYS_SERVER_FIRST, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SYSTEM_SERVER, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_WAIT_TO_CONNECT, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NUM_CONNECT_RETRIES, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_PID, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NAMESPACE, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_URI, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_TMPDIR, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_RANGE, PMIX_ARG_REQD), PMIX_OPTION_END }; static char *peventshorts = "h::vV"; static void opcbfunc(pmix_status_t status, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; lock->status = status; PMIX_WAKEUP_THREAD(&lock->lock); } int main(int argc, char **argv) { pmix_status_t rc; pmix_info_t *info; size_t n; mylock_t mylock; pmix_status_t status; pmix_data_range_t range; pmix_cli_result_t results; pmix_cli_item_t *opt; char *kptr; pmix_rank_t rank = 0; char hostname[PMIX_PATH_MAX]; PMIX_HIDE_UNUSED_PARAMS(argc); /* protect against problems if someone passes us thru a pipe * and then abnormally terminates the pipe early */ signal(SIGPIPE, SIG_IGN); /* init globals */ pmix_tool_basename = "pevent"; gethostname(hostname, sizeof(hostname)); /* initialize the output system */ if (!pmix_output_init()) { return PMIX_ERROR; } /* initialize install dirs code */ rc = pmix_mca_base_framework_open(&pmix_pinstalldirs_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { fprintf(stderr, "pmix_pinstalldirs_base_open() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, rc); return rc; } if (PMIX_SUCCESS != (rc = pmix_pinstall_dirs_base_init(NULL, 0))) { fprintf(stderr, "pmix_pinstalldirs_base_init() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, rc); return rc; } /* initialize the help system */ pmix_show_help_init(); /* keyval lex-based parser */ if (PMIX_SUCCESS != (rc = pmix_util_keyval_parse_init())) { fprintf(stderr, "pmix_util_keyval_parse_init failed with %d\n", rc); return PMIX_ERROR; } /* Setup the parameter system */ if (PMIX_SUCCESS != (rc = pmix_mca_base_var_init())) { fprintf(stderr, "pmix_mca_base_var_init failed with %d\n", rc); return PMIX_ERROR; } /* Parse the command line options */ PMIX_CONSTRUCT(&results, pmix_cli_result_t); rc = pmix_cmd_line_parse(argv, peventshorts, peventoptions, NULL, &results, "help-pevent.txt"); if (PMIX_SUCCESS != rc) { if (PMIX_ERR_SILENT != rc && PMIX_OPERATION_SUCCEEDED != rc) { fprintf(stderr, "%s: command line error (%s)\n", argv[0], PMIx_Error_string(rc)); } if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } exit(rc); } if (NULL == results.tail) { char *str; fprintf(stderr, "%s: must provide event\n", argv[0]); str = pmix_show_help_string("help-pevent.txt", "usage", false, pmix_tool_basename, "PMIx", PMIX_PROXY_VERSION, pmix_tool_basename, PMIX_PROXY_BUGREPORT); if (NULL != str) { printf("%s", str); free(str); } exit(1); } // handle relevant MCA params PMIX_LIST_FOREACH(opt, &results.instances, pmix_cli_item_t) { if (0 == strcmp(opt->key, PMIX_CLI_PMIXMCA)) { for (n=0; NULL != opt->values[n]; n++) { pmix_expose_param(opt->values[n]); } } } /* register params for pmix */ if (PMIX_SUCCESS != (rc = pmix_register_params())) { fprintf(stderr, "pmix_register_params failed with %d\n", rc); return PMIX_ERROR; } /* if the event is a name, look it up */ if ('-' != results.tail[0][0] && !isdigit(results.tail[0][0])) { /* it's a string name */ status = PMIx_Error_code(results.tail[0]); if (INT32_MIN == status) { char *str; /* couldn't find it */ fprintf(stderr, "%s: could not identify status %s\n", argv[0], results.tail[0]); str = pmix_show_help_string("help-pevent.txt", "usage", false, pmix_tool_basename, "PMIx", PMIX_PROXY_VERSION, pmix_tool_basename, PMIX_PROXY_BUGREPORT); if (NULL != str) { printf("%s", str); free(str); } exit(1); } } else { status = (pmix_status_t) strtoul(results.tail[0], NULL, 10); } opt = pmix_cmd_line_get_param(&results, PMIX_CLI_RANGE); if (NULL == opt) { char *str; str = pmix_show_help_string("help-pevent.txt", "usage", false, pmix_tool_basename, "PMIx", PMIX_PROXY_VERSION, pmix_tool_basename, PMIX_PROXY_BUGREPORT); if (NULL != str) { printf("%s", str); free(str); } exit(1); } range = (pmix_data_range_t) strtoul(opt->values[0], NULL, 10); /* if we were given the pid of a starter, then direct that * we connect to it */ n = 3; PMIX_INFO_CREATE(info, n); if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_PID))) { /* see if it is an integer value */ char *leftover, *param; pid_t pid; leftover = NULL; pid = strtol(opt->values[0], &leftover, 10); if (NULL == leftover || 0 == strlen(leftover)) { /* it is an integer */ PMIX_INFO_LOAD(&info[0], PMIX_SERVER_PIDINFO, &pid, PMIX_PID); } else if (0 == strncasecmp(opt->values[0], "file", 4)) { FILE *fp; /* step over the file: prefix */ param = strchr(opt->values[0], ':'); if (NULL == param) { /* malformed input */ pmix_show_help("help-pquery.txt", "bad-option-input", true, pmix_tool_basename, "--pid", opt->values[0], "file:path"); return PMIX_ERR_BAD_PARAM; } ++param; fp = fopen(param, "r"); if (NULL == fp) { pmix_show_help("help-pquery.txt", "file-open-error", true, pmix_tool_basename, "--pid", opt->values[0], param); return PMIX_ERR_BAD_PARAM; } rc = fscanf(fp, "%lu", (unsigned long *) &pid); if (1 != rc) { /* if we were unable to obtain the single conversion we * require, then error out */ pmix_show_help("help-pquery.txt", "bad-file", true, pmix_tool_basename, "--pid", opt->values[0], param); fclose(fp); return PMIX_ERR_BAD_PARAM; } fclose(fp); PMIX_INFO_LOAD(&info[0], PMIX_SERVER_PIDINFO, &pid, PMIX_PID); } else { /* a string that's neither an integer nor starts with 'file:' */ pmix_show_help("help-pquery.txt", "bad-option-input", true, pmix_tool_basename, "--pid", opt->values[0], "file:path"); return PMIX_ERR_BAD_PARAM; } } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_NAMESPACE))) { PMIX_INFO_LOAD(&info[0], PMIX_SERVER_NSPACE, opt->values[0], PMIX_STRING); } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_URI))) { PMIX_INFO_LOAD(&info[0], PMIX_SERVER_URI, opt->values[0], PMIX_STRING); } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYS_SERVER_FIRST)) { /* otherwise, use the system connection first, if available */ PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_SYSTEM_FIRST, NULL, PMIX_BOOL); } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYSTEM_SERVER)) { PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_TO_SYSTEM, NULL, PMIX_BOOL); } else { /* we set ourselves up as a tool, but no connections required */ PMIX_INFO_LOAD(&info[0], PMIX_TOOL_CONNECT_OPTIONAL, NULL, PMIX_BOOL); } /* assign our own name */ pmix_asprintf(&kptr, "%s.%s.%lu", pmix_tool_basename, hostname, (unsigned long)getpid()); PMIX_INFO_LOAD(&info[1], PMIX_TOOL_NSPACE, kptr, PMIX_STRING); free(kptr); PMIX_INFO_LOAD(&info[2], PMIX_TOOL_RANK, &rank, PMIX_PROC_RANK); /* init as a tool */ if (PMIX_SUCCESS != (rc = PMIx_tool_init(&myproc, info, 3))) { fprintf(stderr, "PMIx_tool_init failed: %d\n", rc); exit(rc); } PMIX_INFO_FREE(info, 3); /* register a default event handler */ PMIX_CONSTRUCT_LOCK(&mylock.lock); PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, evhandler_reg_callbk, (void *) &mylock); PMIX_WAIT_THREAD(&mylock.lock); if (PMIX_SUCCESS != mylock.status) { fprintf(stderr, "PMIx_Register_event_handler returned bad status: %d\n", rc); PMIX_DESTRUCT_LOCK(&mylock.lock); goto done; } PMIX_DESTRUCT_LOCK(&mylock.lock); /* generate the specified event */ PMIX_CONSTRUCT_LOCK(&mylock.lock); rc = PMIx_Notify_event(status, &myproc, range, NULL, 0, opcbfunc, (void *) &mylock); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx_Notify_event failed: %d\n", rc); goto done; } PMIX_WAIT_THREAD(&mylock.lock); if (PMIX_SUCCESS != mylock.status) { fprintf(stderr, "PMIx_Notify_event returned bad status: %d\n", rc); } PMIX_DESTRUCT_LOCK(&mylock.lock); done: PMIx_tool_finalize(); return (rc); } pmix-6.1.1~rc2/src/tools/pevent/help-pevent.txt0000664000175000017500000000653215203536752021723 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017 Intel, Inc. All rights reserved. # Copyright (c) 2021-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for OpenPMIx event tool # [version] %s (%s) %s %s # [usage] %s (%s) %s Usage: %s [OPTION] Inject PMIx events /***** General Options *****/ -h|--help This help message -h|--help Help for the specified option -v|--verbose Enable typical debug options -V|--version Print version and exit --pmixmca Set MCA parameter value --uri Specify the URI of the server to which we are to connect, or the name of the file (specified as file:filename) that contains that info --namespace Namespace of the daemon to which we should connect --system-server-first First look for a system server and connect to it if found --system-server Connect to a system server if a local server isn't found --pid PID of the daemon to which we should connect (int => PID or file: for file containing the PID --wait-to-connect Delay specified number of seconds before trying to connect --num-connect-retries Max number of times to try to connect --tmpdir Set the root for the session directory tree --range Range of event to be sent The provided event can be either an integer status code (e.g., -31) or the string name of a status code (e.g., "PMIX_EVENT_NODE_DOWN") Report bugs to %s # [pmixmca] Pass a PMIx MCA parameter Syntax: "pmixmca ", where "key" is the parameter name and "value" is the parameter value. # [pid] PID of the daemon to which we should connect (int => PID or file: for file containing the PID # [range] Range (pmix_range_t) of event to be sent # [tmpdir] Set the root for the session directory tree # [uri] Specify the URI of the server to which we are to connect, or the name of the file (specified as file:filename) that contains that info # [namespace] Namespace of the daemon to which we should connect # [system-server-first] First look for a system server and connect to it if found # [system-server] Connect to a system server if a local server isn't found # [wait-to-connect] Delay specified number of seconds before trying to connect # [num-connect-retries] Max number of times to try to connect pmix-6.1.1~rc2/src/tools/pevent/Makefile.am0000664000175000017500000000371315203536752020765 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CFLAGS = \ -DPMIX_CONFIGURE_USER="\"@PMIX_CONFIGURE_USER@\"" \ -DPMIX_CONFIGURE_HOST="\"@PMIX_CONFIGURE_HOST@\"" \ -DPMIX_CONFIGURE_DATE="\"@PMIX_CONFIGURE_DATE@\"" \ -DPMIX_BUILD_USER="\"$$USER\"" \ -DPMIX_BUILD_HOST="\"$${HOSTNAME:-`(hostname || uname -n) | sed 1q`}\"" \ -DPMIX_BUILD_DATE="\"`$(top_srcdir)/config/getdate.sh`\"" \ -DPMIX_BUILD_CFLAGS="\"@CFLAGS@\"" \ -DPMIX_BUILD_CPPFLAGS="\"@CPPFLAGS@\"" \ -DPMIX_BUILD_LDFLAGS="\"@LDFLAGS@\"" \ -DPMIX_BUILD_LIBS="\"@LIBS@\"" \ -DPMIX_CC_ABSOLUTE="\"@PMIX_CC_ABSOLUTE@\"" \ -DPMIX_GREEK_VERSION="\"@PMIX_GREEK_VERSION@\"" \ -DPMIX_REPO_REV="\"@PMIX_REPO_REV@\"" \ -DPMIX_RELEASE_DATE="\"@PMIX_RELEASE_DATE@\"" if PMIX_INSTALL_BINARIES bin_PROGRAMS = pevent EXTRA_DIST = help-pevent.txt endif # PMIX_INSTALL_BINARIES pevent_SOURCES = pevent.c pevent_LDADD = \ $(top_builddir)/src/libpmix.la pmix-6.1.1~rc2/src/tools/pmix_info/0000775000175000017500000000000015203536752017414 5ustar alastairalastairpmix-6.1.1~rc2/src/tools/pmix_info/Makefile.am0000664000175000017500000000374415203536752021460 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # if PMIX_INSTALL_BINARIES bin_PROGRAMS = pmix_info EXTRA_DIST = help-pmix_info.txt endif # PMIX_INSTALL_BINARIES AM_CFLAGS = \ -DPMIX_CONFIGURE_USER="\"@PMIX_CONFIGURE_USER@\"" \ -DPMIX_CONFIGURE_HOST="\"@PMIX_CONFIGURE_HOST@\"" \ -DPMIX_CONFIGURE_DATE="\"@PMIX_CONFIGURE_DATE@\"" \ -DPMIX_BUILD_USER="\"$$USER\"" \ -DPMIX_BUILD_HOST="\"$${HOSTNAME:-`(hostname || uname -n) | sed 1q`}\"" \ -DPMIX_BUILD_DATE="\"`$(top_srcdir)/config/getdate.sh`\"" \ -DPMIX_BUILD_CFLAGS="\"@CFLAGS@\"" \ -DPMIX_BUILD_CPPFLAGS="\"@CPPFLAGS@\"" \ -DPMIX_BUILD_LDFLAGS="\"@LDFLAGS@\"" \ -DPMIX_BUILD_LIBS="\"@LIBS@\"" \ -DPMIX_CC_ABSOLUTE="\"@PMIX_CC_ABSOLUTE@\"" \ -DPMIX_GREEK_VERSION="\"@PMIX_GREEK_VERSION@\"" \ -DPMIX_REPO_REV="\"@PMIX_REPO_REV@\"" \ -DPMIX_RELEASE_DATE="\"@PMIX_RELEASE_DATE@\"" pmix_info_SOURCES = \ pmix_info.c pmix_info_LDADD = \ $(top_builddir)/src/libpmix.la pmix-6.1.1~rc2/src/tools/pmix_info/pmix_info.c0000664000175000017500000002635515203536752021563 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2007 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010-2016 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #include #include #include "src/class/pmix_object.h" #include "src/class/pmix_pointer_array.h" #include "src/include/pmix_portable_platform_real.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/runtime/pmix_info_support.h" #include "src/runtime/pmix_rte.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_error.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_output.h" #include "src/util/pmix_show_help.h" /* * Public variables */ pmix_cli_result_t results = PMIX_CLI_RESULT_STATIC_INIT; const char *pmix_info_type_base = "base"; static struct option poptions[] = { PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_HELP, PMIX_ARG_OPTIONAL, 'h'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERSION, PMIX_ARG_NONE, 'V'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERBOSE, PMIX_ARG_NONE, 'v'), PMIX_OPTION_DEFINE(PMIX_CLI_PMIXMCA, PMIX_ARG_REQD), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_INFO_ALL, PMIX_ARG_NONE, 'a'), PMIX_OPTION_DEFINE(PMIX_CLI_INFO_ARCH, PMIX_ARG_NONE), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_INFO_CONFIG, PMIX_ARG_NONE, 'c'), PMIX_OPTION_DEFINE(PMIX_CLI_INFO_HOSTNAME, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_INFO_INTERNAL, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_INFO_PARAM, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_INFO_PARAMS, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_INFO_PATH, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_INFO_VERSION, PMIX_ARG_OPTIONAL), PMIX_OPTION_DEFINE(PMIX_CLI_PRETTY_PRINT, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_PARSABLE, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_PARSEABLE, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_INFO_SHOW_FAILED, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_INFO_SELECTED_ONLY, PMIX_ARG_NONE), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_INFO_TYPES, PMIX_ARG_REQD, 't'), PMIX_OPTION_DEFINE(PMIX_CLI_INFO_COLOR, PMIX_ARG_REQD), PMIX_OPTION_END }; static char *pshorts = "h::vVact:"; int main(int argc, char *argv[]) { int ret = 0; bool acted = false; bool want_all = false; int i; char *str, *ptr; pmix_pointer_array_t pmix_component_map; pmix_pointer_array_t mca_types; pmix_info_component_map_t *map; pmix_cli_item_t *opt; PMIX_HIDE_UNUSED_PARAMS(argc); PMIX_CONSTRUCT(&results, pmix_cli_result_t); /* protect against problems if someone passes us thru a pipe * and then abnormally terminates the pipe early */ signal(SIGPIPE, SIG_IGN); /* init globals */ pmix_tool_basename = "pmix_info"; /* initialize the output system */ if (!pmix_output_init()) { return PMIX_ERROR; } /* initialize install dirs code */ if (PMIX_SUCCESS != (ret = pmix_mca_base_framework_open(&pmix_pinstalldirs_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT))) { fprintf(stderr, "pmix_pinstalldirs_base_open() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, ret); return ret; } if (PMIX_SUCCESS != (ret = pmix_pinstall_dirs_base_init(NULL, 0))) { fprintf(stderr, "pmix_pinstalldirs_base_init() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, ret); return ret; } /* initialize the command line, parse it, and return the directives * telling us what the user wants output */ if (PMIX_SUCCESS != (ret = pmix_info_init(argc, argv, &results, poptions, pshorts, "help-pmix_info.txt"))) { exit(ret); } // we do NOT accept arguments other than our own if (NULL != results.tail) { str = PMIx_Argv_join(results.tail, ' '); if (0 != strcmp(str, argv[0])) { ptr = pmix_show_help_string("help-pmix_info.txt", "no-args", false, pmix_tool_basename, str, pmix_tool_basename); free(str); if (NULL != ptr) { printf("%s", ptr); free(ptr); } return -1; } free(str); } /* Get MCA parameters, if any */ if (PMIX_SUCCESS != pmix_mca_base_open(NULL)) { pmix_show_help("help-pmix_info.txt", "lib-call-fail", true, "pmix_mca_base_open", __FILE__, __LINE__); return PMIX_ERROR; } /* register params for pmix */ if (PMIX_SUCCESS != (ret = pmix_register_params())) { fprintf(stderr, "pmix_register_params failed with %d\n", ret); return PMIX_ERROR; } /* setup the mca_types array */ PMIX_CONSTRUCT(&mca_types, pmix_pointer_array_t); pmix_pointer_array_init(&mca_types, 256, INT_MAX, 128); pmix_info_register_types(&mca_types, false); /* init the component map */ PMIX_CONSTRUCT(&pmix_component_map, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_component_map, 64, INT_MAX, 32); /* Register PMIx's params */ if (PMIX_SUCCESS != (ret = pmix_info_register_framework_params(&pmix_component_map))) { if (PMIX_ERR_BAD_PARAM == ret) { /* output what we got */ pmix_info_do_params("PMIx", true, pmix_cmd_line_is_taken(&results, PMIX_CLI_INFO_INTERNAL), &mca_types, &pmix_component_map, NULL); } exit(1); } /* Execute the desired action(s) */ want_all = pmix_cmd_line_is_taken(&results, PMIX_CLI_INFO_ALL); opt = pmix_cmd_line_get_param(&results, PMIX_CLI_INFO_VERSION); if (want_all || NULL != opt) { if (NULL == opt) { pmix_info_show_pmix_package(); pmix_info_show_pmix_version(); pmix_info_show_component_version("pmix", &mca_types, &pmix_component_map, pmix_info_type_all, pmix_info_component_all, pmix_info_ver_full, pmix_info_ver_all); } else if (NULL == opt->values) { pmix_info_show_pmix_package(); pmix_info_show_pmix_version(); pmix_info_show_component_version("pmix", &mca_types, &pmix_component_map, pmix_info_type_all, pmix_info_component_all, pmix_info_ver_full, pmix_info_ver_all); } else { if (0 == strcasecmp(opt->values[0], "pmix") || 0 == strcasecmp(opt->values[0], "all")) { pmix_info_show_pmix_package(); pmix_info_show_pmix_version(); pmix_info_show_component_version("pmix", &mca_types, &pmix_component_map, pmix_info_type_all, pmix_info_component_all, pmix_info_ver_full, pmix_info_ver_all); } else { // the first arg is either the name of a framework, or a framework:component pair char **tmp = PMIx_Argv_split(opt->values[0], ':'); const char *component = pmix_info_component_all; const char *modifier = pmix_info_ver_full; if (NULL != tmp[1]) { component = tmp[1]; } if (NULL != opt->values[1]) { modifier = opt->values[1]; } pmix_info_show_component_version("pmix", &mca_types, &pmix_component_map, tmp[0], component, modifier, pmix_info_ver_all); PMIx_Argv_free(tmp); } acted = true; } } if (want_all || pmix_cmd_line_is_taken(&results, PMIX_CLI_INFO_PATH)) { pmix_info_do_pmix_path(want_all, &results); acted = true; } if (want_all || pmix_cmd_line_is_taken(&results, PMIX_CLI_INFO_ARCH)) { pmix_info_do_arch(); acted = true; } if (!want_all && pmix_cmd_line_is_taken(&results, PMIX_CLI_INFO_HOSTNAME)) { // hostname is contain in pmix_config, so don't duplicate it here pmix_info_do_hostname(); acted = true; } if (want_all || pmix_cmd_line_is_taken(&results, PMIX_CLI_INFO_CONFIG)) { pmix_info_do_pmix_config(true); acted = true; } if (want_all || pmix_cmd_line_is_taken(&results, PMIX_CLI_INFO_PARAM) || pmix_cmd_line_is_taken(&results, PMIX_CLI_INFO_PARAMS)) { pmix_info_do_params("PMIx", true, pmix_cmd_line_is_taken(&results, PMIX_CLI_INFO_INTERNAL), &mca_types, &pmix_component_map, &results); acted = true; } if (pmix_cmd_line_is_taken(&results, PMIX_CLI_INFO_TYPES)) { pmix_info_do_type(&results); acted = true; } /* If no command line args are specified, show default set */ if (!acted) { pmix_info_show_pmix_package(); pmix_info_show_pmix_version(); pmix_info_show_path(pmix_info_path_prefix, pmix_pinstall_dirs.prefix); pmix_info_do_arch(); pmix_info_do_pmix_config(false); pmix_info_show_component_version("pmix", &mca_types, &pmix_component_map, pmix_info_type_all, pmix_info_component_all, pmix_info_ver_full, pmix_info_ver_all); } /* All done */ pmix_info_close_components(); PMIX_DESTRUCT(&results); PMIX_DESTRUCT(&mca_types); for (i = 0; i < pmix_component_map.size; i++) { map = (pmix_info_component_map_t *) pmix_pointer_array_get_item(&pmix_component_map, i); if (NULL != map) { PMIX_RELEASE(map); } } PMIX_DESTRUCT(&pmix_component_map); pmix_info_finalize(); return 0; } pmix-6.1.1~rc2/src/tools/pmix_info/help-pmix_info.txt0000664000175000017500000001652215203536752023101 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2010-2012 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017-2018 Intel, Inc. All rights reserved. # Copyright (c) 2022-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for PMIx pmix-info help # messages. # # [version] %s (%s) %s %s # [usage] %s (%s) %s Usage: %s [OPTION]... PMIx Library Information /***** General Options *****/ -h|--help This help message -h|--help Help for the specified option -v|--verbose Enable typical debug options -V|--version Print version and exit --pmixmca Pass context-specific PMIx MCA parameters ("key" is the parameter name; "value" is the parameter value) -a|--all Show all configuration options and MCA parameters --arch Show architecture PMIx was compiled on -c|--config Show configuration options --hostname Show the hostname that PMIx was configured and built on --internal Show internal MCA parameters (not meant to be modified by users) --param :, Show MCA parameters. The first parameter is the framework (or the keyword "all"); the second parameter is a comma-delimited list of specific component names (if only is given, then all components will be reported). --params :, Synonym for "param" --path Show paths with which PRRTE was configured. Accepts the following parameters: "prefix", "bindir", "libdir", "incdir", "mandir", "pkglibdir", "sysconfdir". --show-version : Show version of PMIx or a component. The first parameter can be the keywords "pmix" or "all", a framework name (indicating all components in a framework), or a framework:component string (indicating a specific component). The second parameter can be one of: full, major, minor, release, greek, svn. --pretty-print When used in conjunction with other parameters, the output is displayed in 'pretty-print' format (default) --parsable When used in conjunction with other parameters, the output is displayed in a machine-parsable format --parseable Synonym for --parsable --color Control color coding: auto (default), never, always --show-failed Show the components that failed to load along with the reason why they failed --selected-only Show only variables from selected components -t| --type Show MCA parameters of the type specified in parameter. Accepts the following parameters: "unsigned_int", "unsigned_long", "unsigned_long_long", "size_t", "string", "version_string", "bool", and "double" Report bugs to %s # [pmixmca] Pass a PMIx MCA parameter Syntax: "--pmixmca ", where "key" is the parameter name and "value" is the parameter value. # [param] Syntax: param Show MCA parameters. The first parameter is the framework (or the keyword "all"); the second parameter is the specific component name (or the keyword "all"). # [params] Synonym for "param" # [internal] Syntax: internal Show internal MCA parameters (i.e., parameters not meant to be modified by users) # [path] Syntax: path Show the paths with which PMIx was configured. Accepts the following parameters: prefix, bindir, libdir, incdir, mandir, pkglibdir, sysconfdir # [arch] Syntax: arch Show architecture PMIx was compiled on # [config] Syntax: c or config Show configuration options used to configure PMIx # [hostname] Syntax: hostname Show the hostname upon which PMIx was configured and built # [all] Syntax: a or all Show all configuration options and MCA parameters # [show-version] Show version of PMIx or a component. The first parameter can be the keywords "pmix" or "all", a framework name (indicating all components in a framework), or a framework:component string (indicating a specific component). The second parameter can be one of: full, major, minor, release, greek, repo. # [pretty-print] When used in conjunction with other parameters, the output is displayed in 'pretty-print' format (default) # [parsable] When used in conjunction with other parameters, the output is displayed in a machine-parsable format # [parseable] When used in conjunction with other parameters, the output is displayed in a machine-parsable format # [color] Control color coding: auto (default), never, always # [show-failed] Show the components that failed to load along with the reason why they failed # [selected-only] Show only variables from selected (active) components # [type] Show MCA parameters of the type specified in parameter. Accepts the following parameters: "unsigned_int", "unsigned_long", "unsigned_long_long", "size_t", "string", "version_string", "bool", and "double" # [lib-call-fail] A library call unexpectedly failed. This is a terminal error; please show this message to an ORTE wizard: Library call: %s Source file: %s Source line number: %d Aborting... # [developer warning: field too long] ************************************************************************** *** DEVELOPER WARNING: A field in pmix_info output is too long and *** will appear poorly in the prettyprint output. *** *** Value: "%s" *** Max length: %d ************************************************************************** # [not-found] The specified framework could not be found: Framework: %s This could be due to a misspelling of the framework name, or because support for that framework was not configured into this version of orte. Please see the "config" option for a full report of how PMIx was configured. # [missing-values] The %s option requires %d values, but fewer were provided: Option: %s Value: %s Please correct this and try again. # [no-args] The %s command does not accept arguments other than those specifically defined by the command. The following were not recognized: Args: %s Please see "%s --help" for a description of all accepted command options. pmix-6.1.1~rc2/src/tools/palloc/0000775000175000017500000000000015203536752016676 5ustar alastairalastairpmix-6.1.1~rc2/src/tools/palloc/help-palloc.txt0000664000175000017500000003440615203536752021646 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2022-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for palloc # [version] %s (%s) %s %s # [usage] %s (%s) %s Usage: %s [OPTION]... PMIx Allocation Request tool /***** General Options *****/ -h|--help This help message -h|--help Help for the specified option -v|--verbose Enable typical debug options -V|--version Print version and exit --pmixmca Set MCA parameter value --uri Specify the URI of the server to which we are to connect, or the name of the file (specified as file:filename) that contains that info --namespace Namespace of the daemon to which we should connect --nspace Synonym for "namespace" --pid PID of the daemon to which we should connect (int => PID or file: for file containing the PID --system-server-first First look for a system server and connect to it if found --system-server-only Connect only to a system-level server --system-controller Connect to the system controller --tmpdir Set the root for the session directory tree --connect-order Specify search order for server connections - e.g., scheduler, system controller, system-level server, or local server --wait-to-connect Delay specified number of seconds before trying to connect --num-connect-retries Max number of times to try to connect --request-id String identifier for this allocation request -q|--queue Scheduler queue this request should be passed to for processing -N|--nodes Number of nodes to be allocated -i|--image OS image to be provisioned on allocated nodes prior to initiating execution of specified job, or turning nodes over to an interactive session -x|--exclude Comma-delimited list of nodes that are to be excluded from consideration for scheduling this allocation --wait-all-nodes Wait for all nodes to be ready before starting execution of the specified job. -w|--nodelist Comma-delimited list of ranges of specific nodes being requested [e.g., host0[1-5],host128]. Can also pass the argument as a filename using the "file:" syntax. Ordering of names and/or duplicate names are ignored. --uid Assign the resulting allocation to the specified user ID --gid Assign the resulting allocation to the specified group ID -t|--time Time limit on the assigned allocation. --signal [@arg1] Send all processes executing within the allocated session the specified signal when it reaches the (optional) specified seconds of its end time. -s|--share Allocated resources can be shared with other allocations. --extend Extend the specified existing session ID per the rest of the given request. --shrink Shrink the specified existing session ID per the rest of the given request. --no-shell Immediately exit after allocating resources, without running a command. --begin Direct the scheduler to defer allocation until the specified time. -I|--immediate Exit if resources are not available within the time period specified. -d|--dependency Defer the start of this session until the specified dependencies have successfully completed. --do-not-wait Submit the allocation request to the scheduler, but do not wait for the allocation to be assigned. Intended for use when submitting a job for batch execution. The command returns the string session ID of the resulting allocation, or if executed with the "do-not-wait" option, the string session ID of the allocation request as assigned by the scheduler. Any command line arguments following the provided options are taken as the job script or executable to be run within the allocation (once assigned) and its attendant argv array. In this case, the allocation will terminate once the provide job script or executable completes. The user is responsible for free'ing the returned string session ID. Report bugs to %s # [pmixmca] Pass a PMIx MCA parameter Syntax: "pmixmca ", where "key" is the parameter name and "value" is the parameter value. # [bad-option-input] %s was given an option that expected a string argument: option: %s argument: %s expected: %s Please correct the option and try again. # [file-open-error] %s was unable to open the specified file provided as an option: option: %s argument: %s file: %s Please correct the option and try again. # [bad-file] %s was unable to read the necessary info from the provided file: option: %s argument: %s file: %s Please correct the option or the file and try again. # # CONNECTION OPTIONS # # [uri] Specify the URI of the DVM master, or the name of the file (specified as file:filename) that contains that info # [num-connect-retries] Max number of times to try to connect to the specified server (int) # [pid] PID of the daemon to which we should connect (int => PID or file: for file containing the PID # [namespace] Namespace of the daemon we are to connect to (char*) # [nspace] Namespace of the daemon we are to connect to (char*) - synonym for "namespace" # [system-server-first] First look for a system server and connect to it if found # [system-server-only] Connect only to a system-level server - abort if one is not found # [system-controller] Look for a system controller and connect to it if found # [tmpdir] Define the root location for the session directory tree where the rendezvous files can be found. The rendezvous files contain connection information for a target server and are located in the session directory tree. It may be necessary to point the tool at the location where those files can be found if that location is other than the expected default. The root of the session directory defaults to the system temporary directory as defined in the environment using (in precedence order) the envars TMPDIR, TEMP, and finally TMP. In the absence of any of those variables, PMIx will default to the "/tmp" location. # [wait-to-connect] Delay specified number of seconds before trying to connect # [connect-order] Comma-delimited list of attributes defining the order in which connections should be attempted, from first to last. If the final entry is not an "only" flag (e.g., PMIX_CONNECT_TO_SYSTEM), then connection will default to the local server if no preceding option succeeds. Thus, the following list: PMIX_CONNECT_TO_SCHEDULER PMIX_CONNECT_TO_SYS_CONTROLLER PMIX_CONNECT_TO_SYSTEM would first attempt to connect to the scheduler, then the system controller, and then the local system-level server. If none of those succeed, then the connection attempt will error out. However, if the last entry were PMIX_CONNECT_SYSTEM_FIRST, then the connection procedure would (after failing to connect to a local system-level server) continue to include an attempt to connect to any local server that accepted the connection request. # # QALLOC-SPECIFIC OPTIONS # [request-id] String identifier for this allocation request. The request ID can be used for subsequent query of request status and as a synonym for the eventual session ID assigned by the scheduler. Note that a request ID that matches a previously submitted request will be rejected by the scheduler - so care should be taken to ensure that the ID provided is unique and not previously used. # [queue] Scheduler queue this request should be passed to for processing. Most schedulers have a number of queues for requests, each queue typically representing a priority or class of request used in the scheduling process. Users should check the names of the queues for their system using the "pquery" tool and submit allocation requests accordingly. # [nodes] The number of nodes to be allocated. In systems where nodes are being subdivided for allocation (e.g., allocating individual cores or hwthreads), it may be necessary to provide a more detailed description of the requested resources. # [image] OS image to be provisioned on allocated nodes prior to initiating execution of specified job, or turning nodes over to an interactive session. Names of the available images can be obtained using the "pquery" tool. # [exclude] Comma-delimited list of nodes that are to be excluded from consideration for scheduling this allocation # [wait-all-nodes] Wait for all nodes to be ready before starting execution of the specified job. # [nodelist] Comma-delimited list of ranges of specific nodes being requested [e.g., host0[1-5],host128]. Can also pass the argument as a filename using the "file:" syntax. Ordering of names and/or duplicate names are ignored. # [uid] Assign the resulting allocation to the specified user ID. Value can be provided as either an integer or a username # [gid] Assign the resulting allocation to the specified group ID. Value can be provided as either an integer or a group name. Typically used for determining file access permissions and for system accounting. # [time] Time limit on the assigned allocation. When the time limit is reached, each process executing in the session is sent SIGTERM followed by SIGKILL. The session is then terminated and all resources returned to the scheduler for reuse. Time is specified in the usual time format of months:days:hours:minutes:seconds, scanning from right to left (i.e., a value of "2" equates to 2 seconds) # [signal] When a session is within the specified seconds of its end time, send all processes executing within it the specified signal. The signal may be a signal number or string name. The optional time is taken in seconds, defaulting to 60 seconds if not specified. # [share] Allocated resources can be shared with other allocations. # [extend] Extend the specified existing session ID per the rest of the given request. For example, an existing session can have additional nodes allocated to it, or could have its time limit increased. # [shrink] Shrink the specified existing session ID per the rest of the given request. For example, an existing session could have a certain number of nodes removed (returning them to the scheduler for reassignment), or its time reduced. # [no-shell] Immediately exit after allocating resources, without running a command. However, the session will still be created and will remain active and own the allocated resources as long as it is active - i.e., it will be an active session with an assigned session ID with no job executing within it. You can submit commands against this resource allocation (e.g., using "prun") if you specify the appropriate connection identification for this allocation. Note that the session is subject to the normal constraints on sessions, including time limits, so that eventually the session will terminate and the resources will be freed, or you can terminate the session manually using the "pcancel" command. # [begin] Direct the scheduler to defer allocation until the specified time. Time may be of the form HH:MM:SS to schedule the session to start at a specific time of day (seconds are optional). If that time is already past, the next day is assumed. You may also specify "midnight" or "noon", and you can have a time-of-day suffixed with AM or PM for running in the morning or the evening. You can also say what day the session should start by specifying a date of the form MMDDYY or MM/DD/YY YYYY-MM-DD. Combine date and time using the usual format YYYY-MM-DD[THH:MM[:SS]]. You can also give times like "now + count" time-units, where the time-units can be "seconds" (default), "minutes", "hours", days, or weeks, or you can ask that the allocation be made "today" or "tomorrow". # [immediate] Exit if resources are not available within the time period specified. If no argument is given, resources must be available immediately for the request to succeed. By default, "immediate" is off, and the command will block until resources become available. Since this option's argument is optional, for proper parsing the single letter option must be followed by an equal sign and the value - e.g., "-I=60" for a time of 60 seconds or "-I30:00" for a time of 30 minutes. # [dependency] Defer the start of this session until the specified dependencies have successfully completed. The dependencies are provided as a comma-delimited list of session IDs. All specified dependencies must be satisfied before the given allocation request will be scheduled. # [do-not-wait] Submit the allocation request to the scheduler, but do not wait for the allocation to be assigned. Intended for use when submitting a job for batch execution. Users should provide a string request ID to enable subsequent queries of request status. pmix-6.1.1~rc2/src/tools/palloc/Makefile.am0000664000175000017500000000220515203536752020731 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # if PMIX_INSTALL_BINARIES bin_PROGRAMS = palloc EXTRA_DIST = help-palloc.txt endif # PMIX_INSTALL_BINARIES palloc_SOURCES = palloc.c palloc_LDADD = \ $(top_builddir)/src/libpmix.la pmix-6.1.1~rc2/src/tools/palloc/palloc.c0000664000175000017500000005163515203536752020326 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "pmix_config.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include #include #include #include #include #include "include/pmix_tool.h" #include "src/common/pmix_attributes.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/runtime/pmix_init_util.h" #include "src/runtime/pmix_rte.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" static struct option pallocptions[] = { PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_HELP, PMIX_ARG_OPTIONAL, 'h'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERSION, PMIX_ARG_NONE, 'V'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERBOSE, PMIX_ARG_NONE, 'v'), PMIX_OPTION_DEFINE(PMIX_CLI_PMIXMCA, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_SYS_SERVER_FIRST, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SYS_SERVER_ONLY, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_WAIT_TO_CONNECT, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NUM_CONNECT_RETRIES, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_PID, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NAMESPACE, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NSPACE, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_URI, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_TMPDIR, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_CONNECTION_ORDER, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_SYS_CONTROLLER, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_REQ_ID, PMIX_ARG_REQD), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_QUEUE, PMIX_ARG_REQD, 'q'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_NODES, PMIX_ARG_REQD, 'N'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_IMAGE, PMIX_ARG_REQD, 'i'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_EXCLUDE, PMIX_ARG_REQD, 'x'), PMIX_OPTION_DEFINE(PMIX_CLI_WAIT_ALL_NODES, PMIX_ARG_NONE), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_NODELIST, PMIX_ARG_REQD, 'w'), PMIX_OPTION_DEFINE(PMIX_CLI_UID, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_GID, PMIX_ARG_REQD), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_TIME, PMIX_ARG_REQD, 't'), PMIX_OPTION_DEFINE(PMIX_CLI_SIGNAL, PMIX_ARG_REQD), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_SHARE, PMIX_ARG_NONE, 's'), PMIX_OPTION_DEFINE(PMIX_CLI_EXTEND, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SHRINK, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_NO_SHELL, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_BEGIN, PMIX_ARG_REQD), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_IMMEDIATE, PMIX_ARG_OPTIONAL, 'I'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_DEPENDENCY, PMIX_ARG_REQD, 'd'), PMIX_OPTION_DEFINE(PMIX_CLI_DO_NOT_WAIT, PMIX_ARG_NONE), PMIX_OPTION_END }; static char *pallocshorts = "h::vVq:N:i:x:w:t:I::d:"; static void cbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *req = (pmix_shift_caddy_t*)cbdata; size_t n; pmix_status_t rc; PMIX_ACQUIRE_OBJECT(req); req->status = status; if (PMIX_SUCCESS == status && 0 < ninfo) { req->ninfo = ninfo; PMIX_INFO_CREATE(req->info, req->ninfo); for (n=0; n < ninfo; n++) { PMIX_INFO_XFER(&req->info[n], &info[n]); if (PMIX_CHECK_KEY(&info[n], PMIX_SESSION_ID)) { rc = PMIx_Value_get_number(&info[n].value, &req->sessionid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { req->status = rc; } } } } if (NULL != release_fn) { release_fn(release_cbdata); } PMIX_POST_OBJECT(req); PMIX_WAKEUP_THREAD(&req->lock); } static void regcbfunc(pmix_status_t status, size_t ref, void *cbdata) { pmix_lock_t *lock = (pmix_lock_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(ref, status); PMIX_ACQUIRE_OBJECT(lock); PMIX_WAKEUP_THREAD(lock); } static void defhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t *results, size_t nresults, pmix_event_notification_cbfunc_fn_t evcbfunc, void *cbdata) { pmix_shift_caddy_t *req = NULL; size_t n; PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, results, nresults); if (PMIX_ERR_UNREACH == status || PMIX_ERR_LOST_CONNECTION == status) { /* we should always have info returned to us - if not, there is * nothing we can do */ if (NULL != info) { for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_EVENT_RETURN_OBJECT)) { req = (pmix_shift_caddy_t *) info[n].value.data.ptr; } } } if (NULL == req) { exit(1); } /* save the status */ req->status = status; /* release the lock */ PMIX_WAKEUP_THREAD(&req->lock); } /* we _always_ have to execute the evhandler callback or * else the event progress engine will hang */ if (NULL != evcbfunc) { evcbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } int main(int argc, char **argv) { pmix_proc_t myproc; pmix_status_t rc; pmix_shift_caddy_t *req = NULL; pmix_info_t *info; pmix_data_array_t darray; void *options; pmix_cli_result_t results; pmix_cli_item_t *opt; size_t n; pmix_rank_t rank = 0; char hostname[PMIX_PATH_MAX], *kptr; bool donotwait = false; uint32_t ui32; uint64_t ui64; pmix_alloc_directive_t directive = PMIX_ALLOC_NEW; pmix_lock_t lock; PMIX_HIDE_UNUSED_PARAMS(argc); /* protect against problems if someone passes us thru a pipe * and then abnormally terminates the pipe early */ signal(SIGPIPE, SIG_IGN); /* init globals */ pmix_tool_basename = "palloc"; gethostname(hostname, sizeof(hostname)); // setup the base infrastructure if (PMIX_SUCCESS != pmix_init_util(NULL, 0, NULL)) { return PMIX_ERROR; } /* Parse the command line options */ PMIX_CONSTRUCT(&results, pmix_cli_result_t); rc = pmix_cmd_line_parse(argv, pallocshorts, pallocptions, NULL, &results, "help-palloc.txt"); if (PMIX_SUCCESS != rc) { if (PMIX_ERR_SILENT != rc && PMIX_OPERATION_SUCCEEDED != rc) { fprintf(stderr, "%s: command line error (%s)\n", argv[0], PMIx_Error_string(rc)); } if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } exit(rc); } // handle relevant MCA params PMIX_LIST_FOREACH(opt, &results.instances, pmix_cli_item_t) { if (0 == strcmp(opt->key, PMIX_CLI_PMIXMCA)) { for (n=0; NULL != opt->values[n]; n++) { pmix_expose_param(opt->values[n]); } } } /* if we were given the pid of a starter, then direct that * we connect to it */ n = 3; PMIX_INFO_CREATE(info, n); if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_PID))) { /* see if it is an integer value */ char *leftover, *param; pid_t pid; leftover = NULL; pid = strtol(opt->values[0], &leftover, 10); if (NULL == leftover || 0 == strlen(leftover)) { /* it is an integer */ PMIX_INFO_LOAD(&info[0], PMIX_SERVER_PIDINFO, &pid, PMIX_PID); } else if (0 == strncasecmp(opt->values[0], "file", 4)) { FILE *fp; /* step over the file: prefix */ param = strchr(opt->values[0], ':'); if (NULL == param) { /* malformed input */ pmix_show_help("help-palloc.txt", "bad-option-input", true, pmix_tool_basename, "--pid", opt->values[0], "file:path"); PMIX_INFO_FREE(info, n); return PMIX_ERR_BAD_PARAM; } ++param; fp = fopen(param, "r"); if (NULL == fp) { pmix_show_help("help-palloc.txt", "file-open-error", true, pmix_tool_basename, "--pid", opt->values[0], param); return PMIX_ERR_BAD_PARAM; } rc = fscanf(fp, "%lu", (unsigned long *) &pid); if (1 != rc) { /* if we were unable to obtain the single conversion we * require, then error out */ pmix_show_help("help-palloc.txt", "bad-file", true, pmix_tool_basename, "--pid", opt->values[0], param); fclose(fp); PMIX_INFO_FREE(info, n); return PMIX_ERR_BAD_PARAM; } fclose(fp); PMIX_INFO_LOAD(&info[0], PMIX_SERVER_PIDINFO, &pid, PMIX_PID); } else { /* a string that's neither an integer nor starts with 'file:' */ pmix_show_help("help-palloc.txt", "bad-option-input", true, pmix_tool_basename, "--pid", opt->values[0], "file:path"); PMIX_INFO_FREE(info, n); return PMIX_ERR_BAD_PARAM; } } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_NAMESPACE))) { PMIX_INFO_LOAD(&info[0], PMIX_SERVER_NSPACE, opt->values[0], PMIX_STRING); } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_NSPACE))) { PMIX_INFO_LOAD(&info[0], PMIX_SERVER_NSPACE, opt->values[0], PMIX_STRING); } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_URI))) { PMIX_INFO_LOAD(&info[0], PMIX_SERVER_URI, opt->values[0], PMIX_STRING); } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYS_SERVER_FIRST)) { PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_SYSTEM_FIRST, NULL, PMIX_BOOL); } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYSTEM_SERVER)) { PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_TO_SYSTEM, NULL, PMIX_BOOL); } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_CONNECTION_ORDER))) { PMIX_INFO_LOAD(&info[0], PMIX_CONNECTION_ORDER, opt->values[0], PMIX_STRING); } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYS_CONTROLLER)) { PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_TO_SYS_CONTROLLER, NULL, PMIX_BOOL); } else { /* if none of the above, setup a common "order" to check */ char **tmp = NULL, *t2; PMIx_Argv_append_nosize(&tmp, PMIX_CONNECT_TO_SCHEDULER); PMIx_Argv_append_nosize(&tmp, PMIX_CONNECT_TO_SYS_CONTROLLER); t2 = PMIx_Argv_join(tmp, ','); PMIx_Argv_free(tmp); PMIX_INFO_LOAD(&info[0], PMIX_CONNECTION_ORDER, t2, PMIX_STRING); free(t2); } /* assign our own name */ pmix_asprintf(&kptr, "%s.%s.%lu", pmix_tool_basename, hostname, (unsigned long)getpid()); PMIX_INFO_LOAD(&info[1], PMIX_TOOL_NSPACE, kptr, PMIX_STRING); free(kptr); PMIX_INFO_LOAD(&info[2], PMIX_TOOL_RANK, &rank, PMIX_PROC_RANK); /* init as a tool */ rc = PMIx_tool_init(&myproc, info, n); PMIX_INFO_FREE(info, n); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx_tool_init failed: %s\n", PMIx_Error_string(rc)); exit(rc); } /* construct the allocation request */ options = PMIx_Info_list_start(); if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_REQ_ID))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_REQ_ID, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_QUEUE))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_QUEUE, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_NODES))) { ui64 = strtoul(opt->values[0], NULL, 10); PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_NUM_NODES, &ui64, PMIX_UINT64); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_IMAGE))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_IMAGE, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_EXCLUDE))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_EXCLUDE, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_WAIT_ALL_NODES))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_WAIT_ALL_NODES, NULL, PMIX_BOOL); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_NODELIST))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_NODE_LIST, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_UID))) { ui32 = strtoul(opt->values[0], NULL, 10); PMIX_INFO_LIST_ADD(rc, options, PMIX_USERID, &ui32, PMIX_UINT32); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_GID))) { ui32 = strtoul(opt->values[0], NULL, 10); PMIX_INFO_LIST_ADD(rc, options, PMIX_GRPID, &ui32, PMIX_UINT32); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_TIME))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_TIME, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_SIGNAL))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_NODE_LIST, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_SHARE))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_SHARE, NULL, PMIX_BOOL); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_EXTEND))) { directive = PMIX_ALLOC_EXTEND; } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_SHRINK))) { directive = PMIX_ALLOC_RELEASE; } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_NO_SHELL))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_NOSHELL, NULL, PMIX_BOOL); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_BEGIN))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_BEGIN, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_IMMEDIATE))) { if (NULL == opt->values || NULL == opt->values[0]) { ui32 = 0; } else { ui32 = PMIX_CONVERT_TIME(opt->values[0]); } PMIX_INFO_LIST_ADD(rc, options, PMIX_TIMEOUT, &ui32, PMIX_UINT); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_DEPENDENCY))) { PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_DEPENDENCY, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_DO_NOT_WAIT))) { donotwait = true; PMIX_INFO_LIST_ADD(rc, options, PMIX_ALLOC_NOT_WAITING, NULL, PMIX_BOOL); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIX_INFO_LIST_RELEASE(options); goto done; } } req = PMIX_NEW(pmix_shift_caddy_t); PMIX_INFO_LIST_CONVERT(rc, options, &darray); if (PMIX_ERR_EMPTY == rc) { req->info = NULL; req->ninfo = 0; } else if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto done; } else { req->info = (pmix_info_t *) darray.array; req->ninfo = darray.size; } PMIX_INFO_LIST_RELEASE(options); // register an event handler so we can exit if the server // goes away PMIX_INFO_CREATE(info, 2); PMIX_INFO_LOAD(&info[1], PMIX_EVENT_RETURN_OBJECT, req, PMIX_POINTER); PMIX_INFO_LOAD(&info[0], PMIX_EVENT_HDLR_NAME, "DEFAULT", PMIX_STRING); PMIX_CONSTRUCT_LOCK(&lock); PMIx_Register_event_handler(NULL, 0, info, 2, defhandler, regcbfunc, &lock); PMIX_WAIT_THREAD(&lock); PMIX_DESTRUCT_LOCK(&lock); PMIX_INFO_FREE(info, 2); rc = PMIx_Allocation_request_nb(directive, req->info, req->ninfo, cbfunc, req); if (PMIX_SUCCESS != rc) { if (PMIX_OPERATION_SUCCEEDED == rc) { fprintf(stderr, "Allocation %s granted\n", req->key); PMIX_RELEASE(req); rc = PMIX_SUCCESS; goto done; } fprintf(stderr, "Allocation request failed: %s\n", PMIx_Error_string(rc)); goto done; } if (donotwait) { fprintf(stderr, "Allocation request being processed\n"); goto done; } PMIX_WAIT_THREAD(&req->lock); if (PMIX_SUCCESS == req->status) { fprintf(stderr, "Allocation %s granted\n", req->key); } else { fprintf(stderr, "Allocation request failed: %s\n", PMIx_Error_string(req->status)); } done: if (NULL != req) { PMIX_RELEASE(req); } PMIx_tool_finalize(); return (rc); } pmix-6.1.1~rc2/src/tools/pattrs/0000775000175000017500000000000015203536752016741 5ustar alastairalastairpmix-6.1.1~rc2/src/tools/pattrs/pattrs.c0000664000175000017500000004640615203536752020434 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "pmix_config.h" #include "pmix_common.h" #include #include #include #include #include #include "include/pmix_tool.h" #include "src/common/pmix_attributes.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/runtime/pmix_rte.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_show_help.h" #define PMIX_PRINT_ATTR_COLUMN_WIDTH 141 typedef struct { pmix_lock_t lock; pmix_status_t status; } mylock_t; static pmix_proc_t myproc; /* define a structure for collecting returned * info from a query */ typedef struct { pmix_lock_t lock; pmix_status_t status; pmix_info_t *info; size_t ninfo; } myquery_data_t; /* this is a callback function for the PMIx_Query * API. The query will callback with a status indicating * if the request could be fully satisfied, partially * satisfied, or completely failed. The info parameter * contains an array of the returned data, with the * info->key field being the key that was provided in * the query call. Thus, you can correlate the returned * data in the info->value field to the requested key. * * Once we have dealt with the returned data, we must * call the release_fn so that the PMIx library can * cleanup */ static void querycbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { myquery_data_t *mq = (myquery_data_t *) cbdata; size_t n; mq->status = status; /* save the returned info - the PMIx library "owns" it * and will release it and perform other cleanup actions * when release_fn is called */ if (0 < ninfo) { PMIX_INFO_CREATE(mq->info, ninfo); mq->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&mq->info[n], &info[n]); } } /* let the library release the data and cleanup from * the operation */ if (NULL != release_fn) { release_fn(release_cbdata); } /* release the block */ PMIX_WAKEUP_THREAD(&mq->lock); } /* this is the event notification function we pass down below * when registering for general events - i.e.,, the default * handler. We don't technically need to register one, but it * is usually good practice to catch any events that occur */ static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, info, ninfo, results, nresults); /* this example doesn't do anything with default events */ if (NULL != cbfunc) { cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } /* event handler registration is done asynchronously because it * may involve the PMIx server registering with the host RM for * external events. So we provide a callback function that returns * the status of the request (success or an error), plus a numerical index * to the registered event. The index is used later on to deregister * an event handler - if we don't explicitly deregister it, then the * PMIx server will do so when it see us exit */ static void evhandler_reg_callbk(pmix_status_t status, size_t evhandler_ref, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; if (PMIX_SUCCESS != status) { fprintf(stderr, "Client %s:%d EVENT HANDLER REGISTRATION FAILED WITH STATUS %d, ref=%lu\n", myproc.nspace, myproc.rank, status, (unsigned long) evhandler_ref); } lock->status = status; PMIX_WAKEUP_THREAD(&lock->lock); } #define PMIX_CLI_CLIENT "client" #define PMIX_CLI_SERVER "server" #define PMIX_CLI_TOOL "tool" #define PMIX_CLI_HOST "host" #define PMIX_CLI_CLIENT_FNS "client-fns" #define PMIX_CLI_SERVER_FNS "server-fns" #define PMIX_CLI_TOOL_FNS "tool-fns" #define PMIX_CLI_HOST_FNS "host-fns" static struct option pattroptions[] = { PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_HELP, PMIX_ARG_OPTIONAL, 'h'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERSION, PMIX_ARG_NONE, 'V'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERBOSE, PMIX_ARG_NONE, 'v'), PMIX_OPTION_DEFINE(PMIX_CLI_PMIXMCA, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_SYS_SERVER_FIRST, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SYSTEM_SERVER, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_DO_NOT_CONNECT, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_WAIT_TO_CONNECT, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NUM_CONNECT_RETRIES, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_PID, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NAMESPACE, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_URI, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_TMPDIR, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_CLIENT, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_SERVER, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_TOOL, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_HOST, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_CLIENT_FNS, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SERVER_FNS, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_TOOL_FNS, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_HOST_FNS, PMIX_ARG_NONE), PMIX_OPTION_END }; static char *pattrshorts = "h::vV"; int main(int argc, char **argv) { pmix_status_t rc; pmix_info_t *info; mylock_t mylock; pmix_cli_result_t results; pmix_cli_item_t *opt; char **fns = NULL, *ptr; size_t n, m; myquery_data_t mq; pmix_query_t query; pmix_regattr_t *reg; char **ans = NULL; bool clientfns, serverfns, toolfns, hostfns; char *client, *server, *tool, *host; char line[PMIX_PRINT_ATTR_COLUMN_WIDTH]; PMIX_HIDE_UNUSED_PARAMS(argc); /* protect against problems if someone passes us thru a pipe * and then abnormally terminates the pipe early */ signal(SIGPIPE, SIG_IGN); /* init globals */ pmix_tool_basename = "pattrs"; /* initialize the output system */ if (!pmix_output_init()) { return PMIX_ERROR; } /* initialize install dirs code */ rc = pmix_mca_base_framework_open(&pmix_pinstalldirs_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { fprintf(stderr, "pmix_pinstalldirs_base_open() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, rc); return rc; } if (PMIX_SUCCESS != (rc = pmix_pinstall_dirs_base_init(NULL, 0))) { fprintf(stderr, "pmix_pinstalldirs_base_init() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, rc); return rc; } /* initialize the help system */ pmix_show_help_init(); /* keyval lex-based parser */ if (PMIX_SUCCESS != (rc = pmix_util_keyval_parse_init())) { fprintf(stderr, "pmix_util_keyval_parse_init failed with %d\n", rc); return PMIX_ERROR; } /* Setup the parameter system */ if (PMIX_SUCCESS != (rc = pmix_mca_base_var_init())) { fprintf(stderr, "pmix_mca_base_var_init failed with %d\n", rc); return PMIX_ERROR; } /* Parse the command line options */ PMIX_CONSTRUCT(&results, pmix_cli_result_t); rc = pmix_cmd_line_parse(argv, pattrshorts, pattroptions, NULL, &results, "help-pattrs.txt"); if (PMIX_SUCCESS != rc) { if (PMIX_ERR_SILENT != rc && PMIX_OPERATION_SUCCEEDED != rc) { fprintf(stderr, "%s: command line error (%s)\n", argv[0], PMIx_Error_string(rc)); } if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } exit(rc); } // handle relevant MCA params PMIX_LIST_FOREACH(opt, &results.instances, pmix_cli_item_t) { if (0 == strcmp(opt->key, PMIX_CLI_PMIXMCA)) { for (n=0; NULL != opt->values[n]; n++) { pmix_expose_param(opt->values[n]); } } } /* register params for pmix */ if (PMIX_SUCCESS != (rc = pmix_register_params())) { fprintf(stderr, "pmix_register_params failed with %d\n", rc); return PMIX_ERROR; } client = pmix_cmd_line_get_nth_instance(&results, PMIX_CLI_CLIENT, 0); server = pmix_cmd_line_get_nth_instance(&results, PMIX_CLI_SERVER, 0); tool = pmix_cmd_line_get_nth_instance(&results, PMIX_CLI_TOOL, 0); host = pmix_cmd_line_get_nth_instance(&results, PMIX_CLI_HOST, 0); clientfns = pmix_cmd_line_is_taken(&results, PMIX_CLI_CLIENT_FNS); serverfns = pmix_cmd_line_is_taken(&results, PMIX_CLI_SERVER_FNS); toolfns = pmix_cmd_line_is_taken(&results, PMIX_CLI_TOOL_FNS); hostfns = pmix_cmd_line_is_taken(&results, PMIX_CLI_HOST_FNS); /* cannot list functions and get attributes at same time */ if ((clientfns || serverfns || toolfns || hostfns) && (client || server || tool || host)) { fprintf(stderr, "Cannot request both a list of functions and attributes at same time\n"); exit(1); } /* if they are asking for client, server, or tool attrs, then * we don't need to connect to anyone - just register the * attrs and report */ if (clientfns || serverfns || toolfns || client || server || tool) { PMIX_INFO_CREATE(info, 1); PMIX_INFO_LOAD(&info[0], PMIX_TOOL_DO_NOT_CONNECT, NULL, PMIX_BOOL); rc = PMIx_tool_init(&myproc, info, 1); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx_tool_init failed: %s\n", PMIx_Error_string(rc)); exit(rc); } if (clientfns) { pmix_register_client_attrs(); fns = pmix_attributes_print_functions(PMIX_CLIENT_FUNCTIONS); } else if (serverfns) { pmix_register_server_attrs(); fns = pmix_attributes_print_functions(PMIX_SERVER_FUNCTIONS); } else if (toolfns) { pmix_register_tool_attrs(); fns = pmix_attributes_print_functions(PMIX_TOOL_FUNCTIONS); } else if (NULL != client) { pmix_register_client_attrs(); fns = pmix_attributes_print_attr(PMIX_CLIENT_ATTRIBUTES, client); } else if (NULL != server) { pmix_register_server_attrs(); fns = pmix_attributes_print_attr(PMIX_SERVER_ATTRIBUTES, server); } else if (NULL != tool) { pmix_register_tool_attrs(); fns = pmix_attributes_print_attr(PMIX_TOOL_ATTRIBUTES, tool); } if (NULL != fns) { for (n = 0; NULL != fns[n]; n++) { fprintf(stderr, "%s\n", fns[n]); } } goto done; } /* if they didn't give us an option, then we can't do anything */ if (!hostfns && NULL == host) { char *str; str = pmix_show_help_string("help-pattrs.txt", "usage", false, pmix_tool_basename, "PMIx", PMIX_PROXY_VERSION, pmix_tool_basename, PMIX_PROXY_BUGREPORT); if (NULL != str) { printf("%s", str); free(str); } exit(1); } /* if we were given the pid of a starter, then direct that * we connect to it */ n = 1; PMIX_INFO_CREATE(info, n); if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_PID))) { /* see if it is an integer value */ char *leftover, *param; pid_t pid; leftover = NULL; pid = strtol(opt->values[0], &leftover, 10); if (NULL == leftover || 0 == strlen(leftover)) { /* it is an integer */ PMIX_INFO_LOAD(&info[0], PMIX_SERVER_PIDINFO, &pid, PMIX_PID); } else if (0 == strncasecmp(opt->values[0], "file", 4)) { FILE *fp; /* step over the file: prefix */ param = strchr(opt->values[0], ':'); if (NULL == param) { /* malformed input */ pmix_show_help("help-pattrs.txt", "bad-option-input", true, pmix_tool_basename, "--pid", opt->values[0], "file:path"); return PMIX_ERR_BAD_PARAM; } ++param; fp = fopen(param, "r"); if (NULL == fp) { pmix_show_help("help-pattrs.txt", "file-open-error", true, pmix_tool_basename, "--pid", opt->values[0], param); return PMIX_ERR_BAD_PARAM; } rc = fscanf(fp, "%lu", (unsigned long *) &pid); if (1 != rc) { /* if we were unable to obtain the single conversion we * require, then error out */ pmix_show_help("help-pattrs.txt", "bad-file", true, pmix_tool_basename, "--pid", opt->values[0], param); fclose(fp); return PMIX_ERR_BAD_PARAM; } fclose(fp); PMIX_INFO_LOAD(&info[0], PMIX_SERVER_PIDINFO, &pid, PMIX_PID); } else { /* a string that's neither an integer nor starts with 'file:' */ pmix_show_help("help-pattrs.txt", "bad-option-input", true, pmix_tool_basename, "--pid", opt->values[0], "file:path"); return PMIX_ERR_BAD_PARAM; } } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_NAMESPACE))) { PMIX_INFO_LOAD(&info[0], PMIX_SERVER_NSPACE, opt->values[0], PMIX_STRING); } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_URI))) { PMIX_INFO_LOAD(&info[0], PMIX_SERVER_URI, opt->values[0], PMIX_STRING); } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYS_SERVER_FIRST)) { /* otherwise, use the system connection first, if available */ PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_SYSTEM_FIRST, NULL, PMIX_BOOL); } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYSTEM_SERVER)) { PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_TO_SYSTEM, NULL, PMIX_BOOL); } else { PMIX_INFO_FREE(info, 1); n = 0; } /* init as a tool */ if (PMIX_SUCCESS != (rc = PMIx_tool_init(&myproc, info, n))) { fprintf(stderr, "PMIx_tool_init failed: %s\n", PMIx_Error_string(rc)); exit(rc); } PMIX_INFO_FREE(info, 1); /* register a default event handler */ PMIX_CONSTRUCT_LOCK(&mylock.lock); PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, evhandler_reg_callbk, (void *) &mylock); PMIX_WAIT_THREAD(&mylock.lock); if (PMIX_SUCCESS != mylock.status) { fprintf(stderr, "PMIx_Register_event_handler returned bad status: %d\n", mylock.status); PMIX_DESTRUCT_LOCK(&mylock.lock); rc = mylock.status; goto done; } PMIX_DESTRUCT_LOCK(&mylock.lock); /* generate the query */ PMIX_QUERY_CONSTRUCT(&query); PMIx_Argv_append_nosize(&query.keys, PMIX_QUERY_ATTRIBUTE_SUPPORT); PMIX_QUERY_QUALIFIERS_CREATE(&query, 1); if (hostfns) { PMIX_INFO_LOAD(&query.qualifiers[0], PMIX_HOST_FUNCTIONS, NULL, PMIX_BOOL); } else { PMIX_INFO_LOAD(&query.qualifiers[0], PMIX_HOST_ATTRIBUTES, host, PMIX_STRING); } PMIX_CONSTRUCT_LOCK(&mq.lock); rc = PMIx_Query_info_nb(&query, 1, querycbfunc, (void *) &mq); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx_Query_info failed: %d\n", rc); goto done; } PMIX_WAIT_THREAD(&mq.lock); PMIX_DESTRUCT_LOCK(&mq.lock); if (PMIX_SUCCESS != mq.status) { fprintf(stderr, "PMIx_Query_info returned: %s\n", PMIx_Error_string(mq.status)); rc = mq.status; } else if (!PMIX_CHECK_KEY(&mq.info[0], PMIX_QUERY_ATTRIBUTE_SUPPORT)) { fprintf(stderr, "PMIx_Query_info returned incorrect key: %s\n", mq.info[0].key); rc = PMIX_ERR_BAD_PARAM; } else { /* print out the returned value(s) */ if (PMIX_CHECK_KEY(&query.qualifiers[0], PMIX_HOST_FUNCTIONS)) { pmix_attributes_print_headers(&ans, PMIX_HOST_FUNCTIONS); if (PMIX_DATA_ARRAY == mq.info[0].value.type) { info = (pmix_info_t *) mq.info[0].value.data.darray->array; ptr = info[0].value.data.string; } else { ptr = mq.info[0].value.data.string; } ans = PMIx_Argv_split(ptr, ','); for (m = 0; NULL != ans[m]; m++) { fprintf(stderr, "%s\n", ans[m]); } PMIx_Argv_free(ans); ans = NULL; } else { pmix_attributes_print_headers(&ans, PMIX_HOST_ATTRIBUTES); memset(line, '=', PMIX_PRINT_ATTR_COLUMN_WIDTH); line[PMIX_PRINT_ATTR_COLUMN_WIDTH - 1] = '\0'; if (PMIX_DATA_ARRAY == mq.info[0].value.type) { info = (pmix_info_t *) mq.info[0].value.data.darray->array; for (m = 0; m < mq.info[0].value.data.darray->size; m++) { reg = (pmix_regattr_t *) info[m].value.data.darray->array; pmix_attributes_print_attrs(&ans, info[m].key, reg, info[m].value.data.darray->size); /* add a spacer between functions */ PMIx_Argv_append_nosize(&ans, " "); PMIx_Argv_append_nosize(&ans, line); PMIx_Argv_append_nosize(&ans, " "); } } else { reg = (pmix_regattr_t *) mq.info[0].value.data.ptr; pmix_attributes_print_attrs(&ans, mq.info[0].key, reg, 1); } for (m = 0; NULL != ans[m]; m++) { fprintf(stderr, "%s\n", ans[m]); } PMIx_Argv_free(ans); ans = NULL; } } done: PMIx_tool_finalize(); return (rc); } pmix-6.1.1~rc2/src/tools/pattrs/Makefile.am0000664000175000017500000000371315203536752021001 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CFLAGS = \ -DPMIX_CONFIGURE_USER="\"@PMIX_CONFIGURE_USER@\"" \ -DPMIX_CONFIGURE_HOST="\"@PMIX_CONFIGURE_HOST@\"" \ -DPMIX_CONFIGURE_DATE="\"@PMIX_CONFIGURE_DATE@\"" \ -DPMIX_BUILD_USER="\"$$USER\"" \ -DPMIX_BUILD_HOST="\"$${HOSTNAME:-`(hostname || uname -n) | sed 1q`}\"" \ -DPMIX_BUILD_DATE="\"`$(top_srcdir)/config/getdate.sh`\"" \ -DPMIX_BUILD_CFLAGS="\"@CFLAGS@\"" \ -DPMIX_BUILD_CPPFLAGS="\"@CPPFLAGS@\"" \ -DPMIX_BUILD_LDFLAGS="\"@LDFLAGS@\"" \ -DPMIX_BUILD_LIBS="\"@LIBS@\"" \ -DPMIX_CC_ABSOLUTE="\"@PMIX_CC_ABSOLUTE@\"" \ -DPMIX_GREEK_VERSION="\"@PMIX_GREEK_VERSION@\"" \ -DPMIX_REPO_REV="\"@PMIX_REPO_REV@\"" \ -DPMIX_RELEASE_DATE="\"@PMIX_RELEASE_DATE@\"" if PMIX_INSTALL_BINARIES bin_PROGRAMS = pattrs EXTRA_DIST = help-pattrs.txt endif # PMIX_INSTALL_BINARIES pattrs_SOURCES = pattrs.c pattrs_LDADD = \ $(top_builddir)/src/libpmix.la pmix-6.1.1~rc2/src/tools/pattrs/help-pattrs.txt0000664000175000017500000001262715203536752021755 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017-2019 Intel, Inc. All rights reserved. # Copyright (c) 2022-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for pattrs # [version] %s (%s) %s %s # [usage] %s (%s) %s Usage: %s [OPTION]... PMIx Supported Attributes and Functions tool /***** General Options *****/ -h|--help This help message -h|--help Help for the specified option -v|--verbose Enable typical debug options -V|--version Print version and exit --pmixmca Set MCA parameter value --do-not-connect Do not connect to a server --uri Specify the URI of the server to which we are to connect, or the name of the file (specified as file:filename) that contains that info --namespace Namespace of the daemon to which we should connect --pid PID of the daemon to which we should connect (int => PID or file: for file containing the PID --system-server-first First look for a system server and connect to it if found --system-server Connect to a system-level server --tmpdir Set the root for the session directory tree --wait-to-connect Delay specified number of seconds before trying to connect --num-connect-retries Max number of times to try to connect --client Comma-delimited list of client functions whose attributes are to be printed (function or "all") --server Comma-delimited list of server functions whose attributes are to be printed (function or "all") --tool Comma-delimited list of tool functions whose attributes are to be printed (function or "all") --host Comma-delimited list of host functions whose attributes are to be printed (function or "all") --client-fns List the functions supported in this client library --server-fns List the functions supported in this server library --tool-fns List the functions supported in this tool library --host-fns List the functions supported by this host environment Report bugs to %s # [pmixmca] Pass a PMIx MCA parameter Syntax: "pmixmca ", where "key" is the parameter name and "value" is the parameter value. # [do-not-connect] Do not attempt to connect to a PMIx server # [uri] Specify the URI of the PMIx server we are to contact, or the name of the file (specified as file:filename) that contains that info # [namespace] Namespace of the daemon we are to connect to (char*) # [pid] PID of the daemon to which we should connect (int => PID or file: for file containing the PID # [system-server-first] First look for a system server and connect to it if found # [system-server] Connect only to a system-level server - abort if one is not found # [tmpdir] Set the root for the session directory tree # [wait-to-connect] Delay specified number of seconds before trying to connect # [num-connect-retries] Max number of times to try to connect to the specified server (int) # [client] Comma-delimited list of client functions whose attributes are to be printed (function or "all") # [server] Comma-delimited list of server functions whose attributes are to be printed (function or "all") # [tool] Comma-delimited list of tool functions whose attributes are to be printed (function or "all") # [host] Comma-delimited list of host functions whose attributes are to be printed (function or "all") # [client-fns] List the functions supported in this client library # [server-fns] List the functions supported in this server library # [tool-fns] List the functions supported in this tool library # [host-fns] List the functions supported by this host environment # [bad-option-input] %s was given an option that expected a string argument: option: %s argument: %s expected: %s Please correct the option and try again. # [file-open-error] %s was unable to open the specified file provided as an option: option: %s argument: %s file: %s Please correct the option and try again. # [bad-file] %s was unable to read the necessary info from the provided file: option: %s argument: %s file: %s Please correct the option or the file and try again. pmix-6.1.1~rc2/src/tools/Makefile.include0000664000175000017500000000272515203536752020514 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2006-2008 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2011-2013 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2014-2020 Intel, Inc. All rights reserved. # Copyright (c) 2023 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This makefile.include does not stand on its own - it is included from # src/Makefile.am SUBDIRS += \ tools/pevent \ tools/pmix_info \ tools/plookup \ tools/pps \ tools/pattrs \ tools/pquery \ tools/wrapper \ tools/palloc \ tools/pctrl DIST_SUBDIRS += \ tools/pevent \ tools/pmix_info \ tools/plookup \ tools/pps \ tools/pattrs \ tools/pquery \ tools/wrapper \ tools/palloc \ tools/pctrl pmix-6.1.1~rc2/src/tools/pps/0000775000175000017500000000000015203536752016226 5ustar alastairalastairpmix-6.1.1~rc2/src/tools/pps/help-pps.txt0000664000175000017500000000600115203536752020514 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017 Intel, Inc. All rights reserved. # Copyright (c) 2021-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for PMIx PS tool # [version] %s (%s) %s %s # [usage] %s (%s) %s Usage: %s [OPTION]... PMIx Job and Process Status Tool /***** General Options *****/ -h|--help This help message -h|--help Help for the specified option -v|--verbose Enable typical debug options -V|--version Print version and exit --uri Specify the URI of the server to which we are to connect, or the name of the file (specified as file:filename) that contains that info --namespace Namespace of the daemon to which we should connect --pid PID of the daemon to which we should connect (int => PID or file: for file containing the PID --system-server-first First look for a system server and connect to it if found --system-server Connect to a system-level server --tmpdir Set the root for the session directory tree --wait-to-connect Delay specified number of seconds before trying to connect --num-connect-retries Max number of times to try to connect --nodes Display Node Information Report bugs to %s # [uri] Specify the URI of the PMIx server we are to contact, or the name of the file (specified as file:filename) that contains that info # [namespace] Namespace of the daemon we are to connect to (char*) # [pid] PID of the daemon to which we should connect (int => PID or file: for file containing the PID # [system-server-first] First look for a system server and connect to it if found # [system-server] Connect only to a system-level server - abort if one is not found # [tmpdir] Set the root for the session directory tree # [wait-to-connect] Delay specified number of seconds before trying to connect # [num-connect-retries] Max number of times to try to connect to the specified server (int) # [nodes] Display node-level information pmix-6.1.1~rc2/src/tools/pps/pps.c0000664000175000017500000006351115203536752017202 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2007-2016 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @fie * PMIX PS command * */ #include "pmix_config.h" #include "pmix_common.h" #include #include #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #include #ifdef HAVE_SYS_STAT_H # include #endif /* HAVE_SYS_STAT_H */ #ifdef HAVE_SYS_TYPES_H # include #endif /* HAVE_SYS_TYPES_H */ #ifdef HAVE_SYS_WAIT_H # include #endif /* HAVE_SYS_WAIT_H */ #include #ifdef HAVE_DIRENT_H # include #endif /* HAVE_DIRENT_H */ #include "src/mca/base/pmix_base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/runtime/pmix_rte.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_show_help.h" #include "include/pmix.h" #include "include/pmix_tool.h" #include "src/include/pmix_globals.h" typedef struct { pmix_lock_t lock; pmix_status_t status; } mylock_t; /* define a structure for collecting returned * info from a query */ typedef struct { mylock_t lock; pmix_info_t *info; size_t ninfo; } myquery_data_t; static pmix_proc_t myproc; /****************** * Local Functions ******************/ #if 0 static int gather_information(pmix_ps_mpirun_info_t *hnpinfo); static int gather_active_jobs(pmix_ps_mpirun_info_t *hnpinfo); static int gather_nodes(pmix_ps_mpirun_info_t *hnpinfo); static int gather_vpid_info(pmix_ps_mpirun_info_t *hnpinfo); static int pretty_print(pmix_ps_mpirun_info_t *hnpinfo); static int pretty_print_nodes(pmix_node_t **nodes, pmix_std_cntr_t num_nodes); static int pretty_print_jobs(pmix_job_t **jobs, pmix_std_cntr_t num_jobs); static int pretty_print_vpids(pmix_job_t *job); static void pretty_print_dashed_line(int len); static char *pretty_node_state(pmix_node_state_t state); static int parseable_print(pmix_ps_mpirun_info_t *hnpinfo); #endif #define PMIX_CLI_NODES "nodes" static struct option ppsoptions[] = { PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_HELP, PMIX_ARG_OPTIONAL, 'h'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERSION, PMIX_ARG_NONE, 'V'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERBOSE, PMIX_ARG_NONE, 'v'), PMIX_OPTION_DEFINE(PMIX_CLI_SYS_SERVER_FIRST, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SYSTEM_SERVER, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_WAIT_TO_CONNECT, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NUM_CONNECT_RETRIES, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_PID, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NAMESPACE, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_URI, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NODES, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_TMPDIR, PMIX_ARG_REQD), PMIX_OPTION_END }; static char *ppsshorts = "h::vV"; /* this is a callback function for the PMIx_Query * API. The query will callback with a status indicating * if the request could be fully satisfied, partially * satisfied, or completely failed. The info parameter * contains an array of the returned data, with the * info->key field being the key that was provided in * the query call. Thus, you can correlate the returned * data in the info->value field to the requested key. * * Once we have dealt with the returned data, we must * call the release_fn so that the PMIx library can * cleanup */ static void querycbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { myquery_data_t *mq = (myquery_data_t *) cbdata; size_t n; PMIX_HIDE_UNUSED_PARAMS(status); /* save the returned info - the PMIx library "owns" it * and will release it and perform other cleanup actions * when release_fn is called */ if (0 < ninfo) { PMIX_INFO_CREATE(mq->info, ninfo); mq->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&mq->info[n], &info[n]); } } /* let the library release the data and cleanup from * the operation */ if (NULL != release_fn) { release_fn(release_cbdata); } /* release the block */ PMIX_WAKEUP_THREAD(&mq->lock.lock); } /* this is the event notification function we pass down below * when registering for general events - i.e.,, the default * handler. */ static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, info, ninfo, results, nresults); /* this example doesn't do anything with default events */ if (NULL != cbfunc) { cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } /* event handler registration is done asynchronously because it * may involve the PMIx server registering with the host RM for * external events. So we provide a callback function that returns * the status of the request (success or an error), plus a numerical index * to the registered event. The index is used later on to deregister * an event handler - if we don't explicitly deregister it, then the * PMIx server will do so when it see us exit */ static void evhandler_reg_callbk(pmix_status_t status, size_t evhandler_ref, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; if (PMIX_SUCCESS != status) { fprintf(stderr, "Client %s:%d EVENT HANDLER REGISTRATION FAILED WITH STATUS %d, ref=%lu\n", myproc.nspace, myproc.rank, status, (unsigned long) evhandler_ref); } lock->status = status; PMIX_WAKEUP_THREAD(&lock->lock); } int main(int argc, char *argv[]) { pmix_status_t rc = PMIX_SUCCESS; pmix_info_t *info; pmix_query_t *query; size_t nq; myquery_data_t myquery_data; mylock_t mylock; pmix_cli_result_t results; PMIX_HIDE_UNUSED_PARAMS(argc); /* protect against problems if someone passes us thru a pipe * and then abnormally terminates the pipe early */ signal(SIGPIPE, SIG_IGN); /* init globals */ pmix_tool_basename = "pps"; /* initialize the output system */ if (!pmix_output_init()) { return PMIX_ERROR; } /* initialize install dirs code */ rc = pmix_mca_base_framework_open(&pmix_pinstalldirs_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { fprintf(stderr, "pmix_pinstalldirs_base_open() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, rc); return rc; } if (PMIX_SUCCESS != (rc = pmix_pinstall_dirs_base_init(NULL, 0))) { fprintf(stderr, "pmix_pinstalldirs_base_init() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, rc); return rc; } /* initialize the help system */ pmix_show_help_init(); /* keyval lex-based parser */ if (PMIX_SUCCESS != (rc = pmix_util_keyval_parse_init())) { fprintf(stderr, "pmix_util_keyval_parse_init failed with %d\n", rc); return PMIX_ERROR; } /* Setup the parameter system */ if (PMIX_SUCCESS != (rc = pmix_mca_base_var_init())) { fprintf(stderr, "pmix_mca_base_var_init failed with %d\n", rc); return PMIX_ERROR; } /* register params for pmix */ if (PMIX_SUCCESS != (rc = pmix_register_params())) { fprintf(stderr, "pmix_register_params failed with %d\n", rc); return PMIX_ERROR; } /* Parse the command line options */ PMIX_CONSTRUCT(&results, pmix_cli_result_t); rc = pmix_cmd_line_parse(argv, ppsshorts, ppsoptions, NULL, &results, "help-pps.txt"); if (PMIX_SUCCESS != rc) { if (PMIX_ERR_SILENT != rc && PMIX_OPERATION_SUCCEEDED != rc) { fprintf(stderr, "%s: command line error (%s)\n", argv[0], PMIx_Error_string(rc)); } if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } exit(rc); } /* if we were given the pid of a starter, then direct that * we connect to it */ /* otherwise, use the system connection first, if available */ PMIX_INFO_CREATE(info, 1); PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_SYSTEM_FIRST, NULL, PMIX_BOOL); /* init as a tool */ if (PMIX_SUCCESS != (rc = PMIx_tool_init(&myproc, info, 1))) { fprintf(stderr, "PMIx_tool_init failed: %d\n", rc); exit(rc); } PMIX_INFO_FREE(info, 1); /* register a default event handler */ PMIX_CONSTRUCT_LOCK(&mylock.lock); PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, evhandler_reg_callbk, (void *) &mylock); PMIX_WAIT_THREAD(&mylock.lock); PMIX_DESTRUCT_LOCK(&mylock.lock); /* if we were given a specific nspace to ask about, then do so */ /* if we were asked to provide the status of the nodes, then do that */ /* otherwise, query the active nspaces */ nq = 1; PMIX_QUERY_CREATE(query, nq); PMIX_ARGV_APPEND(rc, query[0].keys, PMIX_QUERY_NAMESPACES); /* setup the caddy to retrieve the data */ PMIX_CONSTRUCT_LOCK(&myquery_data.lock.lock); myquery_data.info = NULL; myquery_data.ninfo = 0; /* execute the query */ if (PMIX_SUCCESS != (rc = PMIx_Query_info_nb(query, nq, querycbfunc, (void *) &myquery_data))) { fprintf(stderr, "PMIx_Query_info failed: %d\n", rc); goto done; } PMIX_WAIT_THREAD(&myquery_data.lock.lock); PMIX_DESTRUCT_LOCK(&myquery_data.lock.lock); /* we should have received back one info struct containing * a comma-delimited list of nspaces */ if (1 != myquery_data.ninfo) { /* this is an error */ fprintf(stderr, "PMIx Query returned an incorrect number of results: %lu\n", myquery_data.ninfo); PMIX_INFO_FREE(myquery_data.info, myquery_data.ninfo); goto done; } fprintf(stderr, "Active nspaces: %s\n", myquery_data.info[0].value.data.string); /*************** * Cleanup ***************/ done: PMIx_tool_finalize(); return rc; } #if 0 static int pretty_print(pmix_ps_mpirun_info_t *hnpinfo) { char *header; int len_hdr; /* * Print header and remember header length */ len_hdr = asprintf(&header, "Information from mpirun %s", PMIX_JOBID_PRINT(hnpinfo->hnp->name.jobid)); printf("\n\n%s\n", header); free(header); pretty_print_dashed_line(len_hdr); /* * Print Node Information */ if( pmix_ps_globals.nodes ) pretty_print_nodes(hnpinfo->nodes, hnpinfo->num_nodes); /* * Print Job Information */ pretty_print_jobs(hnpinfo->jobs, hnpinfo->num_jobs); return PMIX_SUCCESS; } static int pretty_print_nodes(pmix_node_t **nodes, pmix_std_cntr_t num_nodes) { int line_len; int len_name = 0, len_state = 0, len_slots = 0, len_slots_i = 0, len_slots_m = 0; pmix_node_t *node; pmix_std_cntr_t i; /* * Calculate segment lengths */ len_name = (int) strlen("Node Name"); len_state = (int) strlen("State"); len_slots = (int) strlen("Slots"); len_slots_i = (int) strlen("Slots In Use"); len_slots_m = (int) strlen("Slots Max"); for(i=0; i < num_nodes; i++) { node = nodes[i]; if( NULL != node->name && (int)strlen(node->name) > len_name) len_name = (int) strlen(node->name); if( (int)strlen(pretty_node_state(node->state)) > len_state ) len_state = (int)strlen(pretty_node_state(node->state)); } line_len = (len_name + 3 + len_state + 3 + len_slots + 3 + len_slots_i + 3 + len_slots_m) + 2; /* * Print the header */ printf("%*s | ", len_name, "Node Name"); printf("%*s | ", len_state, "State"); printf("%*s | ", len_slots, "Slots"); printf("%*s | ", len_slots_m, "Slots Max"); printf("%*s | ", len_slots_i, "Slots In Use"); printf("\n"); pretty_print_dashed_line(line_len); /* * Print Info */ for(i=0; i < num_nodes; i++) { node = nodes[i]; printf("%*s | ", len_name, node->name); printf("%*s | ", len_state, pretty_node_state(node->state)); printf("%*d | ", len_slots, (uint)node->slots); printf("%*d | ", len_slots_m, (uint)node->slots_max); printf("%*d | ", len_slots_i, (uint)node->slots_inuse); printf("\n"); } return PMIX_SUCCESS; } static int pretty_print_jobs(pmix_job_t **jobs, pmix_std_cntr_t num_jobs) { int len_jobid = 0, len_state = 0, len_slots = 0, len_vpid_r = 0, len_ckpt_s = 0, len_ckpt_r = 0, len_ckpt_l = 0; int line_len; pmix_job_t *job; pmix_std_cntr_t i; char *jobstr; pmix_jobid_t mask=0x0000ffff; for(i=0; i < num_jobs; i++) { job = jobs[i]; /* check the jobid to see if this is the daemons' job */ if ((0 == (mask & job->jobid)) && !pmix_ps_globals.daemons) { continue; } /* setup the printed name - do -not- free this! */ jobstr = PMIX_JOBID_PRINT(job->jobid); /* * Calculate segment lengths */ len_jobid = strlen(jobstr);; len_state = (int) (strlen(pmix_job_state_to_str(job->state)) < strlen("State") ? strlen("State") : strlen(pmix_job_state_to_str(job->state))); len_slots = 6; len_vpid_r = (int) strlen("Num Procs"); len_ckpt_s = -3; len_ckpt_r = -3; len_ckpt_l = -3; line_len = (len_jobid + 3 + len_state + 3 + len_slots + 3 + len_vpid_r + 3 + len_ckpt_s + 3 + len_ckpt_r + 3 + len_ckpt_l) + 2; /* * Print Header */ printf("\n"); printf("%*s | ", len_jobid , "JobID"); printf("%*s | ", len_state , "State"); printf("%*s | ", len_slots , "Slots"); printf("%*s | ", len_vpid_r , "Num Procs"); printf("\n"); pretty_print_dashed_line(line_len); /* * Print Info */ printf("%*s | ", len_jobid , PMIX_JOBID_PRINT(job->jobid)); printf("%*s | ", len_state , pmix_job_state_to_str(job->state)); printf("%*d | ", len_slots , (uint)job->total_slots_alloc); printf("%*d | ", len_vpid_r, job->num_procs); printf("\n"); pretty_print_vpids(job); printf("\n\n"); /* give a little room between job outputs */ } return PMIX_SUCCESS; } static int pretty_print_vpids(pmix_job_t *job) { int len_o_proc_name = 0, len_proc_name = 0, len_rank = 0, len_pid = 0, len_state = 0, len_node = 0, len_ckpt_s = 0, len_ckpt_r = 0, len_ckpt_l = 0; int i, line_len; pmix_vpid_t v; pmix_proc_t *vpid; pmix_app_context_t *app; char *o_proc_name; char **nodename = NULL; if (0 == job->num_procs) { return PMIX_SUCCESS; } /* * Calculate segment lengths */ len_o_proc_name = (int)strlen("PMIX Name"); len_proc_name = (int)strlen("Process Name"); len_rank = (int)strlen("Local Rank"); len_pid = 6; len_state = 0; len_node = 0; len_ckpt_s = -3; len_ckpt_r = -3; len_ckpt_l = -3; nodename = (char **) calloc(job->num_procs, sizeof(char *)); for(v=0; v < job->num_procs; v++) { char *rankstr; vpid = (pmix_proc_t*)job->procs->addr[v]; /* * Find my app context */ if( 0 >= (int)job->num_apps ) { if( 0 == vpid->name.vpid ) { if( (int)strlen("pmixrun") > len_proc_name) len_proc_name = strlen("pmixrun"); } else { if( (int)strlen("pmixd") > len_proc_name) len_proc_name = strlen("pmixd"); } } for( i = 0; i < (int)job->num_apps; ++i) { app = (pmix_app_context_t*)job->apps->addr[i]; if( app->idx == vpid->app_idx ) { if( (int)strlen(app->app) > len_proc_name) len_proc_name = strlen(app->app); break; } } o_proc_name = pmix_util_print_name_args(&vpid->name); if ((int)strlen(o_proc_name) > len_o_proc_name) len_o_proc_name = strlen(o_proc_name); asprintf(&rankstr, "%u", (uint)vpid->local_rank); if ((int)strlen(rankstr) > len_rank) len_rank = strlen(rankstr); free(rankstr); nodename[v] = NULL; if( pmix_get_attribute(&vpid->attributes, PMIX_PROC_NODENAME, (void**)&nodename[v], PMIX_STRING) && (int)strlen(nodename[v]) > len_node) { len_node = strlen(nodename[v]); } else if ((int)strlen("Unknown") > len_node) { len_node = strlen("Unknown"); } if( (int)strlen(pmix_proc_state_to_str(vpid->state)) > len_state) len_state = strlen(pmix_proc_state_to_str(vpid->state)); } line_len = (len_o_proc_name + 3 + len_proc_name + 3 + len_rank + 3 + len_pid + 3 + len_state + 3 + len_node + 3 + len_ckpt_s + 3 + len_ckpt_r + 3 + len_ckpt_l) + 2; /* * Print Header */ printf("\t"); printf("%*s | ", len_proc_name , "Process Name"); printf("%*s | ", len_o_proc_name , "PMIX Name"); printf("%*s | ", len_rank , "Local Rank"); printf("%*s | ", len_pid , "PID"); printf("%*s | ", len_node , "Node"); printf("%*s | ", len_state , "State"); printf("\n"); printf("\t"); pretty_print_dashed_line(line_len); /* * Print Info */ for(v=0; v < job->num_procs; v++) { vpid = (pmix_proc_t*)job->procs->addr[v]; printf("\t"); if( 0 >= (int)job->num_apps ) { if( 0 == vpid->name.vpid ) { printf("%*s | ", len_proc_name, "pmixrun"); } else { printf("%*s | ", len_proc_name, "pmixd"); } } for( i = 0; i < (int)job->num_apps; ++i) { app = (pmix_app_context_t*)job->apps->addr[i]; if( app->idx == vpid->app_idx ) { printf("%*s | ", len_proc_name, app->app); break; } } o_proc_name = pmix_util_print_name_args(&vpid->name); printf("%*s | ", len_o_proc_name, o_proc_name); printf("%*u | ", len_rank , (uint)vpid->local_rank); printf("%*d | ", len_pid , vpid->pid); printf("%*s | ", len_node , (NULL == nodename[v]) ? "Unknown" : nodename[v]); printf("%*s | ", len_state , pmix_proc_state_to_str(vpid->state)); if (NULL != nodename[v]) { free(nodename[v]); } printf("\n"); } if (NULL != nodename) { free(nodename); } return PMIX_SUCCESS; } static void pretty_print_dashed_line(int len) { static const char dashes[9] = "--------"; while (len >= 8) { printf("%8.8s", dashes); len -= 8; } printf("%*.*s\n", len, len, dashes); } static int gather_information(pmix_ps_mpirun_info_t *hnpinfo) { int ret; if( PMIX_SUCCESS != (ret = gather_active_jobs(hnpinfo) )) { goto cleanup; } if( PMIX_SUCCESS != (ret = gather_nodes(hnpinfo) )) { goto cleanup; } if( PMIX_SUCCESS != (ret = gather_vpid_info(hnpinfo) )) { goto cleanup; } cleanup: return ret; } static int gather_active_jobs(pmix_ps_mpirun_info_t *hnpinfo) { int ret; if (PMIX_SUCCESS != (ret = pmix_util_comm_query_job_info(&(hnpinfo->hnp->name), pmix_ps_globals.jobid, &hnpinfo->num_jobs, &hnpinfo->jobs))) { PMIX_ERROR_LOG(ret); } return ret; } static int gather_nodes(pmix_ps_mpirun_info_t *hnpinfo) { int ret; if (PMIX_SUCCESS != (ret = pmix_util_comm_query_node_info(&(hnpinfo->hnp->name), NULL, &hnpinfo->num_nodes, &hnpinfo->nodes))) { PMIX_ERROR_LOG(ret); } pmix_output(0, "RECEIVED %d NODES", hnpinfo->num_nodes); return ret; } static int gather_vpid_info(pmix_ps_mpirun_info_t *hnpinfo) { int ret; pmix_std_cntr_t i; int cnt; pmix_job_t *job; pmix_proc_t **procs; /* * For each Job in the HNP */ for(i=0; i < hnpinfo->num_jobs; i++) { job = hnpinfo->jobs[i]; /* * Skip getting the vpid's for the HNP, unless asked to do so * The HNP is always the first in the array */ if( 0 == i && !pmix_ps_globals.daemons) { continue; } /* query the HNP for info on the procs in this job */ if (PMIX_SUCCESS != (ret = pmix_util_comm_query_proc_info(&(hnpinfo->hnp->name), job->jobid, PMIX_VPID_WILDCARD, &cnt, &procs))) { PMIX_ERROR_LOG(ret); } job->procs->addr = (void**)procs; job->procs->size = cnt; job->num_procs = cnt; } return PMIX_SUCCESS; } static char *pretty_node_state(pmix_node_state_t state) { switch(state) { case PMIX_NODE_STATE_DOWN: return strdup("Down"); break; case PMIX_NODE_STATE_UP: return strdup("Up"); break; case PMIX_NODE_STATE_REBOOT: return strdup("Reboot"); break; case PMIX_NODE_STATE_UNKNOWN: default: return strdup("Unknown"); break; } } static int parseable_print(pmix_ps_mpirun_info_t *hnpinfo) { pmix_job_t **jobs; pmix_node_t **nodes; pmix_proc_t *proc; pmix_app_context_t *app; char *appname; int i, j; char *nodename; /* don't include the daemon job in the number of jobs reppmixd */ printf("mpirun:%lu:num nodes:%d:num jobs:%d\n", (unsigned long)hnpinfo->hnp->pid, hnpinfo->num_nodes, hnpinfo->num_jobs-1); if (pmix_ps_globals.nodes) { nodes = hnpinfo->nodes; for (i=0; i < hnpinfo->num_nodes; i++) { printf("node:%s:state:%s:slots:%d:in use:%d\n", nodes[i]->name, pretty_node_state(nodes[i]->state), nodes[i]->slots, nodes[i]->slots_inuse); } } jobs = hnpinfo->jobs; /* skip job=0 as that's the daemon job */ for (i=1; i < hnpinfo->num_jobs; i++) { printf("jobid:%d:state:%s:slots:%d:num procs:%d\n", PMIX_LOCAL_JOBID(jobs[i]->jobid), pmix_job_state_to_str(jobs[i]->state), jobs[i]->total_slots_alloc, jobs[i]->num_procs); /* print the proc info */ for (j=0; j < jobs[i]->procs->size; j++) { if (NULL == (proc = (pmix_proc_t*)pmix_pointer_array_get_item(jobs[i]->procs, j))) { continue; } app = (pmix_app_context_t*)pmix_pointer_array_get_item(jobs[i]->apps, proc->app_idx); if (NULL == app) { appname = strdup("NULL"); } else { appname = pmix_basename(app->app); } nodename = NULL; pmix_get_attribute(&proc->attributes, PMIX_PROC_NODENAME, (void**)&nodename, PMIX_STRING); printf("process:%s:rank:%s:pid:%lu:node:%s:state:%s\n", appname, PMIX_VPID_PRINT(proc->name.vpid), (unsigned long)proc->pid, (NULL == nodename) ? "unknown" : nodename, pmix_proc_state_to_str(proc->state)); free(appname); if (NULL != nodename) { free(nodename); } } } return PMIX_SUCCESS; } #endif pmix-6.1.1~rc2/src/tools/pps/Makefile.am0000664000175000017500000000367715203536752020277 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CFLAGS = \ -DPMIX_CONFIGURE_USER="\"@PMIX_CONFIGURE_USER@\"" \ -DPMIX_CONFIGURE_HOST="\"@PMIX_CONFIGURE_HOST@\"" \ -DPMIX_CONFIGURE_DATE="\"@PMIX_CONFIGURE_DATE@\"" \ -DPMIX_BUILD_USER="\"$$USER\"" \ -DPMIX_BUILD_HOST="\"$${HOSTNAME:-`(hostname || uname -n) | sed 1q`}\"" \ -DPMIX_BUILD_DATE="\"`$(top_srcdir)/config/getdate.sh`\"" \ -DPMIX_BUILD_CFLAGS="\"@CFLAGS@\"" \ -DPMIX_BUILD_CPPFLAGS="\"@CPPFLAGS@\"" \ -DPMIX_BUILD_LDFLAGS="\"@LDFLAGS@\"" \ -DPMIX_BUILD_LIBS="\"@LIBS@\"" \ -DPMIX_CC_ABSOLUTE="\"@PMIX_CC_ABSOLUTE@\"" \ -DPMIX_GREEK_VERSION="\"@PMIX_GREEK_VERSION@\"" \ -DPMIX_REPO_REV="\"@PMIX_REPO_REV@\"" \ -DPMIX_RELEASE_DATE="\"@PMIX_RELEASE_DATE@\"" if PMIX_INSTALL_BINARIES bin_PROGRAMS = pps EXTRA_DIST = help-pps.txt endif # PMIX_INSTALL_BINARIES pps_SOURCES = pps.c pps_LDADD = \ $(top_builddir)/src/libpmix.la pmix-6.1.1~rc2/src/tools/pctrl/0000775000175000017500000000000015203536752016550 5ustar alastairalastairpmix-6.1.1~rc2/src/tools/pctrl/help-pctrl.txt0000664000175000017500000001775215203536752021377 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2022-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for pctrl # [version] %s (%s) %s %s # [usage] %s (%s) %s Usage: %s [OPTION]... PMIx Job control tool /***** General Options *****/ -h|--help This help message -h|--help Help for the specified option -v|--verbose Enable typical debug options -V|--version Print version and exit --pmixmca Set MCA parameter value --uri Specify the URI of the server to which we are to connect, or the name of the file (specified as file:filename) that contains that info --namespace Namespace of the daemon to which we should connect --nspace Synonym for "namespace" --pid PID of the daemon to which we should connect (int => PID or file: for file containing the PID --system-server-first First look for a system server and connect to it if found --system-server-only Connect only to a system-level server --tmpdir Set the root for the session directory tree --wait-to-connect Delay specified number of seconds before trying to connect --num-connect-retries Max number of times to try to connect --request-id String identifier for this job control request --pause Pause the specified processes --resume "Un-pause" the specified processes --cancel Cancel the specified request ID ("all" => cancel all requests from this requestor) --kill Force terminate the specified processes --terminate Politely terminate the specified processes --signal Provide the specified processes with the given signal --restart Restart the specified processes using the given checkpoint ID --checkpoint Checkpoint the specified processes and assign the given ID to it --pset Define a new pset (with the given name) whose membership is comprised of the specified processes --targets Comma-delimited list of target processes for the requested job-control operation Report bugs to %s # [pmixmca] Pass a PMIx MCA parameter Syntax: "pmixmca ", where "key" is the parameter name and "value" is the parameter value. # # CONNECTION OPTIONS # # [uri] Specify the URI of the DVM master, or the name of the file (specified as file:filename) that contains that info # [num-connect-retries] Max number of times to try to connect to the specified server (int) # [pid] PID of the daemon to which we should connect (int => PID or file: for file containing the PID # [namespace] Namespace of the daemon we are to connect to (char*) # [nspace] Namespace of the daemon we are to connect to (char*) - synonym for "namespace" # [system-server-first] First look for a system server and connect to it if found # [system-server-only] Connect only to a system-level server - abort if one is not found # [tmpdir] Define the root location for the session directory tree where the rendezvous files can be found. The rendezvous files contain connection information for a target server and are located in the session directory tree. It may be necessary to point the tool at the location where those files can be found if that location is other than the expected default. The root of the session directory defaults to the system temporary directory as defined in the environment using (in precedence order) the envars TMPDIR, TEMP, and finally TMP. In the absence of any of those variables, PMIx will default to the "/tmp" location. # [wait-to-connect] Delay specified number of seconds before trying to connect # # PCTRL-SPECIFIC OPTIONS # [request-id] String identifier for this job control request. The request ID can be used for subsequent query of request status and/or cancellation of the request. Note that a request ID that matches a currently active request will be rejected - so care should be taken to ensure that the ID provided is unique and not currently in use. # [pause] Pause the specified processes. This typically takes the form of applying a SIGSTOP to the specified processes. The pctrl tool will return a status indicating whether or not the operation succeeded. # [resume] Direct the specified processes to resume execution. This typically takes the form of applying a SIGCONT signal to the specified processes. The pctrl tool will return a status indicating whether or not the operation succeeded. # [cancel] Cancel the specified request ID. The provided ID must match the ID provided to a prior request - if the ID cannot be found, then a PMIX_ERR_NOT_FOUND status shall be returned by pctrl. # [kill] Force terminate the specified processes. Precise behavior depends upon the runtime environment. However, typically the specified processes will receive the following sequence of signals: * SIGCONT - wakeup a sleeping process * SIGTERM - provide a trappable signal indicating that the process should cleanly exit, if possible * SIGKILL - forcibly terminate the process The pctrl tool will return a status indicating whether or not the operation succeeded (i.e., all processes exited). # [terminate] Politely terminate the specified processes. Precise behavior depends upon the runtime environment. However, typically the specified processes will receive the following sequence of signals: * SIGCONT - wakeup a sleeping process * SIGTERM - provide a trappable signal indicating that the process should cleanly exit, if possible The pctrl tool will return a status indicating whether or not the operation succeeded (i.e., the processes terminated) # [signal] Provide the specified processes with the given signal. Signals are to be provided via their name (e.g., SIGTERM, SIGKILL) or an integer value (e.g., -9). # [restart] "Un-pause" the specified processes - usually implemented by applying a SIGCONT signal to the processes. # [checkpoint] Checkpoint the specified processes and assign the given ID to it. The checkpoint operation will be conducted according to the method specified when the processes were originally spawned. Support for this operation therefore depends both on the capabilities of the runtime environment _and_ the application being told to checkpoint. # [pset] Define a new pset (with the given name) whose membership is comprised of the specified processes. # [targets] Comma-delimited list of target processes for the requested job-control operation. Wildcard ranks (e.g., to apply the request to all processes in the specified namespace) can be indicated with an asterisk ('*'). Syntax requires that each process be identified as "nspace:rank". Note that typical command line restrictions may necessitate the use of special delimiters - e.g., "my\;weird.nspace:5". pmix-6.1.1~rc2/src/tools/pctrl/pctrl.c0000664000175000017500000004663115203536752020052 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "pmix_config.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include #include #include #include #include #include "include/pmix_tool.h" #include "src/common/pmix_attributes.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/runtime/pmix_init_util.h" #include "src/runtime/pmix_rte.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" static struct option pctrlptions[] = { PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_HELP, PMIX_ARG_OPTIONAL, 'h'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERSION, PMIX_ARG_NONE, 'V'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERBOSE, PMIX_ARG_NONE, 'v'), PMIX_OPTION_DEFINE(PMIX_CLI_PMIXMCA, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_SYS_SERVER_FIRST, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SYS_SERVER_ONLY, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_WAIT_TO_CONNECT, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NUM_CONNECT_RETRIES, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_PID, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NAMESPACE, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NSPACE, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_URI, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_TMPDIR, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_SIGNAL, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_REQ_ID, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_PAUSE, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_RESUME, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_CANCEL, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_KILL, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_TERMINATE, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_RESTART, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_CHKPT, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_PSET_NAME, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_TARGETS, PMIX_ARG_REQD), PMIX_OPTION_END }; static char *pctrlshorts = "h::vV"; static pmix_status_t convert_procs(const char *vals, pmix_data_array_t *array); static int convert_signal(const char *val); static void cbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_shift_caddy_t *req = (pmix_shift_caddy_t*)cbdata; PMIX_HIDE_UNUSED_PARAMS(info, ninfo); PMIX_ACQUIRE_OBJECT(req); req->status = status; if (NULL != release_fn) { release_fn(release_cbdata); } PMIX_POST_OBJECT(req); PMIX_WAKEUP_THREAD(&req->lock); } int main(int argc, char **argv) { pmix_proc_t myproc, *targets = NULL; pmix_status_t rc; pmix_shift_caddy_t *req = NULL; pmix_info_t *info; pmix_data_array_t darray; void *options; pmix_cli_result_t results; pmix_cli_item_t *opt; size_t n, ntargets; pmix_rank_t rank = 0; char hostname[PMIX_PATH_MAX], *kptr; int sigval; char *key = NULL; PMIX_HIDE_UNUSED_PARAMS(argc); /* protect against problems if someone passes us thru a pipe * and then abnormally terminates the pipe early */ signal(SIGPIPE, SIG_IGN); /* init globals */ pmix_tool_basename = "pctrl"; gethostname(hostname, sizeof(hostname)); // setup the base infrastructure if (PMIX_SUCCESS != pmix_init_util(NULL, 0, NULL)) { return PMIX_ERROR; } /* Parse the command line options */ PMIX_CONSTRUCT(&results, pmix_cli_result_t); rc = pmix_cmd_line_parse(argv, pctrlshorts, pctrlptions, NULL, &results, "help-pctrl.txt"); if (PMIX_SUCCESS != rc) { if (PMIX_OPERATION_SUCCEEDED == rc) { exit(0); } if (PMIX_ERR_SILENT != rc) { fprintf(stderr, "%s: command line error (%s)\n", argv[0], PMIx_Error_string(rc)); } exit(rc); } // handle relevant MCA params PMIX_LIST_FOREACH(opt, &results.instances, pmix_cli_item_t) { if (0 == strcmp(opt->key, PMIX_CLI_PMIXMCA)) { for (n=0; NULL != opt->values[n]; n++) { pmix_expose_param(opt->values[n]); } } } // check for common required command line option if (NULL == (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_TARGETS))) { // must tell us the targets for the operation exit(1); } // save the targets // convert the provided string to an array of pmix_proc_t rc = convert_procs(opt->values[0], &darray); if (PMIX_SUCCESS != rc) { // report the error exit(rc); } targets = (pmix_proc_t*)darray.array; ntargets = darray.size; // collect options for init options = PMIx_Info_list_start(); /* if we were given the pid of a starter, then direct that * we connect to it */ if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_PID))) { /* see if it is an integer value */ char *leftover, *param; pid_t pid; leftover = NULL; pid = strtol(opt->values[0], &leftover, 10); if (NULL == leftover || 0 == strlen(leftover)) { /* it is an integer */ rc = PMIx_Info_list_add(options, PMIX_SERVER_PIDINFO, &pid, PMIX_PID); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); free(targets); exit(rc); } } else if (0 == strncasecmp(opt->values[0], "file", 4)) { FILE *fp; /* step over the file: prefix */ param = strchr(opt->values[0], ':'); if (NULL == param) { /* malformed input */ pmix_show_help("help-pquery.txt", "bad-option-input", true, pmix_tool_basename, "--pid", opt->values[0], "file:path"); PMIx_Info_list_release(options); free(targets); return PMIX_ERR_BAD_PARAM; } ++param; fp = fopen(param, "r"); if (NULL == fp) { pmix_show_help("help-pquery.txt", "file-open-error", true, pmix_tool_basename, "--pid", opt->values[0], param); PMIx_Info_list_release(options); free(targets); return PMIX_ERR_BAD_PARAM; } rc = fscanf(fp, "%lu", (unsigned long *) &pid); if (1 != rc) { /* if we were unable to obtain the single conversion we * require, then error out */ pmix_show_help("help-pquery.txt", "bad-file", true, pmix_tool_basename, "--pid", opt->values[0], param); fclose(fp); PMIx_Info_list_release(options); free(targets); return PMIX_ERR_BAD_PARAM; } fclose(fp); rc = PMIx_Info_list_add(options, PMIX_SERVER_PIDINFO, &pid, PMIX_PID); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); free(targets); exit(rc); } } else { /* a string that's neither an integer nor starts with 'file:' */ pmix_show_help("help-pquery.txt", "bad-option-input", true, pmix_tool_basename, "--pid", opt->values[0], "file:path"); PMIx_Info_list_release(options); free(targets); return PMIX_ERR_BAD_PARAM; } } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_NAMESPACE))) { rc = PMIx_Info_list_add(options, PMIX_SERVER_NSPACE, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); free(targets); exit(rc); } } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_NSPACE))) { rc = PMIx_Info_list_add(options, PMIX_SERVER_NSPACE, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); free(targets); exit(rc); } } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_URI))) { rc = PMIx_Info_list_add(options, PMIX_SERVER_URI, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); free(targets); exit(rc); } } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYS_SERVER_FIRST)) { rc = PMIx_Info_list_add(options, PMIX_CONNECT_SYSTEM_FIRST, NULL, PMIX_BOOL); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); free(targets); exit(rc); } } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYS_SERVER_ONLY)) { rc = PMIx_Info_list_add(options, PMIX_CONNECT_TO_SYSTEM, NULL, PMIX_BOOL); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); free(targets); exit(rc); } } /* assign our own name */ pmix_asprintf(&kptr, "%s.%s.%lu", pmix_tool_basename, hostname, (unsigned long)getpid()); rc = PMIx_Info_list_add(options, PMIX_TOOL_NSPACE, kptr, PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); free(targets); exit(rc); } free(kptr); rc = PMIx_Info_list_add(options, PMIX_TOOL_RANK, &rank, PMIX_PROC_RANK); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); free(targets); exit(rc); } rc = PMIx_Info_list_convert(options, &darray); info = (pmix_info_t *) darray.array; n = darray.size; PMIx_Info_list_release(options); /* init as a tool */ rc = PMIx_tool_init(&myproc, info, n); PMIX_INFO_FREE(info, n); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx_tool_init failed: %s\n", PMIx_Error_string(rc)); free(targets); exit(rc); } /* construct the job control request */ options = PMIx_Info_list_start(); if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_REQ_ID))) { rc = PMIx_Info_list_add(options, PMIX_JOB_CTRL_ID, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_PAUSE))) { key = "PAUSE"; rc = PMIx_Info_list_add(options, PMIX_JOB_CTRL_PAUSE, NULL, PMIX_BOOL); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_RESUME))) { key = "RESUME"; rc = PMIx_Info_list_add(options, PMIX_JOB_CTRL_RESUME, NULL, PMIX_BOOL); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_CANCEL))) { key = "CANCEL"; rc = PMIx_Info_list_add(options, PMIX_JOB_CTRL_CANCEL, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_KILL))) { key = "KILL"; rc = PMIx_Info_list_add(options, PMIX_JOB_CTRL_KILL, NULL, PMIX_BOOL); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_RESTART))) { key = "RESTART"; rc = PMIx_Info_list_add(options, PMIX_JOB_CTRL_RESTART, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_CHKPT))) { key = "CHECKPOINT"; rc = PMIx_Info_list_add(options, PMIX_JOB_CTRL_CHECKPOINT, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_TERMINATE))) { key = "TERMINATE"; rc = PMIx_Info_list_add(options, PMIX_JOB_CTRL_TERMINATE, NULL, PMIX_BOOL); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_PSET_NAME))) { key = "DEFINE PSET"; rc = PMIx_Info_list_add(options, PMIX_JOB_CTRL_DEFINE_PSET, opt->values[0], PMIX_STRING); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); goto done; } } if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_SIGNAL))) { key = "SIGNAL"; sigval = convert_signal(opt->values[0]); if (0 == sigval) { // unrecognized signal fprintf(stderr, "Unrecognized signal name: %s\n", opt->values[0]); PMIx_Info_list_release(options); rc = -1; goto done; } rc = PMIx_Info_list_add(options, PMIX_JOB_CTRL_SIGNAL, &sigval, PMIX_INT); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx info list add failed: %s\n", PMIx_Error_string(rc)); PMIx_Info_list_release(options); goto done; } } req = PMIX_NEW(pmix_shift_caddy_t); if (NULL != key) { req->key = strdup(key); } else { req->key = strdup("N/A"); } rc = PMIx_Info_list_convert(options, &darray); if (PMIX_ERR_EMPTY == rc) { req->info = NULL; req->ninfo = 0; } else if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto done; } else { req->info = (pmix_info_t *) darray.array; req->ninfo = darray.size; } PMIx_Info_list_release(options); rc = PMIx_Job_control_nb(targets, ntargets, req->info, req->ninfo, cbfunc, req); if (PMIX_SUCCESS != rc) { if (PMIX_OPERATION_SUCCEEDED == rc) { fprintf(stderr, "Job control request %s granted\n", req->key); PMIX_RELEASE(req); rc = PMIX_SUCCESS; goto done; } fprintf(stderr, "Job control request failed: %s\n", PMIx_Error_string(rc)); goto done; } PMIX_WAIT_THREAD(&req->lock); if (PMIX_SUCCESS == req->status) { fprintf(stderr, "Job control %s granted\n", req->key); } else { fprintf(stderr, "Job control request failed: %s\n", PMIx_Error_string(req->status)); } done: if (NULL != req) { PMIX_RELEASE(req); } if (NULL != targets) { free(targets); } PMIx_tool_finalize(); return (rc); } static pmix_status_t convert_procs(const char *vals, pmix_data_array_t *array) { char **p, *r; size_t cnt, n; pmix_proc_t *procs; // split on any commas p = PMIx_Argv_split(vals, ','); // count how many we have cnt = PMIx_Argv_count(p); // setup the array PMIx_Data_array_construct(array, cnt, PMIX_PROC); // load the array procs = (pmix_proc_t*)array->array; for (n=0; NULL != p[n]; n++) { // find the nspace/rank delimiting ':' r = strrchr(p[n], ':'); *r = '\0'; ++r; // step over the colon PMIX_LOAD_NSPACE(procs[n].nspace, p[n]); if ('*' == *r) { procs[n].rank = PMIX_RANK_WILDCARD; } else { procs[n].rank = strtoul(r, NULL, 10); } } return PMIX_SUCCESS; } typedef struct { char *name; int value; } pmix_signal_t; static pmix_signal_t sigs[] = { #ifdef SIGHUP {"SIGHUP", SIGHUP}, #endif #ifdef SIGABRT {"SIGABRT", SIGABRT}, #endif #ifdef SIGALRM {"SIGALRM", SIGALRM}, #endif #ifdef SIGKILL {"SIGKILL", SIGKILL}, #endif #ifdef SIGPIPE {"SIGPIPE", SIGPIPE}, #endif #ifdef SIGTERM {"SIGTERM", SIGTERM}, #endif #ifdef SIGSTOP {"SIGSTOP", SIGSTOP}, #endif #ifdef SIGTSTP {"SIGTSTP", SIGTSTP}, #endif #ifdef SIGCONT {"SIGCONT", SIGCONT}, #endif #ifdef SIGCHLD {"SIGCHLD", SIGCHLD}, #endif #ifdef SIGINFO {"SIGINFO", SIGINFO}, #endif #ifdef SIGUSR1 {"SIGUSR1", SIGUSR1}, #endif #ifdef SIGUSR2 {"SIGUSR2", SIGUSR2}, #endif #ifdef SIGINT {"SIGINT", SIGINT}, #endif #ifdef SIGTRAP {"SIGTRAP", SIGTRAP}, #endif {NULL, 0} }; static int convert_signal(const char *val) { int n; n = 0; while (NULL != sigs[n].name) { if (0 == strcasecmp(val, sigs[n].name)) { return sigs[n].value; } ++n; } return 0; } pmix-6.1.1~rc2/src/tools/pctrl/Makefile.am0000664000175000017500000000220015203536752020576 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # if PMIX_INSTALL_BINARIES bin_PROGRAMS = pctrl EXTRA_DIST = help-pctrl.txt endif # PMIX_INSTALL_BINARIES pctrl_SOURCES = pctrl.c pctrl_LDADD = \ $(top_builddir)/src/libpmix.la pmix-6.1.1~rc2/src/tools/pquery/0000775000175000017500000000000015203536752016751 5ustar alastairalastairpmix-6.1.1~rc2/src/tools/pquery/help-pquery.txt0000664000175000017500000000777715203536752022007 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2022-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for pquery # [version] %s (%s) %s %s # [usage] %s (%s) %s Usage: %s [OPTION] KEY[qualifier(s)] PMIx Query tool /***** General Options *****/ -h|--help This help message -h|--help Help for the specified option -v|--verbose Enable typical debug options -V|--version Print version and exit --pmixmca Set MCA parameter value --uri Specify the URI of the server to which we are to connect, or the name of the file (specified as file:filename) that contains that info --namespace Namespace of the daemon to which we should connect --pid PID of the daemon to which we should connect (int => PID or file: for file containing the PID --system-server-first First look for a system server and connect to it if found --system-server Connect to a system-level server --tmpdir Set the root for the session directory tree --wait-to-connect Delay specified number of seconds before trying to connect --num-connect-retries Max number of times to try to connect Keys passed to pquery may optionally include one or more qualifiers, with the individual qualifiers delimited by semi-colons. For example: PMIX_STORAGE_XFER_SIZE[PMIX_STORAGE_ID=lustre1,lustre2;PMIX_STORAGE_PATH=foo] Report bugs to %s # [pmixmca] Pass a PMIx MCA parameter Syntax: "pmixmca ", where "key" is the parameter name and "value" is the parameter value. # [uri] Specify the URI of the server to which we are to connect, or the name of the file (specified as file:filename) that contains that info # [namespace] Namespace of the daemon to which we should connect # [system-server-first] First look for a system server and connect to it if found # [system-server] Connect to a system server if a local server isn't found # [pid] PID of the daemon to which we should connect (int => PID or file: for file containing the PID # [wait-to-connect] Delay specified number of seconds before trying to connect # [num-connect-retries] Max number of times to try to connect # [tmpdir] Set the root for the session directory tree # [bad-option-input] %s was given an option that expected a string argument: option: %s argument: %s expected: %s Please correct the option and try again. # [file-open-error] %s was unable to open the specified file provided as an option: option: %s argument: %s file: %s Please correct the option and try again. # [bad-file] %s was unable to read the necessary info from the provided file: option: %s argument: %s file: %s Please correct the option or the file and try again. # [bad-quals] %s was unable to parse the command line because it found a qualifier that is not correct: Qualifier: %s Qualifiers must be of the form "[qual1=value1;qual2=val2;...]". Please correct the command line and try again. pmix-6.1.1~rc2/src/tools/pquery/pquery.c0000664000175000017500000004255015203536752020450 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "pmix_config.h" #include "include/pmix.h" #include "pmix_common.h" #include "include/pmix_server.h" #include #include #include #include #include #include "include/pmix_tool.h" #include "src/common/pmix_attributes.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/runtime/pmix_init_util.h" #include "src/runtime/pmix_rte.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" typedef struct { pmix_lock_t lock; pmix_status_t status; } mylock_t; static pmix_proc_t myproc; /* define a structure for collecting returned * info from a query */ typedef struct { pmix_lock_t lock; pmix_status_t status; pmix_info_t *info; size_t ninfo; } myquery_data_t; /* this is a callback function for the PMIx_Query * API. The query will callback with a status indicating * if the request could be fully satisfied, partially * satisfied, or completely failed. The info parameter * contains an array of the returned data, with the * info->key field being the key that was provided in * the query call. Thus, you can correlate the returned * data in the info->value field to the requested key. * * Once we have dealt with the returned data, we must * call the release_fn so that the PMIx library can * cleanup */ static void querycbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { myquery_data_t *mq = (myquery_data_t *) cbdata; size_t n; mq->status = status; /* save the returned info - the PMIx library "owns" it * and will release it and perform other cleanup actions * when release_fn is called */ if (0 < ninfo) { PMIX_INFO_CREATE(mq->info, ninfo); mq->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&mq->info[n], &info[n]); } } /* let the library release the data and cleanup from * the operation */ if (NULL != release_fn) { release_fn(release_cbdata); } /* release the block */ PMIX_WAKEUP_THREAD(&mq->lock); } /* this is the event notification function we pass down below * when registering for general events - i.e.,, the default * handler. We don't technically need to register one, but it * is usually good practice to catch any events that occur */ static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, info, ninfo, results, nresults); /* this example doesn't do anything with default events */ if (NULL != cbfunc) { cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } /* event handler registration is done asynchronously because it * may involve the PMIx server registering with the host RM for * external events. So we provide a callback function that returns * the status of the request (success or an error), plus a numerical index * to the registered event. The index is used later on to deregister * an event handler - if we don't explicitly deregister it, then the * PMIx server will do so when it see us exit */ static void evhandler_reg_callbk(pmix_status_t status, size_t evhandler_ref, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; if (PMIX_SUCCESS != status) { fprintf(stderr, "Client %s:%d EVENT HANDLER REGISTRATION FAILED WITH STATUS %d, ref=%lu\n", myproc.nspace, myproc.rank, status, (unsigned long) evhandler_ref); } lock->status = status; PMIX_WAKEUP_THREAD(&lock->lock); } static struct option pqoptions[] = { PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_HELP, PMIX_ARG_OPTIONAL, 'h'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERSION, PMIX_ARG_NONE, 'V'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERBOSE, PMIX_ARG_NONE, 'v'), PMIX_OPTION_DEFINE(PMIX_CLI_PMIXMCA, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_SYS_SERVER_FIRST, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_SYSTEM_SERVER, PMIX_ARG_NONE), PMIX_OPTION_DEFINE(PMIX_CLI_WAIT_TO_CONNECT, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NUM_CONNECT_RETRIES, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_PID, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_NAMESPACE, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_URI, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_TMPDIR, PMIX_ARG_REQD), PMIX_OPTION_END }; static char *pqshorts = "h::vV"; int main(int argc, char **argv) { pmix_status_t rc; pmix_info_t *info; mylock_t mylock; pmix_cli_result_t results; pmix_cli_item_t *opt; size_t n, m, nqueries; myquery_data_t mq = { .lock = PMIX_LOCK_STATIC_INIT, .status = 0, .info = NULL, .ninfo = 0 }; char **qkeys = NULL; const char *attr; pmix_list_t querylist, qlist; pmix_querylist_t *qry; char **qprs; char *strt, *endp, *kptr; pmix_infolist_t *iptr; char *str, *result, **ans; pmix_query_t *queries; pmix_rank_t rank = 0; char hostname[PMIX_PATH_MAX]; PMIX_HIDE_UNUSED_PARAMS(argc); /* protect against problems if someone passes us thru a pipe * and then abnormally terminates the pipe early */ signal(SIGPIPE, SIG_IGN); /* init globals */ pmix_tool_basename = "pquery"; gethostname(hostname, sizeof(hostname)); // setup the base infrastructure if (PMIX_SUCCESS != pmix_init_util(NULL, 0, NULL)) { return PMIX_ERROR; } /* Parse the command line options */ PMIX_CONSTRUCT(&results, pmix_cli_result_t); rc = pmix_cmd_line_parse(argv, pqshorts, pqoptions, NULL, &results, "help-pquery.txt"); if (PMIX_SUCCESS != rc) { if (PMIX_ERR_SILENT != rc && PMIX_OPERATION_SUCCEEDED != rc) { fprintf(stderr, "%s: command line error (%s)\n", argv[0], PMIx_Error_string(rc)); } if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } exit(rc); } // handle relevant MCA params PMIX_LIST_FOREACH(opt, &results.instances, pmix_cli_item_t) { if (0 == strcmp(opt->key, PMIX_CLI_PMIXMCA)) { for (n=0; NULL != opt->values[n]; n++) { pmix_expose_param(opt->values[n]); } } } // setup the base infrastructure if (PMIX_SUCCESS != pmix_init_util(NULL, 0, NULL)) { return PMIX_ERROR; } /* get the argv array of keys they want us to query */ qkeys = results.tail; /* if they didn't give us an option, then we can't do anything */ if (NULL == qkeys) { str = pmix_show_help_string("help-pquery.txt", "usage", false, pmix_tool_basename, "PMIx", PMIX_PROXY_VERSION, pmix_tool_basename, PMIX_PROXY_BUGREPORT); if (NULL != str) { printf("%s", str); free(str); } exit(1); } /* if we were given the pid of a starter, then direct that * we connect to it */ n = 3; PMIX_INFO_CREATE(info, n); if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_PID))) { /* see if it is an integer value */ char *leftover, *param; pid_t pid; leftover = NULL; pid = strtol(opt->values[0], &leftover, 10); if (NULL == leftover || 0 == strlen(leftover)) { /* it is an integer */ PMIX_INFO_LOAD(&info[0], PMIX_SERVER_PIDINFO, &pid, PMIX_PID); } else if (0 == strncasecmp(opt->values[0], "file", 4)) { FILE *fp; /* step over the file: prefix */ param = strchr(opt->values[0], ':'); if (NULL == param) { /* malformed input */ pmix_show_help("help-pquery.txt", "bad-option-input", true, pmix_tool_basename, "--pid", opt->values[0], "file:path"); return PMIX_ERR_BAD_PARAM; } ++param; fp = fopen(param, "r"); if (NULL == fp) { pmix_show_help("help-pquery.txt", "file-open-error", true, pmix_tool_basename, "--pid", opt->values[0], param); return PMIX_ERR_BAD_PARAM; } rc = fscanf(fp, "%lu", (unsigned long *) &pid); if (1 != rc) { /* if we were unable to obtain the single conversion we * require, then error out */ pmix_show_help("help-pquery.txt", "bad-file", true, pmix_tool_basename, "--pid", opt->values[0], param); fclose(fp); return PMIX_ERR_BAD_PARAM; } fclose(fp); PMIX_INFO_LOAD(&info[0], PMIX_SERVER_PIDINFO, &pid, PMIX_PID); } else { /* a string that's neither an integer nor starts with 'file:' */ pmix_show_help("help-pquery.txt", "bad-option-input", true, pmix_tool_basename, "--pid", opt->values[0], "file:path"); return PMIX_ERR_BAD_PARAM; } } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_NAMESPACE))) { PMIX_INFO_LOAD(&info[0], PMIX_SERVER_NSPACE, opt->values[0], PMIX_STRING); } else if (NULL != (opt = pmix_cmd_line_get_param(&results, PMIX_CLI_URI))) { PMIX_INFO_LOAD(&info[0], PMIX_SERVER_URI, opt->values[0], PMIX_STRING); } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYS_SERVER_FIRST)) { /* otherwise, use the system connection first, if available */ PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_SYSTEM_FIRST, NULL, PMIX_BOOL); } else if (pmix_cmd_line_is_taken(&results, PMIX_CLI_SYSTEM_SERVER)) { PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_TO_SYSTEM, NULL, PMIX_BOOL); } else { /* we set ourselves up as a tool, but no connections required */ PMIX_INFO_LOAD(&info[0], PMIX_TOOL_CONNECT_OPTIONAL, NULL, PMIX_BOOL); } /* assign our own name */ pmix_asprintf(&kptr, "%s.%s.%lu", pmix_tool_basename, hostname, (unsigned long)getpid()); PMIX_INFO_LOAD(&info[1], PMIX_TOOL_NSPACE, kptr, PMIX_STRING); free(kptr); PMIX_INFO_LOAD(&info[2], PMIX_TOOL_RANK, &rank, PMIX_PROC_RANK); /* init as a tool */ rc = PMIx_tool_init(&myproc, info, n); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx_tool_init failed: %s\n", PMIx_Error_string(rc)); exit(rc); } PMIX_INFO_FREE(info, 1); /* they might be querying the system about a client, server, or tool * attribute, so register those - this will allow us to compare the * provided key with the actual name of the attribute so we can * identify it */ pmix_init_registered_attrs(); pmix_register_client_attrs(); pmix_register_server_attrs(); pmix_register_tool_attrs(); /* register a default event handler */ PMIX_CONSTRUCT_LOCK(&mylock.lock); PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, evhandler_reg_callbk, (void *) &mylock); PMIX_WAIT_THREAD(&mylock.lock); if (PMIX_SUCCESS != mylock.status) { fprintf(stderr, "PMIx_Register_event_handler returned bad status: %d\n", mylock.status); PMIX_DESTRUCT_LOCK(&mylock.lock); rc = mylock.status; goto done; } PMIX_DESTRUCT_LOCK(&mylock.lock); /* generate the queries */ PMIX_CONSTRUCT(&querylist, pmix_list_t); for (n = 0; NULL != qkeys[n]; n++) { qry = PMIX_NEW(pmix_querylist_t); PMIX_CONSTRUCT(&qlist, pmix_list_t); /* check for qualifiers: key[qual=foo;qual=bar] */ if (NULL != (strt = strchr(qkeys[n], '['))) { /* we have qualifiers - find the end */ *strt = '\0'; ++strt; if (NULL == (endp = strrchr(strt, ']'))) { str = pmix_show_help_string("help-pquery.txt", "bad-quals", true, qkeys[n]); if (NULL != str) { printf("%s", str); free(str); } exit(1); } *endp = '\0'; /* break into qual=val pairs */ qprs = PMIx_Argv_split(strt, ';'); for (m = 0; NULL != qprs[m]; m++) { /* break each pair */ if (NULL == (kptr = strchr(qprs[m], '='))) { str = pmix_show_help_string("help-pquery.txt", "bad-quals", true, qkeys[n], qprs[m]); if (NULL != str) { printf("%s", str); free(str); } exit(1); } *kptr = '\0'; kptr++; iptr = PMIX_NEW(pmix_infolist_t); if (NULL == (attr = pmix_attributes_lookup(qprs[m]))) { fprintf(stderr, "Failed to lookup %s\n", qprs[m]); exit(1); } PMIX_INFO_LOAD(&iptr->info, attr, kptr, PMIX_STRING); pmix_list_append(&qlist, &iptr->super); } } /* convert the key */ if (NULL == (attr = pmix_attributes_lookup(qkeys[n]))) { fprintf(stderr, "Failed to lookup %s\n", qkeys[n]); exit(1); } PMIx_Argv_append_nosize(&qry->query.keys, attr); /* add in any qualifiers */ m = pmix_list_get_size(&qlist); if (0 < m) { PMIX_QUERY_QUALIFIERS_CREATE(&qry->query, m); m = 0; PMIX_LIST_FOREACH (iptr, &qlist, pmix_infolist_t) { PMIX_INFO_XFER(&qry->query.qualifiers[m], &iptr->info); ++m; } } pmix_list_append(&querylist, &qry->super); PMIX_LIST_DESTRUCT(&qlist); } /* convert the list of queries into an array */ nqueries = pmix_list_get_size(&querylist); PMIX_QUERY_CREATE(queries, nqueries); m = 0; PMIX_LIST_FOREACH (qry, &querylist, pmix_querylist_t) { /* move the queries across */ queries[m].keys = qry->query.keys; queries[m].nqual = qry->query.nqual; queries[m].qualifiers = qry->query.qualifiers; ++m; } PMIX_LIST_DESTRUCT(&querylist); PMIX_CONSTRUCT_LOCK(&mq.lock); rc = PMIx_Query_info_nb(queries, nqueries, querycbfunc, (void *) &mq); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx_Query_info failed: %d\n", rc); goto done; } PMIX_WAIT_THREAD(&mq.lock); PMIX_DESTRUCT_LOCK(&mq.lock); if (PMIX_SUCCESS != mq.status) { fprintf(stderr, "PMIx_Query_info returned: %s\n", PMIx_Error_string(mq.status)); rc = mq.status; } else { if (0 == mq.ninfo) { fprintf(stderr, "Query returned zero results\n"); goto done; } /* print out the returned value(s) */ for (n = 0; n < mq.ninfo; n++) { if (NULL == (attr = pmix_attributes_reverse_lookup(mq.info[n].key))) { fprintf(stdout, "%s: ", mq.info[n].key); } else { fprintf(stdout, "%s: ", attr); } fprintf(stdout, "\n"); if (PMIX_STRING == mq.info[n].value.type) { ans = PMIx_Argv_split(mq.info[n].value.data.string, ','); for (m=0; NULL != ans[m]; m++) { if (NULL == (attr = pmix_attributes_reverse_lookup(ans[m]))) { fprintf(stdout, " %s\n", ans[m]); } else { fprintf(stdout, " %s\n", attr); } } PMIx_Argv_free(ans); } else { result = PMIx_Value_string(&mq.info[n].value); fprintf(stderr, " %s\n", (NULL == result) ? "NULL" : result); free(result); } } } done: PMIx_tool_finalize(); return (rc); } pmix-6.1.1~rc2/src/tools/pquery/Makefile.am0000664000175000017500000000371315203536752021011 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CFLAGS = \ -DPMIX_CONFIGURE_USER="\"@PMIX_CONFIGURE_USER@\"" \ -DPMIX_CONFIGURE_HOST="\"@PMIX_CONFIGURE_HOST@\"" \ -DPMIX_CONFIGURE_DATE="\"@PMIX_CONFIGURE_DATE@\"" \ -DPMIX_BUILD_USER="\"$$USER\"" \ -DPMIX_BUILD_HOST="\"$${HOSTNAME:-`(hostname || uname -n) | sed 1q`}\"" \ -DPMIX_BUILD_DATE="\"`$(top_srcdir)/config/getdate.sh`\"" \ -DPMIX_BUILD_CFLAGS="\"@CFLAGS@\"" \ -DPMIX_BUILD_CPPFLAGS="\"@CPPFLAGS@\"" \ -DPMIX_BUILD_LDFLAGS="\"@LDFLAGS@\"" \ -DPMIX_BUILD_LIBS="\"@LIBS@\"" \ -DPMIX_CC_ABSOLUTE="\"@PMIX_CC_ABSOLUTE@\"" \ -DPMIX_GREEK_VERSION="\"@PMIX_GREEK_VERSION@\"" \ -DPMIX_REPO_REV="\"@PMIX_REPO_REV@\"" \ -DPMIX_RELEASE_DATE="\"@PMIX_RELEASE_DATE@\"" if PMIX_INSTALL_BINARIES bin_PROGRAMS = pquery EXTRA_DIST = help-pquery.txt endif # PMIX_INSTALL_BINARIES pquery_SOURCES = pquery.c pquery_LDADD = \ $(top_builddir)/src/libpmix.la pmix-6.1.1~rc2/src/tools/plookup/0000775000175000017500000000000015203536752017115 5ustar alastairalastairpmix-6.1.1~rc2/src/tools/plookup/plookup.c0000664000175000017500000002244215203536752020756 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #define _GNU_SOURCE #include #include #include #include #include #include "include/pmix_tool.h" #include "src/mca/base/pmix_base.h" #include "src/mca/pinstalldirs/base/base.h" #include "src/runtime/pmix_rte.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_cmd_line.h" #include "src/util/pmix_keyval_parse.h" #include "src/util/pmix_show_help.h" typedef struct { pmix_lock_t lock; pmix_status_t status; } mylock_t; static pmix_proc_t myproc; /* this is the event notification function we pass down below * when registering for general events - i.e.,, the default * handler. We don't technically need to register one, but it * is usually good practice to catch any events that occur */ static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, info, ninfo, results, nresults); /* this example doesn't do anything with default events */ if (NULL != cbfunc) { cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } /* event handler registration is done asynchronously because it * may involve the PMIx server registering with the host RM for * external events. So we provide a callback function that returns * the status of the request (success or an error), plus a numerical index * to the registered event. The index is used later on to deregister * an event handler - if we don't explicitly deregister it, then the * PMIx server will do so when it see us exit */ static void evhandler_reg_callbk(pmix_status_t status, size_t evhandler_ref, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(evhandler_ref); if (PMIX_SUCCESS != status) { fprintf(stderr, "Client %s:%d EVENT HANDLER REGISTRATION FAILED WITH STATUS %d, ref=%lu\n", myproc.nspace, myproc.rank, status, (unsigned long) evhandler_ref); } lock->status = status; PMIX_WAKEUP_THREAD(&lock->lock); } #define PMIX_CLI_WAIT "wait" static struct option plkoptions[] = { PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_HELP, PMIX_ARG_OPTIONAL, 'h'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERSION, PMIX_ARG_NONE, 'V'), PMIX_OPTION_SHORT_DEFINE(PMIX_CLI_VERBOSE, PMIX_ARG_NONE, 'v'), PMIX_OPTION_DEFINE(PMIX_CLI_PMIXMCA, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_PID, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_TMPDIR, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_WAIT, PMIX_ARG_REQD), PMIX_OPTION_DEFINE(PMIX_CLI_TIMEOUT, PMIX_ARG_REQD), PMIX_OPTION_END }; static char *plkshorts = "h::vV"; int main(int argc, char **argv) { pmix_status_t rc; pmix_info_t *info = NULL; size_t ninfo = 0, n; mylock_t mylock; pmix_pdata_t *pdata = NULL; size_t ndata; int count, timeout; pmix_cli_result_t results; pmix_cli_item_t *opt; char *ans; PMIX_HIDE_UNUSED_PARAMS(argc); /* protect against problems if someone passes us thru a pipe * and then abnormally terminates the pipe early */ signal(SIGPIPE, SIG_IGN); /* init globals */ pmix_tool_basename = "plookup"; /* initialize the output system */ if (!pmix_output_init()) { return PMIX_ERROR; } /* initialize install dirs code */ rc = pmix_mca_base_framework_open(&pmix_pinstalldirs_base_framework, PMIX_MCA_BASE_OPEN_DEFAULT); if (PMIX_SUCCESS != rc) { fprintf(stderr, "pmix_pinstalldirs_base_open() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, rc); return rc; } if (PMIX_SUCCESS != (rc = pmix_pinstall_dirs_base_init(NULL, 0))) { fprintf(stderr, "pmix_pinstalldirs_base_init() failed -- process will likely abort (%s:%d, " "returned %d instead of PMIX_SUCCESS)\n", __FILE__, __LINE__, rc); return rc; } /* initialize the help system */ pmix_show_help_init(); /* keyval lex-based parser */ if (PMIX_SUCCESS != (rc = pmix_util_keyval_parse_init())) { fprintf(stderr, "pmix_util_keyval_parse_init failed with %d\n", rc); return PMIX_ERROR; } /* Setup the parameter system */ if (PMIX_SUCCESS != (rc = pmix_mca_base_var_init())) { fprintf(stderr, "pmix_mca_base_var_init failed with %d\n", rc); return PMIX_ERROR; } /* Parse the command line options */ PMIX_CONSTRUCT(&results, pmix_cli_result_t); rc = pmix_cmd_line_parse(argv, plkshorts, plkoptions, NULL, &results, "help-plookup.txt"); if (PMIX_SUCCESS != rc) { if (PMIX_ERR_SILENT != rc && PMIX_OPERATION_SUCCEEDED != rc) { fprintf(stderr, "%s: command line error (%s)\n", argv[0], PMIx_Error_string(rc)); } if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } exit(rc); } // handle relevant MCA params PMIX_LIST_FOREACH(opt, &results.instances, pmix_cli_item_t) { if (0 == strcmp(opt->key, PMIX_CLI_PMIXMCA)) { for (n=0; NULL != opt->values[n]; n++) { pmix_expose_param(opt->values[n]); } } } /* register params for pmix */ if (PMIX_SUCCESS != (rc = pmix_register_params())) { fprintf(stderr, "pmix_register_params failed with %d\n", rc); return PMIX_ERROR; } if (pmix_cmd_line_is_taken(&results, PMIX_CLI_WAIT)) { ++ninfo; if (pmix_cmd_line_is_taken(&results, PMIX_CLI_TIMEOUT)) { ++ninfo; } } /* determine how many keys were given */ count = PMIx_Argv_count(results.tail); if (0 == count) { /* must give us at least one key */ fprintf(stderr, "%s: Must provide at least one key to lookup\n", argv[0]); exit(1); } ndata = count; /* if we were given the pid of a starter, then direct that * we connect to it */ /* otherwise, use the system connection first, if available */ PMIX_INFO_CREATE(info, 1); PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_SYSTEM_FIRST, NULL, PMIX_BOOL); /* init as a tool */ if (PMIX_SUCCESS != (rc = PMIx_tool_init(&myproc, info, 1))) { fprintf(stderr, "PMIx_tool_init failed: %d\n", rc); exit(rc); } PMIX_INFO_FREE(info, 1); /* register a default event handler */ PMIX_CONSTRUCT_LOCK(&mylock.lock); PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, evhandler_reg_callbk, (void *) &mylock); PMIX_WAIT_THREAD(&mylock.lock); if (PMIX_SUCCESS != mylock.status) { fprintf(stderr, "PMIx_Register_event_handler returned bad status: %d\n", rc); PMIX_DESTRUCT_LOCK(&mylock.lock); goto done; } PMIX_DESTRUCT_LOCK(&mylock.lock); /* setup any info for the lookup */ if (0 < ninfo) { PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_WAIT, NULL, PMIX_BOOL); if (1 < ninfo) { opt = pmix_cmd_line_get_param(&results, PMIX_CLI_TIMEOUT); timeout = strtoul(opt->values[0], NULL, 10); PMIX_INFO_LOAD(&info[1], PMIX_TIMEOUT, &timeout, PMIX_INT); } } /* setup the keys */ PMIX_PDATA_CREATE(pdata, ndata); for (n = 0; n < ndata; n++) { pmix_strncpy(pdata[n].key, results.tail[n], PMIX_MAX_KEYLEN); } /* perform the lookup */ rc = PMIx_Lookup(pdata, ndata, info, ninfo); if (PMIX_SUCCESS != rc) { fprintf(stderr, "PMIx_Lookup failed: %s\n", PMIx_Error_string(rc)); goto done; } for (n = 0; n < ndata; n++) { fprintf(stderr, "Key: %s\n", pdata[n].key); ans = PMIx_Value_string(&pdata[n].value); fprintf(stderr, " %s\n", ans); free(ans); } PMIX_PDATA_FREE(pdata, ndata); done: PMIx_tool_finalize(); return (rc); } pmix-6.1.1~rc2/src/tools/plookup/help-plookup.txt0000664000175000017500000000435015203536752022277 0ustar alastairalastair# -*- text -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2012 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2017 Intel, Inc. All rights reserved. # Copyright (c) 2021-2026 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # This is the US/English help file for OpenPMIx lookup tool # [version] %s (%s) %s %s # [usage] %s (%s) %s Usage: %s [OPTION] ,,... PMIx Lookup tool /***** General Options *****/ -h|--help This help message -h|--help Help for the specified option -v|--verbose Enable typical debug options -V|--version Print version and exit --pmixmca Set MCA parameter value --pid PID of the daemon to which we should connect (int => PID or file: for file containing the PID --tmpdir Set the root for the session directory tree --timeout Max number of seconds to wait for data to become available --wait Wait for data to be available Report bugs to %s # [pmixmca] Pass a PMIx MCA parameter Syntax: "pmixmca ", where "key" is the parameter name and "value" is the parameter value. # [pid] PID of the daemon to which we should connect (int => PID or file: for file containing the PID # [tmpdir] Set the root for the session directory tree # [timeout] Max number of seconds to wait for data to become available # [wait] Wait for data to be available pmix-6.1.1~rc2/src/tools/plookup/Makefile.am0000664000175000017500000000372315203536752021156 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2014 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2017-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CFLAGS = \ -DPMIX_CONFIGURE_USER="\"@PMIX_CONFIGURE_USER@\"" \ -DPMIX_CONFIGURE_HOST="\"@PMIX_CONFIGURE_HOST@\"" \ -DPMIX_CONFIGURE_DATE="\"@PMIX_CONFIGURE_DATE@\"" \ -DPMIX_BUILD_USER="\"$$USER\"" \ -DPMIX_BUILD_HOST="\"$${HOSTNAME:-`(hostname || uname -n) | sed 1q`}\"" \ -DPMIX_BUILD_DATE="\"`$(top_srcdir)/config/getdate.sh`\"" \ -DPMIX_BUILD_CFLAGS="\"@CFLAGS@\"" \ -DPMIX_BUILD_CPPFLAGS="\"@CPPFLAGS@\"" \ -DPMIX_BUILD_LDFLAGS="\"@LDFLAGS@\"" \ -DPMIX_BUILD_LIBS="\"@LIBS@\"" \ -DPMIX_CC_ABSOLUTE="\"@PMIX_CC_ABSOLUTE@\"" \ -DPMIX_GREEK_VERSION="\"@PMIX_GREEK_VERSION@\"" \ -DPMIX_REPO_REV="\"@PMIX_REPO_REV@\"" \ -DPMIX_RELEASE_DATE="\"@PMIX_RELEASE_DATE@\"" if PMIX_INSTALL_BINARIES bin_PROGRAMS = plookup EXTRA_DIST = help-plookup.txt endif # PMIX_INSTALL_BINARIES plookup_SOURCES = plookup.c plookup_LDADD = \ $(top_builddir)/src/libpmix.la pmix-6.1.1~rc2/src/Makefile.am0000664000175000017500000000471515203536752016327 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2006-2020 Cisco Systems, Inc. All rights reserved # Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021 Amazon.com, Inc. or its affiliates. # All Rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # SUBDIRS = \ include \ class \ util/keyval \ util \ mca/base \ $(MCA_pmix_FRAMEWORKS_SUBDIRS) \ $(MCA_pmix_FRAMEWORK_COMPONENT_STATIC_SUBDIRS) \ . \ $(MCA_pmix_FRAMEWORK_COMPONENT_DSO_SUBDIRS) DIST_SUBDIRS = \ include \ class \ util/keyval \ util \ mca/base \ $(MCA_pmix_FRAMEWORKS_SUBDIRS) \ $(MCA_pmix_FRAMEWORK_COMPONENT_ALL_SUBDIRS) headers = sources = nodist_headers = EXTRA_DIST = nobase_pmix_HEADERS = pmixdir = $(pmixincludedir)/$(subdir) libpmix_la_LIBADD = \ mca/base/libpmix_mca_base.la \ class/libpmix_class.la \ util/libpmix_util.la \ $(MCA_pmix_FRAMEWORK_LIBS) libpmix_la_DEPENDENCIES = \ mca/base/libpmix_mca_base.la \ class/libpmix_class.la \ util/libpmix_util.la \ $(MCA_pmix_FRAMEWORK_LIBS) lib_LTLIBRARIES = libpmix.la libpmix_la_SOURCES = $(headers) $(sources) libpmix_la_LDFLAGS = -version-info $(libpmix_so_version) libpmix_la_LIBADD += \ include/libpmixglobal.la libpmix_la_DEPENDENCIES += \ include/libpmixglobal.la include threads/Makefile.include include event/Makefile.include include hwloc/Makefile.include include mca/Makefile.include include client/Makefile.include include server/Makefile.include include runtime/Makefile.include include tool/Makefile.include include tools/Makefile.include include common/Makefile.include nobase_pmix_HEADERS += $(headers) CLEANFILES = core.* *~ pmix-6.1.1~rc2/src/client/0000775000175000017500000000000015203536752015542 5ustar alastairalastairpmix-6.1.1~rc2/src/client/pmix_client_group.c0000664000175000017500000013577715203536752021461 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "src/include/pmix_globals.h" #include "src/mca/gds/base/base.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "src/class/pmix_list.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/gds/gds.h" #include "src/mca/ptl/ptl.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "src/server/pmix_server_ops.h" #include "src/client/pmix_client_ops.h" /* define a tracking object for group operations */ typedef struct { pmix_object_t super; pmix_lock_t lock; pmix_status_t status; size_t ref; size_t accepted; char *grpid; pmix_proc_t *members; size_t nmembers; pmix_info_t *info; size_t ninfo; pmix_info_t *results; size_t nresults; pmix_op_cbfunc_t opcbfunc; pmix_info_cbfunc_t cbfunc; void *cbdata; } pmix_group_tracker_t; static void gtcon(pmix_group_tracker_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); p->status = PMIX_SUCCESS; p->ref = SIZE_MAX; p->accepted = 0; p->grpid = NULL; p->members = NULL; p->nmembers = 0; p->info = NULL; p->ninfo = 0; p->results = NULL; p->nresults = 0; p->cbfunc = NULL; p->opcbfunc = NULL; p->cbdata = NULL; } static void gtdes(pmix_group_tracker_t *p) { PMIX_DESTRUCT_LOCK(&p->lock); if (NULL != p->members) { PMIX_PROC_FREE(p->members, p->nmembers); } if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->ninfo); } if (NULL != p->grpid) { free(p->grpid); p->grpid = NULL; } } PMIX_CLASS_INSTANCE(pmix_group_tracker_t, pmix_object_t, gtcon, gtdes); /* callback for wait completion */ static void construct_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static void destruct_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static void op_cbfunc(pmix_status_t status, void *cbdata); static void op_cbfunc_rel(pmix_status_t status, void *cbdata); static void info_cbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata); static pmix_status_t add_group(const char *grpid, size_t ctxid, pmix_proc_t *members, size_t nmembers); static pmix_status_t get_endpts(pmix_info_t *xfer, pmix_scope_t scope, bool *endpts) { pmix_cb_t cb2; bool found; pmix_kval_t *kv; void *ilist; pmix_status_t rc; pmix_data_array_t darray; PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = &pmix_globals.myid; cb2.scope = scope; cb2.copy = true; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); if (PMIX_SUCCESS == rc) { ilist = PMIx_Info_list_start(); // start with our procID PMIx_Info_list_add(ilist, PMIX_PROCID, &pmix_globals.myid, PMIX_PROC); // add the scope PMIx_Info_list_add(ilist, PMIX_DATA_SCOPE, &cb2.scope, PMIX_SCOPE); // now add the kvals found = false; PMIX_LIST_FOREACH (kv, &cb2.kvs, pmix_kval_t) { if (PMIx_Check_reserved_key(kv->key)) { continue; } PMIx_Info_list_add_value_unique(ilist, kv->key, kv->value, true); found = true; } if (found) { // convert to array rc = PMIx_Info_list_convert(ilist, &darray); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIx_Info_list_release(ilist); return rc; } // insert into a pmix_info_t for packing PMIX_INFO_LOAD(xfer, PMIX_PROC_DATA, &darray, PMIX_DATA_ARRAY); PMIX_DATA_ARRAY_DESTRUCT(&darray); *endpts = true; } PMIx_Info_list_release(ilist); } PMIX_DESTRUCT(&cb2); return PMIX_SUCCESS; } static pmix_status_t construct_msg(pmix_buffer_t *msg, const char *grp, const pmix_proc_t *procs, size_t nprocs, const pmix_info_t *info, size_t ninfo) { pmix_status_t rc; pmix_cmd_t cmd = PMIX_GROUP_CONSTRUCT_CMD; pmix_info_t local_endpts, *icopy, *iarray, *iptr; size_t sz, n, m, niarray; bool lclendpts; /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack the group ID */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &grp, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack the number of procs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nprocs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } if (0 < nprocs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, procs, nprocs, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } /* get our endpt info, if some was posted. We use * "remote" scope as all local procs have access * to info posted by all other local procs, regardless * of their namespace */ sz = ninfo; lclendpts = false; rc = get_endpts(&local_endpts, PMIX_REMOTE, &lclendpts); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } if (lclendpts) { sz = sz + 1; } PMIX_INFO_CREATE(icopy, sz); // check for group info for (n=0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_GROUP_INFO)) { iarray = (pmix_info_t*)info[n].value.data.darray->array; niarray = info[n].value.data.darray->size; // check if the first entry is our procID if (PMIX_PROC != iarray[0].value.type) { // we need to add our ID to the beginning of the array PMIX_INFO_CREATE(iptr, niarray+1); PMIX_INFO_LOAD(&iptr[0], PMIX_PROCID, &pmix_globals.myid, PMIX_PROC); for (m=0; m < niarray; m++) { PMIX_INFO_XFER(&iptr[m+1], &iarray[m]); } PMIx_Load_key(icopy[n].key, PMIX_GROUP_INFO); icopy[n].value.type = PMIX_DATA_ARRAY; icopy[n].value.data.darray = (pmix_data_array_t*)pmix_malloc(sizeof(pmix_data_array_t)); icopy[n].value.data.darray->type = PMIX_INFO; icopy[n].value.data.darray->array = iptr; icopy[n].value.data.darray->size = niarray + 1; } else { PMIX_INFO_XFER(&icopy[n], &info[n]); } } else { PMIX_INFO_XFER(&icopy[n], &info[n]); } } if (lclendpts) { // add the local endpt data PMIX_INFO_XFER(&icopy[n], &local_endpts); PMIX_INFO_DESTRUCT(&local_endpts); ++n; } /* pack the info structs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &sz, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_INFO_FREE(icopy, sz); return rc; } if (0 < sz) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, icopy, sz, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_INFO_FREE(icopy, sz); } return rc; } PMIX_EXPORT pmix_status_t PMIx_Group_construct(const char grp[], const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_info_t **results, size_t *nresults) { pmix_status_t rc; pmix_group_tracker_t *cb; pmix_output_verbose(2, pmix_client_globals.group_output, "pmix: group_construct called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_group_tracker_t); /* push the message into our event base to send to the server */ rc = PMIx_Group_construct_nb(grp, procs, nprocs, info, ninfo, info_cbfunc, cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cb); return rc; } /* wait for the group construct to complete */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; if (PMIX_SUCCESS == rc) { /* user takes responsibility for releasing any results */ *results = cb->results; *nresults = cb->nresults; cb->results = NULL; cb->nresults = 0; } PMIX_RELEASE(cb); return rc; } PMIX_EXPORT pmix_status_t PMIx_Group_construct_nb(const char grp[], const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_info_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg = NULL; pmix_status_t rc; pmix_group_tracker_t *cb = NULL; pmix_output_verbose(2, pmix_client_globals.group_output, "pmix:group_construct_nb called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } // send any data to our server msg = PMIX_NEW(pmix_buffer_t); rc = construct_msg(msg, grp, procs, nprocs, info, ninfo); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_group_tracker_t); cb->cbfunc = cbfunc; cb->cbdata = cbdata; cb->grpid = strdup(grp); /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, construct_cbfunc, (void*)cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cb); PMIX_RELEASE(msg); } return rc; } PMIX_EXPORT pmix_status_t PMIx_Group_destruct(const char grp[], const pmix_info_t info[], size_t ninfo) { pmix_status_t rc; pmix_group_tracker_t cb; pmix_output_verbose(2, pmix_client_globals.group_output, "pmix: group_destruct called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ PMIX_CONSTRUCT(&cb, pmix_group_tracker_t); /* use the non-blocking version */ if (PMIX_SUCCESS != (rc = PMIx_Group_destruct_nb(grp, info, ninfo, op_cbfunc, (void *) &cb))) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* wait for the destruct to complete */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; PMIX_DESTRUCT(&cb); pmix_output_verbose(2, pmix_client_globals.group_output, "pmix: group destruct completed"); return rc; } PMIX_EXPORT pmix_status_t PMIx_Group_destruct_nb(const char grpid[], const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg = NULL; pmix_cmd_t cmd = PMIX_GROUP_DESTRUCT_CMD; pmix_status_t rc; pmix_group_tracker_t *cb = NULL; pmix_group_t *grp, *pgrp; pmix_output_verbose(2, pmix_client_globals.group_output, "pmix:group_destruct_nb called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* check for bozo input */ if (NULL == grpid) { return PMIX_ERR_BAD_PARAM; } /* find this group */ grp = NULL; PMIX_LIST_FOREACH(pgrp, &pmix_client_globals.groups, pmix_group_t) { if (0 == strcmp(grpid, pgrp->grpid)) { grp = pgrp; break; } } if (NULL == grp) { return PMIX_ERR_NOT_FOUND; } msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto done; } /* pack the group ID */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &grpid, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto done; } /* pack the membership - the server isn't storing it, * so we have to send it so that the server can * track when all local procs have participated */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &grp->nmbrs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto done; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, grp->members, grp->nmbrs, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto done; } /* pack the info structs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto done; } if (0 < ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto done; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_group_tracker_t); cb->opcbfunc = cbfunc; cb->cbdata = cbdata; cb->grpid = strdup(grpid); /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, destruct_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cb); } done: if (PMIX_SUCCESS != rc && NULL != msg) { PMIX_RELEASE(msg); } return rc; } static void chaincbfunc(pmix_status_t status, void *cbdata) { pmix_group_tracker_t *cb = (pmix_group_tracker_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); if (NULL != cb) { PMIX_RELEASE(cb); } } static void relcbfunc(void *cbdata) { pmix_group_tracker_t *cb = (pmix_group_tracker_t *) cbdata; PMIX_RELEASE(cb); } static void invite_handler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t *results, size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { pmix_group_tracker_t *cb = NULL; pmix_proc_t *affected = NULL; size_t n; pmix_status_t rc = PMIX_GROUP_INVITE_DECLINED; size_t contextid; bool gotctxid = false; PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, results, nresults); /* find the object we asked to be returned with event */ for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_EVENT_RETURN_OBJECT)) { if (PMIX_POINTER != info[n].value.type) { /* this is an unrecoverable error - need to abort */ } cb = (pmix_group_tracker_t *) info[n].value.data.ptr; } else if (PMIX_CHECK_KEY(&info[n], PMIX_EVENT_AFFECTED_PROC)) { if (PMIX_PROC != info[n].value.type) { /* this is an unrecoverable error - need to abort */ } affected = info[n].value.data.proc; } else if (PMIX_CHECK_KEY(&info[n], PMIX_GROUP_CONTEXT_ID)) { rc = PMIx_Value_get_number(&info[n].value, &contextid, PMIX_SIZE); gotctxid = true; } } if (NULL == cb) { pmix_output(0, "%s: INVITE HANDLER NULL OBJECT", PMIX_NAME_PRINT(&pmix_globals.myid)); /* this is an unrecoverable error - need to abort */ /* always must continue the chain */ cbfunc(rc, NULL, 0, chaincbfunc, NULL, cbdata); return; } /* if the status is accepted, then record it */ if (PMIX_GROUP_INVITE_ACCEPTED == status) { cb->accepted++; /* allow the chain to continue */ rc = PMIX_SUCCESS; goto complete; } /* if the reporting process terminated, then issue the corresponding * group event - it only goes to this process */ if (PMIX_PROC_TERMINATED == status) { if (gotctxid) { cb->ninfo = 2; } else { cb->ninfo = 1; } PMIX_INFO_CREATE(cb->info, cb->ninfo); PMIX_INFO_LOAD(&cb->info[0], PMIX_EVENT_AFFECTED_PROC, affected, PMIX_PROC); if (gotctxid) { PMIX_INFO_LOAD(&cb->info[1], PMIX_GROUP_CONTEXT_ID, &contextid, PMIX_SIZE); } rc = PMIx_Notify_event(PMIX_GROUP_INVITE_FAILED, &pmix_globals.myid, PMIX_RANGE_PROC_LOCAL, cb->info, cb->ninfo, chaincbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { /* this is an unrecoverable error - need to abort */ pmix_output(0, "%s: INVITE HANDLER ERROR", PMIX_NAME_PRINT(&pmix_globals.myid)); } PMIX_INFO_FREE(cb->info, cb->ninfo); goto complete; } /* otherwise, we consider the process as having "declined" and * ignore it here - if the user registered a handler for that * case, then the chain will eventually call it */ complete: /* check for complete */ if (cb->accepted == cb->nmembers) { /* execute the completion callback */ if (NULL != cb->cbfunc) { cb->cbfunc(PMIX_SUCCESS, info, ninfo, cb->cbdata, relcbfunc, cb->cbdata); } } /* always must continue the chain */ cbfunc(PMIX_EVENT_ACTION_COMPLETE, cb->results, cb->nresults, NULL, NULL, cbdata); return; } static void regcbfunc(pmix_status_t status, size_t refid, void *cbdata) { pmix_group_tracker_t *cb = (pmix_group_tracker_t *) cbdata; cb->status = status; cb->ref = refid; PMIX_WAKEUP_THREAD(&cb->lock); } PMIX_EXPORT pmix_status_t PMIx_Group_invite(const char grp[], const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_info_t **results, size_t *nresults) { pmix_group_tracker_t *cb; pmix_status_t rc; size_t n; pmix_data_array_t darray; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, then we cannot notify */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* check for bozo input */ if (NULL == grp || NULL == procs) { return PMIX_ERR_BAD_PARAM; } cb = PMIX_NEW(pmix_group_tracker_t); /* we have to bump the reference count of this object * because the invite_nb function involves a release * and we need the object after the invite completes */ PMIX_RETAIN(cb); rc = PMIx_Group_invite_nb(grp, procs, nprocs, info, ninfo, info_cbfunc, (void *)cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cb); return rc; } /* wait for the group construction to complete or fail */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; *results = cb->results; *nresults = cb->nresults; cb->results = NULL; cb->nresults = 0; PMIX_RELEASE(cb); /* announce group completion, including list of final * members - only sent to members. Servers will intercept * and update their membership lists */ cb = PMIX_NEW(pmix_group_tracker_t); cb->ninfo = 4; PMIX_INFO_CREATE(cb->info, cb->ninfo); if (NULL == cb->info) { PMIX_RELEASE(cb); return PMIX_ERR_NOMEM; } n = 0; darray.type = PMIX_PROC; darray.array = (pmix_proc_t*)procs; darray.size = nprocs; // load the custom range PMIX_INFO_LOAD(&cb->info[n], PMIX_EVENT_CUSTOM_RANGE, &darray, PMIX_DATA_ARRAY); ++n; // provide final group membership PMIX_INFO_LOAD(&cb->info[n], PMIX_GROUP_MEMBERSHIP, &darray, PMIX_DATA_ARRAY); ++n; /* mark that this only goes to non-default handlers */ PMIX_INFO_LOAD(&cb->info[n], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); ++n; /* provide the group ID */ PMIX_INFO_LOAD(&cb->info[n], PMIX_GROUP_ID, grp, PMIX_STRING); /* notify members */ rc = PMIx_Notify_event(PMIX_GROUP_CONSTRUCT_COMPLETE, &pmix_globals.myid, PMIX_RANGE_CUSTOM, cb->info, cb->ninfo, op_cbfunc, (void *)cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cb); return rc; } /* wait for the notify to get out */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; PMIX_RELEASE(cb); return rc; } PMIX_EXPORT pmix_status_t PMIx_Group_invite_nb(const char grp[], const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_info_cbfunc_t cbfunc, void *cbdata) { pmix_group_tracker_t *cb; pmix_group_tracker_t lock; pmix_status_t codes[] = { PMIX_GROUP_INVITE_ACCEPTED, PMIX_GROUP_INVITE_DECLINED, PMIX_PROC_TERMINATED }; size_t ncodes, n; pmix_info_t myinfo[2]; pmix_status_t rc; pmix_cb_t cb2; pmix_info_t optional; pmix_kval_t *kv; uint32_t jsize; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, then we cannot notify */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* check for bozo input */ if (NULL == grp || NULL == procs) { return PMIX_ERR_BAD_PARAM; } cb = PMIX_NEW(pmix_group_tracker_t); if (NULL == cb) { return PMIX_ERR_NOMEM; } cb->cbfunc = cbfunc; cb->cbdata = cbdata; cb->accepted = 1; // obviously, we accept /* compute the number of proposed members */ for (n = 0; n < nprocs; n++) { if (PMIX_RANK_WILDCARD == procs[n].rank) { /* must get the number of procs in this nspace */ PMIX_CONSTRUCT(&cb2, pmix_cb_t); PMIX_INFO_LOAD(&optional, PMIX_OPTIONAL, NULL, PMIX_BOOL); cb2.proc = (pmix_proc_t*)&procs[n]; cb2.key = PMIX_JOB_SIZE; cb2.info = &optional; cb2.ninfo = 1; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs); PMIX_DESTRUCT(&cb2); if (NULL != kv) { // should never be NULL rc = PMIx_Value_get_number(kv->value, &jsize, PMIX_UINT32); PMIX_RELEASE(kv); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cb); PMIX_DESTRUCT(&cb2); return PMIX_ERR_BAD_PARAM; } cb->nmembers += jsize; } } else { PMIX_RELEASE(cb); PMIX_DESTRUCT(&cb2); return PMIX_ERR_BAD_PARAM; } } else { cb->nmembers++; } } /* register an event handler specifically to respond * to accept responses */ PMIX_INFO_LOAD(&myinfo[0], PMIX_EVENT_RETURN_OBJECT, cb, PMIX_POINTER); PMIX_INFO_LOAD(&myinfo[1], PMIX_EVENT_HDLR_PREPEND, NULL, PMIX_BOOL); ncodes = sizeof(codes) / sizeof(pmix_status_t); PMIX_CONSTRUCT(&lock, pmix_group_tracker_t); PMIx_Register_event_handler(codes, ncodes, myinfo, 2, invite_handler, regcbfunc, &lock); PMIX_WAIT_THREAD(&lock.lock); rc = lock.status; cb->ref = lock.ref; PMIX_DESTRUCT(&lock); PMIX_INFO_DESTRUCT(&myinfo[0]); PMIX_INFO_DESTRUCT(&myinfo[1]); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cb); return rc; } /* check for directives */ if (NULL != info) { for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_TIMEOUT)) { /* setup a timer */ break; } } } /* limit the range to just the procs we are inviting */ PMIX_INFO_CREATE(cb->info, 3); if (NULL == cb->info) { PMIX_CONSTRUCT(&lock, pmix_group_tracker_t); PMIx_Deregister_event_handler(cb->ref, op_cbfunc, &lock); PMIX_WAIT_THREAD(&lock.lock); PMIX_DESTRUCT(&lock); PMIX_RELEASE(cb); return PMIX_ERR_NOMEM; } cb->ninfo = 3; n = 0; (void) strncpy(cb->info[n].key, PMIX_EVENT_CUSTOM_RANGE, PMIX_MAX_KEYLEN); cb->info[n].value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(cb->info[n].value.data.darray, nprocs, PMIX_PROC); if (NULL == cb->info[n].value.data.darray || NULL == cb->info[n].value.data.darray->array) { PMIX_CONSTRUCT(&lock, pmix_group_tracker_t); PMIx_Deregister_event_handler(cb->ref, op_cbfunc, &lock); PMIX_WAIT_THREAD(&lock.lock); PMIX_DESTRUCT(&lock); PMIX_RELEASE(cb); return PMIX_ERR_NOMEM; } memcpy(cb->info[n].value.data.darray->array, procs, nprocs * sizeof(pmix_proc_t)); ++n; /* mark that this only goes to non-default handlers */ PMIX_INFO_LOAD(&cb->info[n], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); ++n; /* provide the group ID */ PMIX_INFO_LOAD(&cb->info[n], PMIX_GROUP_ID, grp, PMIX_STRING); /* notify everyone of the invitation */ PMIX_CONSTRUCT(&lock, pmix_group_tracker_t); rc = PMIx_Notify_event(PMIX_GROUP_INVITED, &pmix_globals.myid, PMIX_RANGE_CUSTOM, cb->info, cb->ninfo, op_cbfunc, (void *) &lock); PMIX_WAIT_THREAD(&lock.lock); rc = lock.status; PMIX_DESTRUCT(&lock); if (PMIX_SUCCESS != rc) { PMIX_CONSTRUCT(&lock, pmix_group_tracker_t); PMIx_Deregister_event_handler(cb->ref, op_cbfunc, &lock); PMIX_WAIT_THREAD(&lock.lock); PMIX_DESTRUCT(&lock); PMIX_RELEASE(cb); } return rc; } PMIX_EXPORT pmix_status_t PMIx_Group_join(const char grp[], const pmix_proc_t *leader, pmix_group_opt_t opt, const pmix_info_t info[], size_t ninfo, pmix_info_t **results, size_t *nresults) { pmix_status_t rc; pmix_group_tracker_t *cb; PMIX_HIDE_UNUSED_PARAMS(results, nresults); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object as we need to pass it to the * recv routine so we know which lock to release when * the return message is recvd */ cb = PMIX_NEW(pmix_group_tracker_t); rc = PMIx_Group_join_nb(grp, leader, opt, info, ninfo, info_cbfunc, cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cb); return rc; } /* wait for the group construction to complete */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; PMIX_RELEASE(cb); pmix_output_verbose(2, pmix_client_globals.group_output, "pmix: group construction completed"); return rc; } PMIX_EXPORT pmix_status_t PMIx_Group_join_nb(const char grp[], const pmix_proc_t *leader, pmix_group_opt_t opt, const pmix_info_t info[], size_t ninfo, pmix_info_cbfunc_t cbfunc, void *cbdata) { pmix_status_t rc; pmix_group_tracker_t *cb; pmix_status_t code; size_t n; pmix_data_range_t range; PMIX_HIDE_UNUSED_PARAMS(grp, cbfunc); pmix_output_verbose(2, pmix_client_globals.group_output, "[%s:%d] pmix: join nb called", pmix_globals.myid.nspace, pmix_globals.myid.rank); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, then we cannot notify */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object as we need to pass it to the * recv routine so we know which lock to release when * the notification is done */ cb = PMIX_NEW(pmix_group_tracker_t); cb->cbfunc = cbfunc; cb->cbdata = cbdata; /* check for directives */ if (NULL != info) { for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_TIMEOUT)) { /* setup a timer */ break; } } } /* set the code according to their request */ if (PMIX_GROUP_ACCEPT == opt) { code = PMIX_GROUP_INVITE_ACCEPTED; } else { code = PMIX_GROUP_INVITE_DECLINED; } /* only notify the leader so we don't hit all procs */ if (NULL != leader) { range = PMIX_RANGE_CUSTOM; PMIX_INFO_CREATE(cb->info, 1); if (NULL == cb->info) { PMIX_RELEASE(cb); return PMIX_ERR_NOMEM; } PMIX_INFO_LOAD(&cb->info[0], PMIX_EVENT_CUSTOM_RANGE, leader, PMIX_PROC); cb->ninfo = 1; } else { range = PMIX_RANGE_SESSION; } rc = PMIx_Notify_event(code, &pmix_globals.myid, range, cb->info, cb->ninfo, op_cbfunc_rel, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cb); } pmix_output_verbose(2, pmix_client_globals.group_output, "[%s:%d] pmix: group invite %s", pmix_globals.myid.nspace, pmix_globals.myid.rank, (PMIX_GROUP_INVITE_ACCEPTED == code) ? "ACCEPTED" : "DECLINED"); return rc; } PMIX_EXPORT pmix_status_t PMIx_Group_leave(const char grp[], const pmix_info_t info[], size_t ninfo) { pmix_status_t rc; pmix_group_tracker_t cb; pmix_output_verbose(2, pmix_client_globals.group_output, "pmix: group_leave called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ PMIX_CONSTRUCT(&cb, pmix_group_tracker_t); /* push the message into our event base to send to the server */ if (PMIX_SUCCESS != (rc = PMIx_Group_leave_nb(grp, info, ninfo, op_cbfunc, (void *) &cb))) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb); return rc; } /* wait for the operation to complete */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; PMIX_DESTRUCT(&cb); pmix_output_verbose(2, pmix_client_globals.group_output, "pmix: group leave completed"); return rc; } PMIX_EXPORT pmix_status_t PMIx_Group_leave_nb(const char grp[], const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg = NULL; pmix_cmd_t cmd = PMIX_GROUP_LEAVE_CMD; pmix_status_t rc; pmix_group_tracker_t *cb = NULL; pmix_output_verbose(2, pmix_client_globals.group_output, "pmix:group_leave_nb called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* check for bozo input */ if (NULL == grp) { return PMIX_ERR_BAD_PARAM; } msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto done; } /* pack the group ID */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &grp, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto done; } /* pack the info structs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto done; } if (0 < ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); goto done; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_group_tracker_t); cb->opcbfunc = cbfunc; cb->cbdata = cbdata; /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, destruct_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cb); } done: if (PMIX_SUCCESS != rc && NULL != msg) { PMIX_RELEASE(msg); } return rc; } static void op_cbfunc(pmix_status_t status, void *cbdata) { pmix_group_tracker_t *cb = (pmix_group_tracker_t *) cbdata; cb->status = status; if (NULL != cb->cbfunc) { cb->cbfunc(status, cb->info, cb->ninfo, cb->cbdata, NULL, NULL); } PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } static void relfn(void *cbdata) { pmix_group_tracker_t *cb = (pmix_group_tracker_t *) cbdata; PMIX_RELEASE(cb); } static void op_cbfunc_rel(pmix_status_t status, void *cbdata) { pmix_group_tracker_t *cb = (pmix_group_tracker_t *) cbdata; cb->status = status; if (NULL != cb->cbfunc) { cb->cbfunc(status, cb->info, cb->ninfo, cb->cbdata, relfn, cb); } else { PMIX_RELEASE(cb); } } static void construct_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_group_tracker_t *cb = (pmix_group_tracker_t *) cbdata; pmix_status_t rc; pmix_status_t ret; int32_t cnt; size_t ctxid = SIZE_MAX; bool gotctxid = false; pmix_proc_t *members = NULL; size_t nmembers = 0; size_t ngrpinfo = 0; size_t n, m, ninfo, npinfo; pmix_info_t grpinfo, *iptr, *pinfo; pmix_data_array_t darray; void *ilist; PMIX_HIDE_UNUSED_PARAMS(pr, hdr); pmix_output_verbose(2, pmix_client_globals.group_output, "%s pmix:client construct callback activated with %d bytes", PMIX_NAME_PRINT(&pmix_globals.myid), (NULL == buf) ? -1 : (int) buf->bytes_used); if (NULL == buf) { ret = PMIX_ERR_BAD_PARAM; goto report; } /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { ret = PMIX_ERR_UNREACH; goto report; } /* unpack the returned status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; } if (PMIX_SUCCESS != ret) { goto report; } /* unpack the final membership */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &nmembers, &cnt, PMIX_SIZE); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { goto report; } else if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; goto report; } if (0 < nmembers) { PMIX_PROC_CREATE(members, nmembers); cnt = nmembers; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, members, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; goto report; } } /* unpack any ctxid that was provided */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &gotctxid, &cnt, PMIX_BOOL); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { goto report; } else if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; goto report; } if (gotctxid) { cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ctxid, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; goto report; } } // unpack any group info that was provided cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ngrpinfo, &cnt, PMIX_SIZE); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { goto report; } else if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; goto report; } if (0 < ngrpinfo && gotctxid) { for (n=0; n < ngrpinfo; n++) { PMIX_INFO_CONSTRUCT(&grpinfo); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &grpinfo, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; PMIX_INFO_DESTRUCT(&grpinfo); goto report; } // store the info locally iptr = (pmix_info_t*)grpinfo.value.data.darray->array; ninfo = grpinfo.value.data.darray->size; if (PMIX_CHECK_KEY(&grpinfo, PMIX_GROUP_INFO)) { // this is just a single array of group info rc = pmix_server_process_grpinfo(ctxid, iptr, ninfo); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; PMIX_INFO_DESTRUCT(&grpinfo); goto report; } } else { // contains an array of group info arrays for (m=0; m < ninfo; m++) { pinfo = (pmix_info_t*)iptr[m].value.data.darray->array; npinfo = iptr[m].value.data.darray->size; rc = pmix_server_process_grpinfo(ctxid, pinfo, npinfo); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; PMIX_INFO_DESTRUCT(&grpinfo); goto report; } } } PMIX_INFO_DESTRUCT(&grpinfo); } } report: ilist = PMIx_Info_list_start(); rc = PMIx_Info_list_add(ilist, PMIX_GROUP_ID, cb->grpid, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); goto done; } if (NULL != members) { darray.array = members; darray.size = nmembers; darray.type = PMIX_PROC; rc = PMIx_Info_list_add(ilist, PMIX_GROUP_MEMBERSHIP, &darray, PMIX_DATA_ARRAY); // data was copied into the info if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); goto done; } } if (gotctxid) { rc = PMIx_Info_list_add(ilist, PMIX_GROUP_CONTEXT_ID, &ctxid, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(ilist); goto done; } } PMIx_Info_list_convert(ilist, &darray); cb->info = (pmix_info_t*)darray.array; cb->ninfo = darray.size; PMIx_Info_list_release(ilist); done: if (NULL != members) { PMIX_PROC_FREE(members, nmembers); } if (NULL != cb->cbfunc) { cb->cbfunc(ret, cb->info, cb->ninfo, cb->cbdata, relfn, cb); return; } PMIX_RELEASE(cb); } static void destruct_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_group_tracker_t *cb = (pmix_group_tracker_t *) cbdata; pmix_status_t rc; pmix_status_t ret; int32_t cnt; pmix_group_t *grp; PMIX_HIDE_UNUSED_PARAMS(pr, hdr); pmix_output_verbose(2, pmix_client_globals.group_output, "pmix:client recv callback activated with %d bytes", (NULL == buf) ? -1 : (int) buf->bytes_used); if (NULL == buf) { ret = PMIX_ERR_BAD_PARAM; PMIX_ERROR_LOG(ret); goto report; } /* find this group */ grp = NULL; PMIX_LIST_FOREACH(grp, &pmix_client_globals.groups, pmix_group_t) { if (0 == strcmp(cb->grpid, grp->grpid)) { pmix_list_remove_item(&pmix_client_globals.groups, &grp->super); PMIX_RELEASE(grp); break; } } /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { ret = PMIX_ERR_UNREACH; goto report; } /* unpack the returned status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; } report: if (NULL != cb->opcbfunc) { cb->opcbfunc(ret, cb->cbdata); } PMIX_RELEASE(cb); } static void info_cbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_group_tracker_t *cb = (pmix_group_tracker_t *) cbdata; size_t n, nmembers = 0; pmix_proc_t *members = NULL; char *grpid = NULL; size_t ctxid = SIZE_MAX; pmix_status_t rc; /* see if anything was returned - e.g., a context id */ cb->status = status; /* copy/save any returned info */ if (NULL != info) { cb->nresults = ninfo; PMIX_INFO_CREATE(cb->results, cb->nresults); for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_GROUP_MEMBERSHIP)) { members = (pmix_proc_t*)info[n].value.data.darray->array; nmembers = info[n].value.data.darray->size; } else if (PMIX_CHECK_KEY(&info[n], PMIX_GROUP_ID)) { grpid = info[n].value.data.string; } else if (PMIX_CHECK_KEY(&info[n], PMIX_GROUP_CONTEXT_ID)) { rc = PMIx_Value_get_number(&info[n].value, &ctxid, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } PMIX_INFO_XFER(&cb->results[n], &info[n]); } } if (NULL != members && NULL != grpid) { add_group(grpid, ctxid, members, nmembers); } if (NULL != release_fn) { release_fn(release_cbdata); } PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } static pmix_status_t add_group(const char *grpid, size_t ctxid, pmix_proc_t *members, size_t nmembers) { pmix_group_t *grp; /* since the group construction has finished, we can add * the group to out list of groups. Always sort the * the array to maintain the same view across participants.*/ grp = PMIX_NEW(pmix_group_t); PMIX_PROC_CREATE(grp->members, nmembers); memcpy(grp->members, members, nmembers * sizeof(pmix_proc_t)); qsort(grp->members, nmembers, sizeof(pmix_proc_t), pmix_util_compare_proc); grp->nmbrs = nmembers; grp->grpid = strdup(grpid); grp->ctxid = ctxid; pmix_list_append(&pmix_client_globals.groups, &grp->super); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/client/pmix_client_topology.c0000664000175000017500000002564215203536752022166 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "src/client/pmix_client_ops.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_error.h" static void _loadtp(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); cb->pstatus = pmix_hwloc_load_topology(cb->topo); PMIX_WAKEUP_THREAD(&cb->lock); } PMIX_EXPORT pmix_status_t PMIx_Load_topology(pmix_topology_t *topo) { pmix_status_t rc; pmix_cb_t cb; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.topo = topo; PMIX_THREADSHIFT(&cb, _loadtp); /* wait for the result */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.pstatus; PMIX_DESTRUCT(&cb); return rc; } PMIX_EXPORT pmix_status_t PMIx_Parse_cpuset_string(const char *cpuset_string, pmix_cpuset_t *cpuset) { pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } rc = pmix_hwloc_parse_cpuset_string(cpuset_string, cpuset); return rc; } PMIX_EXPORT pmix_status_t PMIx_Get_cpuset(pmix_cpuset_t *cpuset, pmix_bind_envelope_t ref) { pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } rc = pmix_hwloc_get_cpuset(cpuset, ref); return rc; } PMIX_EXPORT pmix_status_t PMIx_Get_relative_locality(const char *locality1, const char *locality2, pmix_locality_t *locality) { pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } rc = pmix_hwloc_get_relative_locality(locality1, locality2, locality); return rc; } static void icbrelfn(void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; PMIX_RELEASE(cb); } static void distcb(pmix_status_t status, pmix_device_distance_t *dist, size_t ndist, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; size_t n; cb->status = status; cb->nvals = ndist; if (PMIX_SUCCESS == status && 0 < ndist) { PMIX_DEVICE_DIST_CREATE(cb->dist, cb->nvals); for (n = 0; n < cb->nvals; n++) { if (NULL != dist[n].uuid) { cb->dist[n].uuid = strdup(dist[n].uuid); } if (NULL != dist[n].osname) { cb->dist[n].osname = strdup(dist[n].osname); } cb->dist[n].type = dist[n].type; cb->dist[n].mindist = dist[n].mindist; cb->dist[n].maxdist = dist[n].maxdist; } } if (NULL != release_fn) { release_fn(release_cbdata); } /* release the caller */ PMIX_WAKEUP_THREAD(&cb->lock); } pmix_status_t PMIx_Compute_distances(pmix_topology_t *topo, pmix_cpuset_t *cpuset, pmix_info_t info[], size_t ninfo, pmix_device_distance_t *distances[], size_t *ndist) { pmix_cb_t cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_globals.debug_output, "pmix:compute_distances"); *distances = NULL; *ndist = 0; /* create a callback object so we can be notified when * the non-blocking operation is complete */ PMIX_CONSTRUCT(&cb, pmix_cb_t); rc = PMIx_Compute_distances_nb(topo, cpuset, info, ninfo, distcb, &cb); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT(&cb); return rc; } /* wait for the data to return */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; /* xfer the results */ if (NULL != cb.dist) { *distances = cb.dist; *ndist = cb.nvals; cb.dist = NULL; cb.nvals = 0; } PMIX_DESTRUCT(&cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:compute_distances completed"); return rc; } static void dcbfunc(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (NULL != cb->cbfunc.distfn) { cb->cbfunc.distfn(cb->status, cb->dist, cb->nvals, cb->cbdata, icbrelfn, cb); return; } PMIX_RELEASE(cb); } static void direcv(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_status_t rc; int cnt; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:compute_dist recv from server with %d bytes", (int) buf->bytes_used); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { rc = PMIX_ERR_UNREACH; goto complete; } /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cb->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS != cb->status) { rc = cb->status; goto complete; } /* unpack any returned data */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cb->nvals, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < cb->nvals) { PMIX_DEVICE_DIST_CREATE(cb->dist, cb->nvals); cnt = cb->nvals; PMIX_BFROPS_UNPACK(rc, peer, buf, cb->dist, &cnt, PMIX_DEVICE_DIST); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } complete: pmix_output_verbose(2, pmix_globals.debug_output, "pmix:compute_dist recv from server releasing"); /* release the caller */ cb->cbfunc.distfn(rc, cb->dist, cb->nvals, cb->cbdata, icbrelfn, (void *) cb); } pmix_status_t PMIx_Compute_distances_nb(pmix_topology_t *tp, pmix_cpuset_t *cp, pmix_info_t info[], size_t ninfo, pmix_device_dist_cbfunc_t cbfunc, void *cbdata) { pmix_cb_t *cb; pmix_status_t rc; pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_COMPUTE_DEVICE_DISTANCES_CMD; pmix_topology_t *topo = NULL; pmix_cpuset_t *cpuset = NULL; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } cb = PMIX_NEW(pmix_cb_t); cb->cbfunc.distfn = cbfunc; cb->cbdata = cbdata; /* if the topology is NULL, then use ours */ if (NULL == tp) { if (NULL == pmix_globals.topology.topology) { /* if our topology is NULL, try to get it */ rc = pmix_hwloc_load_topology(&pmix_globals.topology); if (PMIX_SUCCESS != rc) { /* try to ask our server if they can do it */ goto request; } } topo = &pmix_globals.topology; } else { topo = tp; } /* same for cpuset */ if (NULL == cp) { /* if our cpuset is NULL, it could be we are unbound or * that we haven't yet gotten our cpuset. Try to get it. */ if (NULL == pmix_globals.cpuset.bitmap) { rc = pmix_hwloc_get_cpuset(&pmix_globals.cpuset, PMIX_CPUBIND_PROCESS); if (PMIX_SUCCESS != rc) { /* try to ask our server if they can do it */ goto request; } } cpuset = &pmix_globals.cpuset; } else { cpuset = cp; } /* see if I can support this myself */ cb->status = pmix_hwloc_compute_distances(topo, cpuset, info, ninfo, &cb->dist, &cb->nvals); if (PMIX_SUCCESS == cb->status) { /* threadshift to return the result */ PMIX_THREADSHIFT(cb, dcbfunc); return PMIX_SUCCESS; } request: /* if I am a server (but not a tool) or I am not connected, there is nothing more I can do */ if ((PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) || !pmix_atomic_check_bool(&pmix_globals.connected)) { PMIX_RELEASE(cb); return PMIX_ERR_UNREACH; } /* don't send our topology if it's local */ if (topo == &pmix_globals.topology) { topo = NULL; } /* if we are a tool or client, then relay this request to the server */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cb); return rc; } /* pack the topology we want them to use */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, topo, 1, PMIX_TOPO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cb); return rc; } /* pack the cpuset */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cpuset, 1, PMIX_PROC_CPUSET); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cb); return rc; } /* pack the directives */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cb); return rc; } if (0 < ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cb); return rc; } } /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, direcv, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } return rc; } pmix-6.1.1~rc2/src/client/pmix_client_resolve.c0000664000175000017500000007246615203536752021777 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "src/include/pmix_globals.h" #include "src/mca/gds/base/base.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "src/class/pmix_list.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/gds/gds.h" #include "src/mca/ptl/base/base.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/client/pmix_client_ops.h" #include "src/server/pmix_server_ops.h" /* local object definition */ typedef struct { pmix_object_t super; pmix_event_t ev; pmix_lock_t lock; pmix_status_t status; char *nodename; pmix_nspace_t nspace; pmix_proc_t *procs; size_t nprocs; char *nodelist; } pmix_resolve_caddy_t; static void rcon(pmix_resolve_caddy_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); p->nodename = NULL; PMIX_LOAD_NSPACE(p->nspace, NULL); p->procs = NULL; p->nprocs = 0; p->nodelist = NULL; } static void rdes(pmix_resolve_caddy_t *p) { PMIX_DESTRUCT_LOCK(&p->lock); if (NULL != p->procs) { PMIX_PROC_FREE(p->procs, p->nprocs); } if (NULL != p->nodelist) { free(p->nodelist); } } static PMIX_CLASS_INSTANCE(pmix_resolve_caddy_t, pmix_object_t, rcon, rdes); /* callback for wait completion */ static void wait_peers_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static void wait_node_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static pmix_status_t try_fetch(pmix_cb_t *cb) { pmix_status_t rc; // first try the client's store PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, cb); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { return PMIX_SUCCESS; } if (!PMIX_GDS_CHECK_COMPONENT(pmix_client_globals.myserver, "hash")) { // try again with our hash store PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, cb); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { return PMIX_SUCCESS; } } // if the namespace isn't known, then abort if (PMIX_ERR_INVALID_NAMESPACE == rc) { return rc; } if (PMIX_RANK_UNDEF != cb->proc->rank) { return PMIX_ERR_NOT_FOUND; } // try again with wildcard cb->proc->rank = PMIX_RANK_WILDCARD; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, cb); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { return PMIX_SUCCESS; } if (!PMIX_GDS_CHECK_COMPONENT(pmix_client_globals.myserver, "hash")) { // try again with our hash store PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, cb); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { return PMIX_SUCCESS; } } // get here if not found return PMIX_ERR_NOT_FOUND; } static void resolve_peers(int sd, short args, void *cbdata) { pmix_resolve_caddy_t *cd = (pmix_resolve_caddy_t*)cbdata; pmix_cb_t cb; pmix_info_t info[3]; pmix_status_t rc; pmix_proc_t proc; pmix_value_t *val; char **p, **tmp = NULL, *prs; pmix_proc_t *pa; size_t m, n, np, ninfo; pmix_namespace_t *ns; char *key; pmix_kval_t *kv; PMIX_HIDE_UNUSED_PARAMS(sd, args); // restrict our search to already available info - do // not allow the search to call up to the server. This // avoids a threadlock situation PMIX_INFO_LOAD(&info[0], PMIX_OPTIONAL, NULL, PMIX_BOOL); /* if I am a client and my server is earlier than v3.2.x, then * I need to look for this data under rank=PMIX_RANK_WILDCARD * with a key equal to the nodename */ if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer) && PMIX_PEER_IS_EARLIER(pmix_client_globals.myserver, 3, 1, 100)) { proc.rank = PMIX_RANK_WILDCARD; key = cd->nodename; ninfo = 1; } else { proc.rank = PMIX_RANK_UNDEF; key = PMIX_LOCAL_PEERS; PMIX_INFO_LOAD(&info[1], PMIX_NODE_INFO, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[2], PMIX_HOSTNAME, cd->nodename, PMIX_STRING); ninfo = 3; } PMIX_CONSTRUCT(&cb, pmix_cb_t); proc.rank = PMIX_RANK_UNDEF; cb.proc = &proc; cb.key = key; cb.scope = PMIX_INTERNAL; cb.info = info; cb.ninfo = ninfo; if (0 == pmix_nslen(cd->nspace)) { rc = PMIX_ERR_DATA_VALUE_NOT_FOUND; np = 0; /* cycle across all known nspaces and aggregate the results */ PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { PMIX_LOAD_NSPACE(proc.nspace, ns->nspace); rc = try_fetch(&cb); if (PMIX_SUCCESS != rc) { continue; } /* sanity check */ if (0 == pmix_list_get_size(&cb.kvs)) { continue; } kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs); val = kv->value; if (PMIX_STRING != val->type) { PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL); PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); continue; } if (NULL == val->data.string) { /* no local peers on this node */ PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); continue; } /* prepend the nspace */ if (0 > asprintf(&prs, "%s:%s", ns->nspace, val->data.string)) { PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); continue; } /* add to our list of results */ PMIx_Argv_append_nosize(&tmp, prs); /* split to count the npeers */ p = PMIx_Argv_split(val->data.string, ','); np += PMIx_Argv_count(p); /* done with this entry */ PMIx_Argv_free(p); free(prs); // clean up and cycle around to next namespace PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); } if (0 < np) { /* allocate the proc array */ PMIX_PROC_CREATE(pa, np); if (NULL == pa) { rc = PMIX_ERR_NOMEM; PMIx_Argv_free(tmp); goto done; } cd->procs = pa; cd->nprocs = np; /* transfer the results */ np = 0; for (n = 0; NULL != tmp[n]; n++) { /* find the nspace delimiter */ prs = strchr(tmp[n], ':'); if (NULL == prs) { /* should never happen, but silence a Coverity warning */ rc = PMIX_ERR_BAD_PARAM; PMIx_Argv_free(tmp); PMIX_PROC_FREE(pa, np); cd->procs = NULL; cd->nprocs = 0; goto done; } *prs = '\0'; ++prs; p = PMIx_Argv_split(prs, ','); for (m = 0; NULL != p[m]; m++) { PMIX_LOAD_NSPACE(pa[np].nspace, tmp[n]); pa[np].rank = strtoul(p[m], NULL, 10); ++np; } PMIx_Argv_free(p); } PMIx_Argv_free(tmp); rc = PMIX_SUCCESS; } goto done; } /* get the list of local peers for this nspace and node */ PMIX_LOAD_PROCID(&proc, cd->nspace, PMIX_RANK_UNDEF); rc = try_fetch(&cb); if (PMIX_SUCCESS == rc) { goto process; } if (PMIX_ERR_INVALID_NAMESPACE == rc) { // this namespace is unknown goto done; } if (PMIX_ERR_NOT_FOUND == rc) { // found the namespace, but the node is // not present on that namespace - the // default response is correct rc = PMIX_SUCCESS; goto done; } if (PMIX_ERR_DATA_VALUE_NOT_FOUND == rc) { // found the namespace and node, but the // host did not provide the information goto done; } process: /* sanity check */ if (0 == pmix_list_get_size(&cb.kvs)) { rc = PMIX_ERR_INVALID_VAL; goto done; } kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs); val = kv->value; if (PMIX_STRING != val->type || NULL == val->data.string) { rc = PMIX_ERR_INVALID_VAL; goto done; } /* split the procs to get a list */ p = PMIx_Argv_split(val->data.string, ','); np = PMIx_Argv_count(p); /* allocate the proc array */ PMIX_PROC_CREATE(pa, np); if (NULL == pa) { rc = PMIX_ERR_NOMEM; PMIx_Argv_free(p); goto done; } /* transfer the results */ for (n = 0; n < np; n++) { PMIX_LOAD_NSPACE(pa[n].nspace, cd->nspace); pa[n].rank = strtoul(p[n], NULL, 10); } PMIx_Argv_free(p); cd->procs = pa; cd->nprocs = np; done: for (n=0; n < ninfo; n++) { PMIX_INFO_DESTRUCT(&info[n]); } PMIX_DESTRUCT(&cb); cd->status = rc; PMIX_WAKEUP_THREAD(&cd->lock); } static void respeer(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_cb_t *cb = (pmix_cb_t*)cbdata; size_t n; PMIX_ACQUIRE_OBJECT(cb); cb->status = status; if (PMIX_SUCCESS == status) { cb->ninfo = ninfo; PMIX_INFO_CREATE(cb->info, ninfo); for (n=0; n < ninfo; n++) { PMIX_INFO_XFER(&cb->info[n], &info[n]); } } if (NULL != release_fn) { release_fn(release_cbdata); } PMIX_WAKEUP_THREAD(&cb->lock); PMIX_POST_OBJECT(cb); } PMIX_EXPORT pmix_status_t PMIx_Resolve_peers(const char *nodename, const pmix_nspace_t nspace, pmix_proc_t **procs, size_t *nprocs) { pmix_resolve_caddy_t *cd; pmix_buffer_t *msg; pmix_status_t rc; pmix_cmd_t cmd = PMIX_RESOLVE_PEERS_CMD; char *nd, *str; pmix_info_t *iptr; pmix_query_t query; pmix_cb_t cb; pmix_value_t *val; /* set default response */ *procs = NULL; *nprocs = 0; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } // if the nodename is NULL, then they are asking for our // local host if (NULL == nodename) { nd = pmix_globals.hostname; } else { nd = (char*)nodename; } // if we are a server, see if our host can answer the // request since it should have more global knowledge if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { if (NULL != pmix_host_server.query) { PMIX_QUERY_CONSTRUCT(&query); PMIX_ARGV_APPEND(rc, query.keys, PMIX_QUERY_RESOLVE_PEERS); PMIX_INFO_CREATE(iptr, 2); str = (char*)nspace; PMIX_INFO_LOAD(&iptr[0], PMIX_NSPACE, str, PMIX_STRING); PMIX_INFO_SET_QUALIFIER(&iptr[0]); PMIX_INFO_LOAD(&iptr[1], PMIX_HOSTNAME, nd, PMIX_STRING); PMIX_INFO_SET_QUALIFIER(&iptr[1]); query.qualifiers = iptr; query.nqual = 2; PMIX_CONSTRUCT(&cb, pmix_cb_t); rc = pmix_host_server.query(&pmix_globals.myid, &query, 1, respeer, (void*)&cb); if (PMIX_SUCCESS == rc) { // wait for the response PMIX_WAIT_THREAD(&cb.lock); PMIX_QUERY_DESTRUCT(&query); rc = cb.status; if (PMIX_SUCCESS == rc) { // string return should be in first info if (0 < cb.ninfo) { val = &cb.info[0].value; if (PMIX_DATA_ARRAY != val->type || PMIX_PROC != val->data.darray->type) { PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL); } else { *procs = (pmix_proc_t*)val->data.darray->array; *nprocs = val->data.darray->size; // protect the returned data cb.info = NULL; cb.ninfo = 0; PMIX_DESTRUCT(&cb); return rc; } } } } PMIX_DESTRUCT(&cb); } // if we get here, then the host wasn't able to // provide us with what we need, so let's do it ourselves cd = PMIX_NEW(pmix_resolve_caddy_t); cd->nodename = nd; PMIX_LOAD_NSPACE(cd->nspace, nspace); PMIX_THREADSHIFT(cd, resolve_peers); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; if (PMIX_SUCCESS == rc) { *procs = cd->procs; *nprocs = cd->nprocs; // protect the returning values cd->procs = NULL; cd->nprocs = 0; } PMIX_RELEASE(cd); return rc; } /* if we aren't connected, don't attempt to send - just * provide our local understanding of the situation. * Threadshift to compute it as we will be accessing * global info */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { cd = PMIX_NEW(pmix_resolve_caddy_t); cd->nodename = nd; PMIX_LOAD_NSPACE(cd->nspace, nspace); PMIX_THREADSHIFT(cd, resolve_peers); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; if (PMIX_SUCCESS == rc) { *procs = cd->procs; *nprocs = cd->nprocs; // protect the returning values cd->procs = NULL; cd->nprocs = 0; } PMIX_RELEASE(cd); return rc; } // send the request to our server as they have a more // global view of the situation than we might msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the request information */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nd, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } str = (char*)nspace; PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &str, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } cd = PMIX_NEW(pmix_resolve_caddy_t); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, wait_peers_cbfunc, (void *) cd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); return rc; } PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; if (PMIX_SUCCESS == rc) { *procs = cd->procs; *nprocs = cd->nprocs; // protect the returning values cd->procs = NULL; cd->nprocs = 0; } else { // if the server couldn't process it, that's likely because it // is an older version that doesn't recognize the cmd. So // process it ourselves cd->nodename = nd; PMIX_LOAD_NSPACE(cd->nspace, nspace); // reset the lock PMIX_DESTRUCT_LOCK(&cd->lock); PMIX_CONSTRUCT_LOCK(&cd->lock); PMIX_THREADSHIFT(cd, resolve_peers); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; if (PMIX_SUCCESS == rc) { *procs = cd->procs; *nprocs = cd->nprocs; // protect the returning values cd->procs = NULL; cd->nprocs = 0; } } PMIX_RELEASE(cd); return rc; } static void resolve_nodes(int sd, short args, void *cbdata) { pmix_resolve_caddy_t *cd = (pmix_resolve_caddy_t*)cbdata; pmix_cb_t cb; pmix_info_t info; pmix_status_t rc; pmix_proc_t proc; pmix_kval_t *kv; pmix_value_t *val = NULL; char **tmp = NULL, **p; size_t n; pmix_namespace_t *ns; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cd); /* get the list of nodes for this nspace */ proc.rank = PMIX_RANK_WILDCARD; // restrict our search to already available info - do // not allow the search to call up to the server. This // avoids a threadlock situation PMIX_INFO_LOAD(&info, PMIX_OPTIONAL, NULL, PMIX_BOOL); PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &proc; cb.key = PMIX_NODE_LIST; cb.scope = PMIX_INTERNAL; cb.info = &info; cb.ninfo = 1; if (0 == pmix_nslen(cd->nspace)) { /* cycle across all known nspaces and aggregate the results */ PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { PMIX_LOAD_NSPACE(proc.nspace, ns->nspace); rc = try_fetch(&cb); if (PMIX_SUCCESS != rc) { continue; } /* sanity check */ if (0 == pmix_list_get_size(&cb.kvs)) { continue; } kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs); val = kv->value; if (PMIX_STRING != val->type) { PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL); PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); continue; } if (NULL == val->data.string) { /* no nodes found */ PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); continue; } /* add to our list of results, ensuring uniqueness */ p = PMIx_Argv_split(val->data.string, ','); for (n = 0; NULL != p[n]; n++) { PMIx_Argv_append_unique_nosize(&tmp, p[n]); } PMIx_Argv_free(p); PMIX_LIST_DESTRUCT(&cb.kvs); PMIX_CONSTRUCT(&cb.kvs, pmix_list_t); } if (0 < PMIx_Argv_count(tmp)) { cd->nodelist = PMIx_Argv_join(tmp, ','); PMIx_Argv_free(tmp); } rc = PMIX_SUCCESS; goto done; } // looking for a specific nspace PMIX_LOAD_NSPACE(proc.nspace, cd->nspace); rc = try_fetch(&cb); if (PMIX_SUCCESS == rc) { goto process; } if (PMIX_ERR_INVALID_NAMESPACE == rc) { // this namespace is unknown goto done; } if (PMIX_ERR_NOT_FOUND == rc) { // found the namespace, but the node is // not present on that namespace - the // default response is correct rc = PMIX_SUCCESS; goto done; } if (PMIX_ERR_DATA_VALUE_NOT_FOUND == rc) { // found the namespace and node, but the // host did not provide the information goto done; } process: /* sanity check */ if (0 == pmix_list_get_size(&cb.kvs)) { goto done; } kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs); val = kv->value; if (PMIX_STRING != val->type || NULL == val->data.string) { PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL); goto done; } cd->nodelist = strdup(val->data.string); done: /* pass back the result */ cd->status = rc; // protect the field cb.info = NULL; cb.ninfo = 0; PMIX_DESTRUCT(&cb); PMIX_WAKEUP_THREAD(&cd->lock); PMIX_POST_OBJECT(cd); } static void resnode(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_cb_t *cb = (pmix_cb_t*)cbdata; size_t n; PMIX_ACQUIRE_OBJECT(cb); cb->status = status; if (PMIX_SUCCESS == status) { cb->ninfo = ninfo; PMIX_INFO_CREATE(cb->info, ninfo); for (n=0; n < ninfo; n++) { PMIX_INFO_XFER(&cb->info[n], &info[n]); } } if (NULL != release_fn) { release_fn(release_cbdata); } PMIX_WAKEUP_THREAD(&cb->lock); PMIX_POST_OBJECT(cb); } PMIX_EXPORT pmix_status_t PMIx_Resolve_nodes(const pmix_nspace_t nspace, char **nodelist) { pmix_resolve_caddy_t *cd; pmix_status_t rc; pmix_buffer_t *msg = NULL; pmix_cmd_t cmd = PMIX_RESOLVE_NODE_CMD; char *str; pmix_query_t query; pmix_info_t info; pmix_cb_t cb; pmix_value_t *val; /* set default response */ *nodelist = NULL; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } // if we are a server, see if our host can answer the // request since it should have more global knowledge if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { if (NULL != pmix_host_server.query) { PMIX_QUERY_CONSTRUCT(&query); PMIX_ARGV_APPEND(rc, query.keys, PMIX_QUERY_RESOLVE_NODE); str = (char*)nspace; PMIX_INFO_LOAD(&info, PMIX_NSPACE, str, PMIX_STRING); PMIX_INFO_SET_QUALIFIER(&info); query.qualifiers = &info; query.nqual = 1; PMIX_CONSTRUCT(&cb, pmix_cb_t); rc = pmix_host_server.query(&pmix_globals.myid, &query, 1, resnode, (void*)&cb); if (PMIX_SUCCESS == rc) { // wait for the response PMIX_WAIT_THREAD(&cb.lock); // protect the qualifier query.qualifiers = NULL; query.nqual = 0; PMIX_QUERY_DESTRUCT(&query); rc = cb.status; if (PMIX_SUCCESS == rc) { // string return should be in first info if (0 < cb.ninfo) { val = &cb.info[0].value; if (PMIX_STRING != val->type) { PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL); } else { *nodelist = strdup(val->data.string); PMIX_DESTRUCT(&cb); return rc; } } } } PMIX_DESTRUCT(&cb); } // if we get here, then the host wasn't able to // provide us with what we need, so let's do it ourselves cd = PMIX_NEW(pmix_resolve_caddy_t); PMIX_LOAD_NSPACE(cd->nspace, nspace); PMIX_THREADSHIFT(cd, resolve_nodes); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; if (PMIX_SUCCESS == rc) { *nodelist = cd->nodelist; // protect the returned value cd->nodelist = NULL; } PMIX_RELEASE(cd); return rc; } /* if we aren't connected, don't attempt to send - just * provide our local understanding of the situation. * Threadshift to compute it as we will be accessing * global info */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { cd = PMIX_NEW(pmix_resolve_caddy_t); PMIX_LOAD_NSPACE(cd->nspace, nspace); PMIX_THREADSHIFT(cd, resolve_nodes); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; if (PMIX_SUCCESS == rc) { *nodelist = cd->nodelist; // protect the returned value cd->nodelist = NULL; } PMIX_RELEASE(cd); return rc; } // send the request to our server as they have a more // global view of the situation than we might msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the request information */ str = (char*)nspace; PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &str, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } cd = PMIX_NEW(pmix_resolve_caddy_t); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, wait_node_cbfunc, (void *) cd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(cd); return rc; } PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; if (PMIX_SUCCESS == rc) { *nodelist = cd->nodelist; // protect the returning values cd->nodelist = NULL; } else { // if the server couldn't process it, that's likely because it // is an older version that doesn't recognize the cmd. So // process it ourselves PMIX_LOAD_NSPACE(cd->nspace, nspace); // reset the lock PMIX_DESTRUCT_LOCK(&cd->lock); PMIX_CONSTRUCT_LOCK(&cd->lock); PMIX_THREADSHIFT(cd, resolve_nodes); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; if (PMIX_SUCCESS == rc) { *nodelist = cd->nodelist; // protect the returned value cd->nodelist = NULL; } } PMIX_RELEASE(cd); return rc; } static void wait_peers_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_resolve_caddy_t *cd = (pmix_resolve_caddy_t*)cbdata; pmix_status_t rc; pmix_status_t ret; int32_t cnt; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:client resolve_peers callback activated with %d bytes", (NULL == buf) ? -1 : (int) buf->bytes_used); PMIX_HIDE_UNUSED_PARAMS(pr, hdr); if (NULL == buf) { ret = PMIX_ERR_BAD_PARAM; goto done; } /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { ret = PMIX_ERR_UNREACH; goto done; } /* unpack the returned status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; } /* if the status is success, then unpack the answer */ if (PMIX_SUCCESS == ret) { cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &cd->nprocs, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; goto done; } if (0 < cd->nprocs) { PMIX_PROC_CREATE(cd->procs, cd->nprocs); cnt = cd->nprocs; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, cd->procs, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_PROC_FREE(cd->procs, cd->nprocs); ret = rc; goto done; } } } done: cd->status = ret; PMIX_WAKEUP_THREAD(&cd->lock); return; } static void wait_node_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_resolve_caddy_t *cd = (pmix_resolve_caddy_t*)cbdata; pmix_status_t rc; pmix_status_t ret; int32_t cnt; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:client resolve_peers callback activated with %d bytes", (NULL == buf) ? -1 : (int) buf->bytes_used); PMIX_HIDE_UNUSED_PARAMS(pr, hdr); if (NULL == buf) { ret = PMIX_ERR_BAD_PARAM; goto done; } /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { ret = PMIX_ERR_UNREACH; goto done; } /* unpack the returned status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; } /* if the status is success, then unpack the answer */ if (PMIX_SUCCESS == ret) { cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &cd->nodelist, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; goto done; } } done: cd->status = ret; PMIX_WAKEUP_THREAD(&cd->lock); return; } pmix-6.1.1~rc2/src/client/pmix_client_ops.h0000664000175000017500000000415715203536752021116 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_CLIENT_OPS_H #define PMIX_CLIENT_OPS_H #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "src/class/pmix_pointer_array.h" #include "src/common/pmix_iof.h" #include "src/include/pmix_globals.h" #include "src/threads/pmix_threads.h" BEGIN_C_DECLS typedef struct { pmix_peer_t *myserver; // messaging support to/from my server bool singleton; // no server pmix_list_t pending_requests; // list of pmix_cb_t pending data requests pmix_pointer_array_t peers; // array of pmix_peer_t cached for data ops pmix_list_t groups; // list of groups this client is part of // verbosity for client get operations int get_output; int get_verbose; // verbosity for client connect operations int connect_output; int connect_verbose; // verbosity for client fence operations int fence_output; int fence_verbose; // verbosity for client pub operations int pub_output; int pub_verbose; // verbosity for client spawn operations int spawn_output; int spawn_verbose; // verbosity for client event operations int event_output; int event_verbose; // verbosity for client iof operations int iof_output; int iof_verbose; // verbosity for basic client functions int base_output; int base_verbose; /* IOF output sinks */ pmix_iof_sink_t iof_stdout; pmix_iof_sink_t iof_stderr; // verbosity for client group operations int group_output; int group_verbose; } pmix_client_globals_t; PMIX_EXPORT extern pmix_client_globals_t pmix_client_globals; PMIX_EXPORT void pmix_parse_localquery(int sd, short args, void *cbdata); PMIX_EXPORT pmix_status_t pmix_client_convert_group_procs(const pmix_proc_t *inprocs, size_t insize, pmix_proc_t **outprocs, size_t *outsize); END_C_DECLS #endif /* PMIX_CLIENT_OPS_H */ pmix-6.1.1~rc2/src/client/pmix_client_connect.c0000664000175000017500000004300715203536752021736 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "src/include/pmix_globals.h" #include "src/mca/gds/base/base.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "src/class/pmix_list.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/gds/gds.h" #include "src/mca/ptl/ptl.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "pmix_client_ops.h" /* callback for wait completion */ static void wait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static void op_cbfunc(pmix_status_t status, void *cbdata); PMIX_EXPORT pmix_status_t PMIx_Connect(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo) { pmix_status_t rc; pmix_cb_t *cb; pmix_output_verbose(2, pmix_client_globals.connect_output, "pmix: connect called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_cb_t); /* push the message into our event base to send to the server */ if (PMIX_SUCCESS != (rc = PMIx_Connect_nb(procs, nprocs, info, ninfo, op_cbfunc, cb))) { PMIX_RELEASE(cb); return rc; } /* wait for the connect to complete */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; PMIX_RELEASE(cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix: connect completed"); return rc; } PMIX_EXPORT pmix_status_t PMIx_Connect_nb(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_CONNECTNB_CMD; pmix_status_t rc; pmix_cb_t *cb, cb2; pmix_byte_object_t bo; pmix_buffer_t pbkt; pmix_info_t xfer; pmix_kval_t *kv; void *ilist; pmix_data_array_t darray; bool found; size_t n; pmix_nspace_t nspace; pmix_rank_t minrank; pmix_proc_t proc; pmix_output_verbose(2, pmix_client_globals.connect_output, "pmix:connect_nb called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* check for bozo input */ if (NULL == procs || 0 >= nprocs) { return PMIX_ERR_BAD_PARAM; } msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack the number of procs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nprocs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, procs, nprocs, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack the info structs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* get our endpt info, if some was posted. We use * "remote" scope as all local procs have access * to info posted by all other local procs, regardless * of their namespace */ PMIX_BYTE_OBJECT_CONSTRUCT(&bo); PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = &pmix_globals.myid; cb2.scope = PMIX_REMOTE; cb2.copy = true; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); if (PMIX_SUCCESS == rc) { ilist = PMIx_Info_list_start(); PMIX_CONSTRUCT(&pbkt, pmix_buffer_t); // start with our procID PMIx_Info_list_add(ilist, PMIX_PROCID, &pmix_globals.myid, PMIX_PROC); // now add the kvals found = false; PMIX_LIST_FOREACH (kv, &cb2.kvs, pmix_kval_t) { if (PMIx_Check_reserved_key(kv->key)) { continue; } PMIx_Info_list_add_value_unique(ilist, kv->key, kv->value, true); found = true; } if (found) { // convert to array rc = PMIx_Info_list_convert(ilist, &darray); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIx_Info_list_release(ilist); return rc; } // insert into a pmix_info_t for packing PMIX_INFO_LOAD(&xfer, PMIX_PROC_DATA, &darray, PMIX_DATA_ARRAY); PMIX_DATA_ARRAY_DESTRUCT(&darray); // pack the result PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &xfer, 1, PMIX_INFO); PMIX_INFO_DESTRUCT(&xfer); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIx_Info_list_release(ilist); return rc; } } PMIx_Info_list_release(ilist); } PMIX_DESTRUCT(&cb2); /* if this operation involves multiple namespaces, then we need to * share job-level info between the participants. We only need to * add it once per namespace, so have the lowest participating rank * in each namespace add the info */ PMIX_LOAD_NSPACE(nspace, procs[0].nspace); found = false; for (n=1; n < nprocs; n++) { if (!PMIX_CHECK_NSPACE(nspace, procs[n].nspace)) { found = true; break; } } if (found) { // see if I am the lowest participating rank from my namespace minrank = UINT32_MAX; for (n=0; n < nprocs; n++) { if (PMIX_CHECK_NSPACE(pmix_globals.myid.nspace, procs[n].nspace)) { // this is my nspace - check the rank if (PMIX_RANK_WILDCARD == procs[n].rank) { // all ranks included, so see if I am rank 0 if (0 == pmix_globals.myid.rank) { minrank = 0; break; } } else { // see if I am the lowest if (procs[n].rank < minrank) { minrank = procs[n].rank; } } } } if (minrank == pmix_globals.myid.rank) { // we will provide the job-level info for our nspace PMIX_CONSTRUCT(&cb2, pmix_cb_t); PMIX_LOAD_PROCID(&proc, pmix_globals.myid.nspace, PMIX_RANK_WILDCARD); cb2.proc = &proc; cb2.scope = PMIX_SCOPE_UNDEF; cb2.copy = false; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb2); if (PMIX_SUCCESS != rc) { if (!PMIX_GDS_CHECK_COMPONENT(pmix_client_globals.myserver, "hash")) { /* check the data in my hash module */ PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb2); goto moveon; } } else { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&cb2); goto moveon; } } if (0 < pmix_list_get_size(&cb2.kvs)) { // pack to send it along ilist = PMIx_Info_list_start(); // start with our namespace PMIx_Info_list_add(ilist, PMIX_NSPACE, pmix_globals.myid.nspace, PMIX_PROC_NSPACE); // now add the kvals PMIX_LIST_FOREACH (kv, &cb2.kvs, pmix_kval_t) { PMIx_Info_list_add_value_unique(ilist, kv->key, kv->value, true); found = true; } // convert to array rc = PMIx_Info_list_convert(ilist, &darray); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIx_Info_list_release(ilist); return rc; } // insert into a pmix_info_t for packing PMIX_INFO_LOAD(&xfer, PMIX_JOB_INFO_ARRAY, &darray, PMIX_DATA_ARRAY); // pack the result PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &xfer, 1, PMIX_INFO); PMIX_DATA_ARRAY_DESTRUCT(&darray); PMIX_INFO_DESTRUCT(&xfer); PMIx_Info_list_release(ilist); } } } moveon: /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_cb_t); cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, wait_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } return rc; } PMIX_EXPORT pmix_status_t PMIx_Disconnect(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo) { pmix_status_t rc; pmix_cb_t *cb; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_cb_t); if (PMIX_SUCCESS != (rc = PMIx_Disconnect_nb(procs, nprocs, info, ninfo, op_cbfunc, cb))) { PMIX_RELEASE(cb); return rc; } /* wait for the disconnect to complete */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; PMIX_RELEASE(cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix: disconnect completed"); return rc; } PMIX_EXPORT pmix_status_t PMIx_Disconnect_nb(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_DISCONNECTNB_CMD; pmix_status_t rc; pmix_cb_t *cb; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: disconnect called"); size_t cnt; for (cnt = 0; cnt < nprocs; cnt++) { if (0 != strcmp(pmix_globals.myid.nspace, procs[cnt].nspace)) { PMIX_GDS_DEL_NSPACE(rc, procs[cnt].nspace); } } if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* check for bozo input */ if (NULL == procs || 0 >= nprocs) { return PMIX_ERR_BAD_PARAM; } msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack the number of procs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nprocs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, procs, nprocs, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack the info structs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_cb_t); cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, wait_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } pmix_output_verbose(2, pmix_globals.debug_output, "pmix: disconnect completed"); return rc; } static void wait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_status_t rc; pmix_status_t ret; int32_t cnt; char *nspace; pmix_buffer_t bkt; pmix_byte_object_t bo; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:client recv callback activated with %d bytes", (NULL == buf) ? -1 : (int) buf->bytes_used); PMIX_HIDE_UNUSED_PARAMS(pr, hdr); if (NULL == buf) { ret = PMIX_ERR_BAD_PARAM; goto report; } /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { ret = PMIX_ERR_UNREACH; goto report; } /* unpack the returned status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; } /* connect has to also pass back data from all nspace's involved in * the operation, including our own. Each will come as a byte object */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &bo, &cnt, PMIX_BYTE_OBJECT); while (PMIX_SUCCESS == rc) { /* load it for unpacking */ PMIX_CONSTRUCT(&bkt, pmix_buffer_t); PMIX_LOAD_BUFFER(pmix_client_globals.myserver, &bkt, bo.bytes, bo.size); /* unpack the nspace for this blob */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, &bkt, &nspace, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&bkt); continue; } /* extract and process any proc-related info for this nspace */ PMIX_GDS_STORE_JOB_INFO(rc, pmix_globals.mypeer, nspace, &bkt); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } free(nspace); PMIX_DESTRUCT(&bkt); /* get the next one */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &bo, &cnt, PMIX_BYTE_OBJECT); } if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); ret = rc; } report: if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(ret, cb->cbdata); } PMIX_RELEASE(cb); } static void op_cbfunc(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; cb->status = status; PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } pmix-6.1.1~rc2/src/client/pmix_client_pub.c0000664000175000017500000004506115203536752021075 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "src/class/pmix_list.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/ptl/ptl.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "pmix_client_ops.h" static void wait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static void op_cbfunc(pmix_status_t status, void *cbdata); static void wait_lookup_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static void lookup_cbfunc(pmix_status_t status, pmix_pdata_t pdata[], size_t ndata, void *cbdata); PMIX_EXPORT pmix_status_t PMIx_Publish(const pmix_info_t info[], size_t ninfo) { pmix_status_t rc; pmix_cb_t *cb; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: publish called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object to let us know when it is done */ cb = PMIX_NEW(pmix_cb_t); if (PMIX_SUCCESS != (rc = PMIx_Publish_nb(info, ninfo, op_cbfunc, cb))) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cb); return rc; } /* wait for the server to ack our request */ PMIX_WAIT_THREAD(&cb->lock); rc = (pmix_status_t) cb->status; PMIX_RELEASE(cb); return rc; } PMIX_EXPORT pmix_status_t PMIx_Publish_nb(const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_PUBLISHNB_CMD; pmix_status_t rc; pmix_cb_t *cb; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: publish called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* check for bozo cases */ if (NULL == info) { /* nothing to publish */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return PMIX_ERR_BAD_PARAM; } /* create the publish cmd */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack our effective userid - will be used to constrain lookup */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &pmix_globals.uid, 1, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pass the number of info structs - needed on remote end so * space can be malloc'd for the values */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < ninfo) { /* pack the info structs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_cb_t); cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, wait_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } return rc; } PMIX_EXPORT pmix_status_t PMIx_Lookup(pmix_pdata_t pdata[], size_t ndata, const pmix_info_t info[], size_t ninfo) { pmix_status_t rc; pmix_cb_t *cb; char **keys = NULL; size_t i; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: lookup called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* bozo protection */ if (NULL == pdata) { return PMIX_ERR_BAD_PARAM; } /* transfer the pdata keys to the keys argv array */ for (i = 0; i < ndata; i++) { if ('\0' != pdata[i].key[0]) { PMIx_Argv_append_nosize(&keys, pdata[i].key); } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_cb_t); cb->cbdata = (void *) pdata; cb->nvals = ndata; if (PMIX_SUCCESS != (rc = PMIx_Lookup_nb(keys, info, ninfo, lookup_cbfunc, cb))) { PMIX_RELEASE(cb); PMIx_Argv_free(keys); return rc; } /* wait for the server to ack our request */ PMIX_WAIT_THREAD(&cb->lock); /* the data has been stored in the info array by lookup_cbfunc, so * nothing more for us to do */ rc = cb->status; PMIX_RELEASE(cb); return rc; } PMIX_EXPORT pmix_status_t PMIx_Lookup_nb(char **keys, const pmix_info_t info[], size_t ninfo, pmix_lookup_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_LOOKUPNB_CMD; pmix_status_t rc; pmix_cb_t *cb; size_t nkeys, n; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: lookup_nb called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* check for bozo cases */ if (NULL == keys) { return PMIX_ERR_BAD_PARAM; } /* create the lookup cmd */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack our effective userid - will be used to constrain lookup */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &pmix_globals.uid, 1, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the keys */ nkeys = PMIx_Argv_count(keys); PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nkeys, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < nkeys) { for (n = 0; n < nkeys; n++) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &keys[n], 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } } /* pass the number of info structs - needed on remote end so * space can be malloc'd for the values */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < ninfo) { /* pack the info structs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_cb_t); cb->cbfunc.lookupfn = cbfunc; cb->cbdata = cbdata; /* send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, wait_lookup_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } return rc; } PMIX_EXPORT pmix_status_t PMIx_Unpublish(char **keys, const pmix_info_t info[], size_t ninfo) { pmix_status_t rc; pmix_cb_t *cb; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: unpublish called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_cb_t); /* push the message into our event base to send to the server */ if (PMIX_SUCCESS != (rc = PMIx_Unpublish_nb(keys, info, ninfo, op_cbfunc, cb))) { PMIX_RELEASE(cb); return rc; } /* wait for the server to ack our request */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; PMIX_RELEASE(cb); return rc; } PMIX_EXPORT pmix_status_t PMIx_Unpublish_nb(char **keys, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_UNPUBLISHNB_CMD; pmix_status_t rc; pmix_cb_t *cb; size_t i, j; pmix_output_verbose(2, pmix_globals.debug_output, "pmix: unpublish called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create the unpublish cmd */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack our effective userid - will be used to constrain lookup */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &pmix_globals.uid, 1, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the number of keys */ i = PMIx_Argv_count(keys); PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &i, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < i) { for (j = 0; j < i; j++) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &keys[j], 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } } /* pass the number of info structs - needed on remote end so * space can be malloc'd for the values */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (0 < ninfo) { /* pack the info structs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object */ cb = PMIX_NEW(pmix_cb_t); cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; /* send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, wait_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } return rc; } static void wait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_status_t rc; int ret; int32_t cnt; PMIX_ACQUIRE_OBJECT(cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:client recv callback activated with %d bytes", (NULL == buf) ? -1 : (int) buf->bytes_used); PMIX_HIDE_UNUSED_PARAMS(pr, hdr); if (NULL == buf) { ret = PMIX_ERR_BAD_PARAM; goto report; } /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { ret = PMIX_ERR_UNREACH; goto report; } /* unpack the returned status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; } report: if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(ret, cb->cbdata); } PMIX_RELEASE(cb); } static void op_cbfunc(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; cb->status = status; PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } static void wait_lookup_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_status_t rc, ret; int32_t cnt; pmix_pdata_t *pdata; size_t ndata; PMIX_ACQUIRE_OBJECT(cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:client recv callback activated with %d bytes", (NULL == buf) ? -1 : (int) buf->bytes_used); PMIX_HIDE_UNUSED_PARAMS(pr, hdr); /* set the defaults */ pdata = NULL; ndata = 0; if (NULL == cb->cbfunc.lookupfn) { /* nothing we can do with this */ PMIX_RELEASE(cb); return; } if (NULL == buf) { rc = PMIX_ERR_BAD_PARAM; goto report; } /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { rc = PMIX_ERR_UNREACH; goto report; } /* unpack the returned status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; } if (PMIX_SUCCESS != ret) { if (NULL != cb->cbfunc.lookupfn) { cb->cbfunc.lookupfn(ret, NULL, 0, cb->cbdata); } PMIX_RELEASE(cb); return; } /* unpack the number of returned values */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ndata, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cb); return; } if (0 < ndata) { /* create the array storage */ PMIX_PDATA_CREATE(pdata, ndata); cnt = ndata; /* unpack the returned values into the pdata array */ PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, pdata, &cnt, PMIX_PDATA); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } report: if (NULL != cb->cbfunc.lookupfn) { cb->cbfunc.lookupfn(rc, pdata, ndata, cb->cbdata); } cleanup: /* cleanup */ if (NULL != pdata) { PMIX_PDATA_FREE(pdata, ndata); } PMIX_RELEASE(cb); } static void lookup_cbfunc(pmix_status_t status, pmix_pdata_t pdata[], size_t ndata, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_pdata_t *tgt = (pmix_pdata_t *) cb->cbdata; size_t i, j; PMIX_ACQUIRE_OBJECT(cb); cb->status = status; if (PMIX_SUCCESS == status || PMIX_ERR_PARTIAL_SUCCESS == status) { /* find the matching key in the provided info array - okay * if not found as it might just be a partial return */ for (i = 0; i < ndata; i++) { for (j = 0; j < cb->nvals; j++) { if (0 == strcmp(pdata[i].key, tgt[j].key)) { /* transfer the publishing proc id */ memcpy(&tgt[j].proc, &pdata[i].proc, sizeof(pmix_proc_t)); /* transfer the value to the pmix_info_t */ PMIX_BFROPS_VALUE_XFER(cb->status, pmix_client_globals.myserver, &tgt[j].value, &pdata[i].value); break; } } } } PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } pmix-6.1.1~rc2/src/client/pmix_client_spawn.c0000664000175000017500000004527415203536752021445 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "src/class/pmix_list.h" #include "src/common/pmix_pfexec.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/gds/gds.h" #include "src/mca/pmdl/pmdl.h" #include "src/mca/pnet/base/base.h" #include "src/mca/ptl/ptl.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_basename.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_getcwd.h" #include "src/util/pmix_printf.h" #include "src/server/pmix_server_ops.h" #include "pmix_client_ops.h" static void wait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static void spawn_cbfunc(pmix_status_t status, char nspace[], void *cbdata); PMIX_EXPORT pmix_status_t PMIx_Spawn(const pmix_info_t job_info[], size_t ninfo, const pmix_app_t apps[], size_t napps, pmix_nspace_t nspace) { pmix_status_t rc; pmix_cb_t *cb; pmix_output_verbose(2, pmix_client_globals.spawn_output, "%s pmix: spawn called", PMIX_NAME_PRINT(&pmix_globals.myid)); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* ensure the nspace is initialized - note that nspace * is a pmix_nspace_t object, and therefore it cannot * be NULL */ memset(nspace, 0, PMIX_MAX_NSLEN + 1); /* create a callback object */ cb = PMIX_NEW(pmix_cb_t); if (PMIX_SUCCESS != (rc = PMIx_Spawn_nb(job_info, ninfo, apps, napps, spawn_cbfunc, cb))) { /* note: the call may have returned PMIX_OPERATION_SUCCEEDED thus indicating * that the spawn was atomically completed */ if (PMIX_OPERATION_SUCCEEDED == rc) { PMIX_LOAD_NSPACE(nspace, cb->pname.nspace); rc = PMIX_SUCCESS; } PMIX_RELEASE(cb); return rc; } /* wait for the result */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; if (NULL != nspace) { pmix_strncpy(nspace, cb->pname.nspace, PMIX_MAX_NSLEN); } PMIX_RELEASE(cb); return rc; } static void _lclcbfunc(int sd, short args, void *cbdata) { pmix_setup_caddy_t *fcd = (pmix_setup_caddy_t*)cbdata; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); // set default status rc = fcd->status; // process IOF requests if (PMIX_SUCCESS == fcd->status) { rc = pmix_server_process_iof(fcd, fcd->nspace); } if (NULL != fcd->spcbfunc) { fcd->spcbfunc(rc, fcd->nspace, fcd->cbdata); } // cleanup if (NULL != fcd->nspace) { free(fcd->nspace); } PMIX_RELEASE(fcd); } static void localcbfunc(pmix_status_t status, char nspace[], void *cbdata) { pmix_setup_caddy_t *fcd = (pmix_setup_caddy_t*)cbdata; fcd->status = status; if (NULL != nspace) { fcd->nspace = strdup(nspace); } PMIX_THREADSHIFT(fcd, _lclcbfunc); } PMIX_EXPORT pmix_status_t PMIx_Spawn_nb(const pmix_info_t job_info[], size_t ninfo, const pmix_app_t apps[], size_t napps, pmix_spawn_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_SPAWNNB_CMD; pmix_status_t rc; size_t n, m; pmix_setup_caddy_t *fcd = NULL; pmix_app_t *aptr; bool jobenvars = false; bool forkexec = false; pmix_kval_t *kv; pmix_list_t ilist; char cwd[PMIX_PATH_MAX]; char *tmp, *t2; bool proxy = false; void *xlist; pmix_proc_t parent; pmix_data_array_t darray; pmix_output_verbose(2, pmix_client_globals.spawn_output, "%s pmix: spawn_nb called", PMIX_NAME_PRINT(&pmix_globals.myid)); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { /* if I am a launcher, we default to local fork/exec */ if (PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer)) { forkexec = true; } else if (!PMIX_PEER_IS_SERVER(pmix_globals.mypeer) || PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { return PMIX_ERR_UNREACH; } } // setup the caddy fcd = PMIX_NEW(pmix_setup_caddy_t); fcd->spcbfunc = cbfunc; fcd->cbdata = cbdata; /* check job info for directives */ if (NULL != job_info) { xlist = PMIx_Info_list_start(); for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&job_info[n], PMIX_SETUP_APP_ENVARS)) { PMIX_CONSTRUCT(&ilist, pmix_list_t); rc = pmix_pmdl.harvest_envars(NULL, job_info, ninfo, &ilist); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&ilist); PMIX_RELEASE(fcd); return rc; } PMIX_LIST_FOREACH (kv, &ilist, pmix_kval_t) { /* cycle across all the apps and set this envar */ for (m = 0; m < napps; m++) { aptr = (pmix_app_t *) &apps[m]; PMIx_Setenv(kv->value->data.envar.envar, kv->value->data.envar.value, true, &aptr->env); } } jobenvars = true; PMIX_LIST_DESTRUCT(&ilist); } else if (PMIX_CHECK_KEY(&job_info[n], PMIX_PARENT_ID)) { PMIX_XFER_PROCID(&parent, job_info[n].value.data.proc); proxy = true; } rc = PMIx_Info_list_xfer(xlist, &job_info[n]); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(xlist); PMIX_RELEASE(fcd); return rc; } } // convert the list to an array rc = PMIx_Info_list_convert(xlist, &darray); if (PMIX_SUCCESS != rc) { PMIx_Info_list_release(xlist); PMIX_RELEASE(fcd); return rc; } fcd->info = darray.array; fcd->ninfo = darray.size; } /* sadly, we have to copy the apps array since we are * going to modify the individual app structs */ fcd->napps = napps; PMIX_APP_CREATE(fcd->apps, fcd->napps); for (n = 0; n < napps; n++) { aptr = (pmix_app_t *) &apps[n]; /* protect against bozo case */ if (NULL == aptr->cmd && NULL == aptr->argv) { /* they gave us nothing to spawn! */ PMIX_RELEASE(fcd); return PMIX_ERR_BAD_PARAM; } if (NULL == aptr->cmd) { // aptr->argv cannot be NULL as well or we // would have caught it above fcd->apps[n].cmd = strdup(aptr->argv[0]); } else { fcd->apps[n].cmd = strdup(aptr->cmd); } /* if they didn't give us a desired working directory, then * take the one we are in */ if (NULL == aptr->cwd) { rc = pmix_getcwd(cwd, sizeof(cwd)); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(fcd); return rc; } fcd->apps[n].cwd = strdup(cwd); } else { fcd->apps[n].cwd = strdup(aptr->cwd); } /* if they didn't give us the cmd as the first argv, fix it */ if (NULL == aptr->argv) { tmp = pmix_basename(aptr->cmd); fcd->apps[n].argv = (char **) malloc(2 * sizeof(char *)); fcd->apps[n].argv[0] = tmp; fcd->apps[n].argv[1] = NULL; } else { fcd->apps[n].argv = PMIx_Argv_copy(aptr->argv); tmp = pmix_basename(aptr->cmd); t2 = pmix_basename(aptr->argv[0]); if (0 != strcmp(tmp, t2)) { // assume that the user may have put the argv // for their cmd in the argv array, but not // started with the actual cmd - so add it // to the front of the array PMIx_Argv_prepend_nosize(&fcd->apps[n].argv, tmp); } free(tmp); free(t2); } // copy the env array fcd->apps[n].env = PMIx_Argv_copy(aptr->env); // copy the #procs fcd->apps[n].maxprocs = aptr->maxprocs; /* do a quick check of the apps directive array to ensure * the ninfo field has been set */ if (NULL != aptr->info) { if (0 == aptr->ninfo) { /* look for the info marked as "end" */ m = 0; while (!(PMIX_INFO_IS_END(&aptr->info[m])) && m < SIZE_MAX) { ++m; } if (SIZE_MAX == m) { /* nothing we can do */ PMIX_RELEASE(fcd); return PMIX_ERR_BAD_PARAM; } aptr->ninfo = m; } // copy the info array if (0 < aptr->ninfo) { fcd->apps[n].ninfo = aptr->ninfo; PMIX_INFO_CREATE(fcd->apps[n].info, fcd->apps[n].ninfo); for (m=0; m < aptr->ninfo; m++) { PMIX_INFO_XFER(&fcd->apps[n].info[m], &aptr->info[m]); } } } if (!jobenvars) { for (m = 0; m < fcd->apps[n].ninfo; m++) { if (PMIX_CHECK_KEY(&fcd->apps[n].info[m], PMIX_SETUP_APP_ENVARS)) { PMIX_CONSTRUCT(&ilist, pmix_list_t); rc = pmix_pmdl.harvest_envars(NULL, fcd->apps[n].info, fcd->apps[n].ninfo, &ilist); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&ilist); PMIX_RELEASE(fcd); return rc; } PMIX_LIST_FOREACH (kv, &ilist, pmix_kval_t) { PMIx_Setenv(kv->value->data.envar.envar, kv->value->data.envar.value, true, &fcd->apps[n].env); } jobenvars = true; PMIX_LIST_DESTRUCT(&ilist); break; } } } } /* if we are a server, then process this ourselves */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_LAUNCHER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { if (NULL == pmix_host_server.spawn) { PMIX_RELEASE(fcd); return PMIX_ERR_NOT_SUPPORTED; } /* if I am spawning on behalf of someone else, then * that peer is the "spawner" */ if (proxy) { /* find the parent's peer object */ fcd->peer = pmix_get_peer_object(&parent); if (NULL == fcd->peer) { PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND); PMIX_RELEASE(fcd); return PMIX_ERR_NOT_FOUND; } } else { fcd->peer = pmix_globals.mypeer; } PMIX_RETAIN(fcd->peer); /* run a quick check of the directives to see if any IOF * requests were included so we can set that up now - helps * to catch any early output - and a request for notification * of job termination so we can setup the event registration */ pmix_server_spawn_parser(fcd->peer, &fcd->channels, &fcd->flags, fcd->info, fcd->ninfo); /* call the local host */ rc = pmix_host_server.spawn(&pmix_globals.myid, fcd->info, fcd->ninfo, fcd->apps, fcd->napps, localcbfunc, fcd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(fcd); } return rc; } /* if we are not connected, then just fork/exec * the specified application */ fcd->peer = pmix_globals.mypeer; PMIX_RETAIN(fcd->peer); if (forkexec) { rc = pmix_pfexec_base_spawn_job(fcd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(fcd); } return rc; } msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(fcd); return rc; } /* pack the job-level directives */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &fcd->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(fcd); return rc; } if (0 < fcd->ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, fcd->info, fcd->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(fcd); return rc; } } /* pack the apps */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &fcd->napps, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(fcd); return rc; } if (0 < fcd->napps) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, fcd->apps, fcd->napps, PMIX_APP); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(fcd); return rc; } } /* check for IOF flags */ pmix_server_spawn_parser(fcd->peer, &fcd->channels, &fcd->flags, fcd->info, fcd->ninfo); /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, wait_cbfunc, (void *) fcd); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(fcd); } return rc; } /* callback for wait completion */ static void wait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_setup_caddy_t *fcd = (pmix_setup_caddy_t *) cbdata; char nspace[PMIX_MAX_NSLEN + 1]; char *n2 = NULL; pmix_status_t rc, ret; int32_t cnt; pmix_namespace_t *nptr, *ns; PMIX_ACQUIRE_OBJECT(fcd); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:client recv spawn callback activated with %d bytes", (NULL == buf) ? -1 : (int) buf->bytes_used); PMIX_HIDE_UNUSED_PARAMS(pr, hdr); /* init */ memset(nspace, 0, PMIX_MAX_NSLEN + 1); if (NULL == buf) { ret = PMIX_ERR_BAD_PARAM; goto report; } /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { ret = PMIX_ERR_UNREACH; goto report; } /* unpack the returned status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; } /* unpack the namespace */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &n2, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); ret = rc; } pmix_output_verbose(1, pmix_globals.debug_output, "pmix:client recv '%s'", n2); if (NULL != n2) { /* protect length */ pmix_strncpy(nspace, n2, PMIX_MAX_NSLEN); free(n2); PMIX_GDS_STORE_JOB_INFO(rc, pmix_globals.mypeer, nspace, buf); /* extract and process any job-related info for this nspace */ if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; } /* process any IOF flags - we are only concerned if we are a TOOL * and need to know if/how we should output any IO */ if (PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { nptr = NULL; PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) { if (PMIX_CHECK_NSPACE(ns->nspace, nspace)) { nptr = ns; break; } } if (NULL == nptr) { /* shouldn't happen, but protect us */ nptr = PMIX_NEW(pmix_namespace_t); nptr->nspace = strdup(nspace); pmix_list_append(&pmix_globals.nspaces, &nptr->super); } /* as a client, we only handle a select set of the flags */ memcpy(&nptr->iof_flags, &fcd->flags, sizeof(pmix_iof_flags_t)); nptr->iof_flags.file = NULL; nptr->iof_flags.directory = NULL; /* since we are not a server, nocopy equates to no_local_output */ if (fcd->flags.nocopy) { nptr->iof_flags.local_output = false; } } } report: if (NULL != fcd->spcbfunc) { fcd->spcbfunc(ret, nspace, fcd->cbdata); } PMIX_RELEASE(fcd); } static void spawn_cbfunc(pmix_status_t status, char nspace[], void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; PMIX_ACQUIRE_OBJECT(cb); cb->status = status; if (NULL != nspace) { cb->pname.nspace = strdup(nspace); } PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } pmix-6.1.1~rc2/src/client/pmix_client_convert.c0000664000175000017500000001474315203536752021772 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2021 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2022 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "src/class/pmix_object.h" #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/include/pmix_globals.h" static void append_unique(pmix_list_t *list, const pmix_proc_t *proc) { pmix_proclist_t *nm; // check for pre-existence PMIX_LIST_FOREACH(nm, list, pmix_proclist_t) { // require exact match if (!PMIX_CHECK_NSPACE(nm->proc.nspace, proc->nspace)) { continue; } if (nm->proc.rank != proc->rank) { continue; } // already present return; } // wasn't found, so add it nm = PMIX_NEW(pmix_proclist_t); memcpy(&nm->proc, proc, sizeof(pmix_proc_t)); pmix_list_append(list, &nm->super); } pmix_status_t pmix_client_convert_group_procs(const pmix_proc_t *inprocs, size_t insize, pmix_proc_t **outprocs, size_t *outsize) { pmix_list_t cache; pmix_proclist_t *nm; pmix_group_t *grp; size_t n, i, cnt, sz; bool match; uint32_t jsize; pmix_status_t rc; pmix_kval_t *kv; pmix_proc_t *procs, proc; pmix_cb_t cb2; PMIX_CONSTRUCT(&cache, pmix_list_t); /* cycle thru the procs and check to see if any reference * a PMIx group */ for (n = 0; n < insize; n++) { match = false; PMIX_LIST_FOREACH(grp, &pmix_client_globals.groups, pmix_group_t) { if (PMIX_CHECK_NSPACE(grp->grpid, inprocs[n].nspace)) { match = true; /* the nspace matches this group ID */ if (PMIX_RANK_WILDCARD == inprocs[n].rank) { /* we need to replace this proc with the grp members */ for (i=0; i < grp->nmbrs; i++) { append_unique(&cache, &grp->members[i]); } continue; } /* if the rank isn't wildcard, then we want a specific * proc from within the group. The group might include * members that have rank=wildcard for their nspace, * and so we have to count from the beginning to find * the proc of the specified group rank */ cnt = 0; for (i = 0; i < grp->nmbrs; i++) { /* we are looking for the cnt=inprocs[n].rank proc * within the group. so count our way across */ if (PMIX_RANK_WILDCARD == grp->members[i].rank) { /* We must get the number of procs in this nspace so * we can check to see if the specified rank actually * falls within it */ PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = (pmix_proc_t*)&grp->members[i]; cb2.key = PMIX_JOB_SIZE; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); if (PMIX_SUCCESS != rc && PMIX_OPERATION_SUCCEEDED != rc) { /* couldn't get the job size, so have to abort */ PMIX_LIST_DESTRUCT(&cache); PMIX_DESTRUCT(&cb2); return rc; } kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs); PMIX_DESTRUCT(&cb2); if (NULL == kv) { // should never be NULL /* couldn't retrieve the size, so we have * to abort */ PMIX_LIST_DESTRUCT(&cache); return PMIX_ERR_NOT_FOUND; } rc = PMIx_Value_get_number(kv->value, &jsize, PMIX_UINT32); PMIX_RELEASE(kv); if (PMIX_SUCCESS != rc) { PMIX_LIST_DESTRUCT(&cache); return PMIX_ERR_BAD_PARAM; } if (cnt + jsize > inprocs[n].rank) { /* the specified rank is within this job */ PMIX_LOAD_NSPACE(proc.nspace, grp->members[i].nspace); proc.rank = inprocs[n].rank - cnt; append_unique(&cache, &proc); break; } else { /* increment the count */ cnt += jsize; /* continue to the next group member */ } } else { /* this is a single proc entry, so just see if * it matches the one they asked for */ if (cnt == inprocs[n].rank) { append_unique(&cache, &grp->members[i]); break; } else { /* increment the count */ ++cnt; /* continue to the next group member */ } } } } if (match) { break; } } if (!match) { /* xfer the incoming proc across to the cache */ append_unique(&cache, &inprocs[n]); } } /* we have to return the cached array because * we might have replaced some of the entries */ sz = pmix_list_get_size(&cache); PMIX_PROC_CREATE(procs, sz); n = 0; PMIX_LIST_FOREACH(nm, &cache, pmix_proclist_t) { memcpy(&procs[n], &nm->proc, sizeof(pmix_proc_t)); ++n; } PMIX_LIST_DESTRUCT(&cache); *outprocs = procs; *outsize = sz; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/client/Makefile.include0000664000175000017500000000153415203536752020627 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2014-2020 Intel, Inc. All rights reserved. # Copyright (c) 2014 Artem Y. Polyakov . # All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2023-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # headers += \ client/pmix_client_ops.h sources += \ client/pmix_client.c \ client/pmix_client_fence.c \ client/pmix_client_get.c \ client/pmix_client_pub.c \ client/pmix_client_spawn.c \ client/pmix_client_connect.c \ client/pmix_client_group.c \ client/pmix_client_fabric.c \ client/pmix_client_topology.c \ client/pmix_client_convert.c \ client/pmix_client_resolve.c pmix-6.1.1~rc2/src/client/pmix_client.c0000664000175000017500000015141415203536752020227 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016-2017 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2022 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include #ifdef PMIX_GIT_REPO_BUILD static const char pmix_version_string[] = "OpenPMIx " PMIX_VERSION ", repo rev: " PMIX_REPO_REV " (PMIx Standard: " PMIX_STD_VERSION "," " Stable ABI: " PMIX_STD_ABI_STABLE_VERSION "," " Provisional ABI: " PMIX_STD_ABI_PROVISIONAL_VERSION ")"; #else static const char pmix_version_string[] = "OpenPMIx " PMIX_VERSION " (PMIx Standard: " PMIX_STD_VERSION "," " Stable ABI: " PMIX_STD_ABI_STABLE_VERSION "," " Provisional ABI: " PMIX_STD_ABI_PROVISIONAL_VERSION ")"; #endif #include "src/class/pmix_list.h" #include "src/common/pmix_attributes.h" #include "src/common/pmix_iof.h" #include "src/event/pmix_event.h" #include "src/hwloc/pmix_hwloc.h" #include "src/include/pmix_globals.h" #include "src/mca/bfrops/base/base.h" #include "src/mca/gds/base/base.h" #include "src/mca/pcompress/base/base.h" #include "src/mca/preg/preg.h" #include "src/mca/ptl/base/base.h" #include "src/runtime/pmix_progress_threads.h" #include "src/runtime/pmix_rte.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #include "src/util/pmix_show_help.h" #include "pmix_client_ops.h" #include "src/server/pmix_server_ops.h" #define PMIX_MAX_RETRIES 10 static void _notify_complete(pmix_status_t status, void *cbdata) { pmix_event_chain_t *chain = (pmix_event_chain_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_ACQUIRE_OBJECT(chain); PMIX_RELEASE(chain); } static void pmix_client_notify_recv(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_status_t rc; int32_t cnt; pmix_cmd_t cmd; pmix_event_chain_t *chain; size_t ninfo; pmix_output_verbose(2, pmix_client_globals.event_output, "%s pmix:client_notify_recv - processing event", PMIX_NAME_PRINT(&pmix_globals.myid)); PMIX_HIDE_UNUSED_PARAMS(peer, hdr, cbdata); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { return; } /* start the local notification chain */ chain = PMIX_NEW(pmix_event_chain_t); if (NULL == chain) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } chain->final_cbfunc = _notify_complete; chain->final_cbdata = chain; cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &cmd, &cnt, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &chain->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } /* unpack the source of the event */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &chain->source, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } /* unpack the info that might have been provided */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } /* we always leave space for event hdlr name and a callback object */ chain->nallocated = ninfo + 2; PMIX_INFO_CREATE(chain->info, chain->nallocated); if (NULL == chain->info) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); PMIX_RELEASE(chain); return; } if (0 < ninfo) { chain->ninfo = ninfo; cnt = ninfo; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, chain->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(chain); goto error; } } /* prep the chain for processing */ pmix_prep_event_chain(chain, chain->info, ninfo, false); pmix_output_verbose(2, pmix_client_globals.event_output, "%s pmix:client_notify_recv - processing event %s, calling errhandler", PMIX_NAME_PRINT(&pmix_globals.myid), PMIx_Error_string(chain->status)); pmix_invoke_local_event_hdlr(chain); return; error: /* we always need to return */ pmix_output_verbose(2, pmix_client_globals.event_output, "%s pmix:client_notify_recv - unpack error status =%s, calling def errhandler", PMIX_NAME_PRINT(&pmix_globals.myid), PMIx_Error_string(rc)); chain = PMIX_NEW(pmix_event_chain_t); if (NULL == chain) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return; } chain->status = rc; pmix_invoke_local_event_hdlr(chain); } pmix_client_globals_t pmix_client_globals = { .myserver = NULL, .singleton = false, .pending_requests = PMIX_LIST_STATIC_INIT, .peers = PMIX_POINTER_ARRAY_STATIC_INIT, .groups = PMIX_LIST_STATIC_INIT, .get_output = -1, .get_verbose = 0, .connect_output = -1, .connect_verbose = 0, .fence_output = -1, .fence_verbose = 0, .pub_output = -1, .pub_verbose = 0, .spawn_output = -1, .spawn_verbose = 0, .event_output = -1, .event_verbose = 0, .iof_output = -1, .iof_verbose = 0, .base_output = -1, .base_verbose = 0, .group_output = -1, .group_verbose = 0, .iof_stdout = PMIX_IOF_SINK_STATIC_INIT, .iof_stderr = PMIX_IOF_SINK_STATIC_INIT }; /* callback for wait completion */ static void wait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_lock_t *lock = (pmix_lock_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(pr, hdr, buf); PMIX_ACQUIRE_OBJECT(lock); pmix_output_verbose(2, pmix_client_globals.base_output, "pmix:client wait_cbfunc received"); PMIX_POST_OBJECT(lock); PMIX_WAKEUP_THREAD(lock); } /* callback to receive job info */ static void job_data(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_status_t rc; char *nspace; int32_t cnt = 1; pmix_cb_t *cb = (pmix_cb_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(pr, hdr); PMIX_ACQUIRE_OBJECT(cb); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { cb->status = PMIX_ERROR; PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); return; } /* unpack the nspace - should be same as our own */ PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &nspace, &cnt, PMIX_STRING); if (PMIX_SUCCESS != rc || !PMIX_CHECK_NSPACE(nspace, pmix_globals.myid.nspace)) { if (PMIX_SUCCESS == rc) { rc = PMIX_ERR_INVALID_VAL; } PMIX_ERROR_LOG(rc); cb->status = PMIX_ERROR; PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); return; } /* decode it */ PMIX_GDS_STORE_JOB_INFO(cb->status, pmix_client_globals.myserver, nspace, buf); free(nspace); cb->status = PMIX_SUCCESS; PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } PMIX_EXPORT const char *PMIx_Get_version(void) { return pmix_version_string; } /* event handler registration callback */ static void mycbfn(pmix_status_t status, size_t refid, void *cbdata) { pmix_rshift_caddy_t *cd = (pmix_rshift_caddy_t *) cbdata; PMIX_ACQUIRE_OBJECT(cd); if (PMIX_SUCCESS == status) { cd->status = refid; } else { cd->status = status; } PMIX_WAKEUP_THREAD(&cd->lock); } static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { pmix_lock_t *lock = NULL; char *name = NULL; size_t n; pmix_output_verbose(2, pmix_client_globals.base_output, "[%s:%d] DEBUGGER RELEASE RECVD", pmix_globals.myid.nspace, pmix_globals.myid.rank); PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, results, nresults); if (NULL != info) { lock = NULL; for (n = 0; n < ninfo; n++) { if (0 == strncmp(info[n].key, PMIX_EVENT_RETURN_OBJECT, PMIX_MAX_KEYLEN)) { lock = (pmix_lock_t *) info[n].value.data.ptr; } else if (0 == strncmp(info[n].key, PMIX_EVENT_HDLR_NAME, PMIX_MAX_KEYLEN)) { name = info[n].value.data.string; } } /* if the object wasn't returned, then that is an error */ if (NULL == lock) { pmix_output_verbose(2, pmix_client_globals.base_output, "event handler %s failed to return object", (NULL == name) ? "NULL" : name); /* let the event handler progress */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } return; } } if (NULL != lock) { PMIX_WAKEUP_THREAD(lock); } if (NULL != cbfunc) { cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } static void _check_for_notify(pmix_info_t info[], size_t ninfo) { size_t n, m = 0; pmix_info_t *model = NULL, *library = NULL, *vers = NULL, *tmod = NULL; pmix_shift_caddy_t *scd; for (n = 0; n < ninfo; n++) { if (0 == strncmp(info[n].key, PMIX_PROGRAMMING_MODEL, PMIX_MAX_KEYLEN)) { /* we need to generate an event indicating that * a programming model has been declared */ model = &info[n]; ++m; } else if (0 == strncmp(info[n].key, PMIX_MODEL_LIBRARY_NAME, PMIX_MAX_KEYLEN)) { library = &info[n]; ++m; } else if (0 == strncmp(info[n].key, PMIX_MODEL_LIBRARY_VERSION, PMIX_MAX_KEYLEN)) { vers = &info[n]; ++m; } else if (0 == strncmp(info[n].key, PMIX_THREADING_MODEL, PMIX_MAX_KEYLEN)) { tmod = &info[n]; ++m; } } if (0 < m) { /* notify anyone listening that a model has been declared */ scd = PMIX_NEW(pmix_shift_caddy_t); if (NULL == scd) { /* nothing we can do */ return; } PMIX_INFO_CREATE(scd->info, m + 1); if (NULL == scd->info) { PMIX_RELEASE(scd); return; } scd->infocopy = true; scd->ninfo = m + 1; n = 0; if (NULL != model) { PMIX_INFO_XFER(&scd->info[n], model); ++n; } if (NULL != library) { PMIX_INFO_XFER(&scd->info[n], library); ++n; } if (NULL != vers) { PMIX_INFO_XFER(&scd->info[n], vers); ++n; } if (NULL != tmod) { PMIX_INFO_XFER(&scd->info[n], tmod); ++n; } /* mark that it is not to go to any default handlers */ PMIX_INFO_LOAD(&scd->info[n], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); scd->status = PMIX_MODEL_DECLARED; scd->proc = &pmix_globals.myid; scd->range = PMIX_RANGE_PROC_LOCAL; scd->cbfunc.opcbfn = NULL; scd->cbdata = NULL; PMIX_THREADSHIFT(scd, pmix_internal_notify_event); PMIX_WAIT_THREAD(&scd->lock); PMIX_RELEASE(scd); } } static void client_iof_handler(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_peer_t *peer = (pmix_peer_t *) pr; pmix_proc_t source; pmix_iof_channel_t channel; pmix_byte_object_t bo; int32_t cnt; pmix_status_t rc; size_t refid, ninfo = 0; pmix_iof_req_t *req; pmix_info_t *info = NULL; PMIX_HIDE_UNUSED_PARAMS(hdr, cbdata); PMIX_ACQUIRE_OBJECT(peer); pmix_output_verbose(2, pmix_client_globals.iof_output, "recvd IOF with %d bytes", (int) buf->bytes_used); /* if the buffer is empty, they are simply closing the socket */ if (0 == buf->bytes_used) { return; } PMIX_BYTE_OBJECT_CONSTRUCT(&bo); cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &source, &cnt, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &channel, &cnt, PMIX_IOF_CHANNEL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &refid, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return; } if (0 < ninfo) { PMIX_INFO_CREATE(info, ninfo); cnt = ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } } cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &bo, &cnt, PMIX_BYTE_OBJECT); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto cleanup; } /* lookup the handler for this IOF package */ req = (pmix_iof_req_t *) pmix_pointer_array_get_item(&pmix_globals.iof_requests, refid); if (NULL != req && NULL != req->cbfunc) { req->cbfunc(refid, channel, &source, &bo, info, ninfo); } else { /* otherwise, simply write it out to the specified std IO channel */ if (NULL != bo.bytes && 0 < bo.size) { pmix_iof_write_output(&source, channel, &bo); } } cleanup: /* cleanup the memory */ if (0 < ninfo) { PMIX_INFO_FREE(info, ninfo); } PMIX_BYTE_OBJECT_DESTRUCT(&bo); } static int client_init_cntr = 0; pmix_status_t PMIx_Init(pmix_proc_t *proc, pmix_info_t info[], size_t ninfo) { char *evar, *suri; pmix_status_t rc = PMIX_SUCCESS; pmix_cb_t cb; pmix_buffer_t *req; pmix_cmd_t cmd = PMIX_REQ_CMD; pmix_proc_t wildcard; pmix_info_t ginfo, evinfo[4]; pmix_lock_t releaselock; size_t n; bool found; pmix_ptl_posted_recv_t *rcv; pid_t pid; pmix_kval_t *kptr, *kv; pmix_iof_req_t *iofreq; pmix_rshift_caddy_t *cd; pmix_shift_caddy_t *scd; bool unreach = false; // check if an init has been called if (pmix_atomic_test_and_set(&pmix_globals.init_called)) { // track the ref count pmix_atomic_fetch_add(&client_init_cntr, 1); // did the prior call get far enough? We might be in a tight // race between multiple calls to PMIx_Init - bad programming // technique, but all we can do is try to protect against it if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } // return our proc name if they requested it if (NULL != proc) { PMIX_LOAD_PROCID(proc, pmix_globals.myid.nspace, pmix_globals.myid.rank); } /* we also need to check the info keys to see if something needs * to be done with them - e.g., to notify another library that we * also have called init */ if (NULL != info) { _check_for_notify(info, ninfo); } /* if we were given connection info, then we should try * to connect if are currently unconnected */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { rc = pmix_ptl.connect_to_peer((struct pmix_peer_t *) pmix_client_globals.myserver, info, ninfo, &suri); if (PMIX_SUCCESS == rc) { pmix_client_globals.singleton = false; free(suri); } } return PMIX_SUCCESS; } else { pmix_atomic_fetch_add(&client_init_cntr, 1); } /* backward compatibility fix - remove any directive to use * the old usock component so we avoid a warning message */ if (NULL != (evar = getenv("PMIX_MCA_ptl"))) { if (0 == strcmp(evar, "usock")) { /* we cannot support a usock-only environment */ fprintf(stderr, "-------------------------------------------------------------------\n"); fprintf(stderr, "PMIx no longer supports the \"usock\" transport for client-server\n"); fprintf(stderr, "communication. A directive was detected that only allows that mode.\n"); fprintf(stderr, "We cannot continue - please remove that constraint and try again.\n"); fprintf(stderr, "-------------------------------------------------------------------\n"); return PMIX_ERR_INIT; } /* anything else should just be cleared */ pmix_unsetenv("PMIX_MCA_ptl", &environ); } /* setup the runtime - this init's the globals, * opens and initializes the required frameworks */ rc = pmix_rte_init(PMIX_PROC_CLIENT, info, ninfo, pmix_client_notify_recv); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* setup the base verbosity */ if (0 < pmix_client_globals.base_verbose) { /* set default output */ pmix_client_globals.base_output = pmix_output_open(NULL); pmix_output_set_verbosity(pmix_client_globals.base_output, pmix_client_globals.base_verbose); } /* setup the IO Forwarding recv */ rcv = PMIX_NEW(pmix_ptl_posted_recv_t); rcv->tag = PMIX_PTL_TAG_IOF; rcv->cbfunc = client_iof_handler; /* add it to the end of the list of recvs */ pmix_list_append(&pmix_ptl_base.posted_recvs, &rcv->super); /* create the default iof handler */ iofreq = PMIX_NEW(pmix_iof_req_t); iofreq->channels = PMIX_FWD_STDOUT_CHANNEL | PMIX_FWD_STDERR_CHANNEL | PMIX_FWD_STDDIAG_CHANNEL; pmix_pointer_array_set_item(&pmix_globals.iof_requests, 0, iofreq); /* define the sinks */ PMIX_IOF_SINK_DEFINE(&pmix_client_globals.iof_stdout, &pmix_globals.myid, 1, PMIX_FWD_STDOUT_CHANNEL, pmix_iof_write_handler); PMIX_IOF_SINK_DEFINE(&pmix_client_globals.iof_stderr, &pmix_globals.myid, 2, PMIX_FWD_STDERR_CHANNEL, pmix_iof_write_handler); /* setup the globals */ PMIX_CONSTRUCT(&pmix_client_globals.pending_requests, pmix_list_t); PMIX_CONSTRUCT(&pmix_client_globals.peers, pmix_pointer_array_t); pmix_pointer_array_init(&pmix_client_globals.peers, 1, INT_MAX, 1); pmix_client_globals.myserver = PMIX_NEW(pmix_peer_t); if (NULL == pmix_client_globals.myserver) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } pmix_client_globals.myserver->nptr = PMIX_NEW(pmix_namespace_t); if (NULL == pmix_client_globals.myserver->nptr) { PMIX_RELEASE(pmix_client_globals.myserver); PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } pmix_client_globals.myserver->info = PMIX_NEW(pmix_rank_info_t); if (NULL == pmix_client_globals.myserver->info) { PMIX_RELEASE(pmix_client_globals.myserver); PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } pmix_output_verbose(2, pmix_client_globals.base_output, "pmix: init called"); /* see if the required info is present */ if (NULL == (evar = getenv("PMIX_NAMESPACE"))) { /* if we didn't see a PMIx server (e.g., missing envar), * then allow us to run as a singleton */ pid = getpid(); pmix_snprintf(pmix_globals.myid.nspace, PMIX_MAX_NSLEN, "singleton.%s.%lu", pmix_globals.hostname, (unsigned long) pid); pmix_globals.myid.rank = 0; if (NULL != proc) { PMIX_LOAD_PROCID(proc, pmix_globals.myid.nspace, pmix_globals.myid.rank); } pmix_globals.mypeer->nptr->nspace = strdup(pmix_globals.myid.nspace); /* define us as an IOF endpoint so any output will be printed */ pmix_globals.iof_flags.local_output = true; PMIX_CONSTRUCT(&pmix_server_globals.iof, pmix_list_t); PMIX_CONSTRUCT(&pmix_server_globals.iof_residuals, pmix_list_t); } else { if (NULL != proc) { PMIX_LOAD_NSPACE(proc->nspace, evar); } PMIX_LOAD_NSPACE(pmix_globals.myid.nspace, evar); /* set the global pmix_namespace_t object for our peer */ pmix_globals.mypeer->nptr->nspace = strdup(evar); /* we also require our rank */ if (NULL == (evar = getenv("PMIX_RANK"))) { /* let the caller know that the server isn't available yet */ PMIX_ERROR_LOG(PMIX_ERR_DATA_VALUE_NOT_FOUND); return PMIX_ERR_DATA_VALUE_NOT_FOUND; } else { pmix_globals.myid.rank = strtol(evar, NULL, 10); } if (NULL != proc) { proc->rank = pmix_globals.myid.rank; } } pmix_globals.pindex = -1; /* setup a rank_info object for us */ pmix_globals.mypeer->info = PMIX_NEW(pmix_rank_info_t); if (NULL == pmix_globals.mypeer->info) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); return PMIX_ERR_NOMEM; } pmix_globals.mypeer->info->pname.nspace = strdup(pmix_globals.myid.nspace); pmix_globals.mypeer->info->pname.rank = pmix_globals.myid.rank; PMIX_LOAD_PROCID(pmix_globals.myidval.data.proc, pmix_globals.myid.nspace, pmix_globals.myid.rank); pmix_globals.myrankval.data.rank = pmix_globals.myid.rank; pmix_globals.mypeer->info->realuid = pmix_globals.realuid; pmix_globals.mypeer->info->uid = pmix_globals.uid; pmix_globals.mypeer->info->realgid = pmix_globals.realgid; pmix_globals.mypeer->info->gid = pmix_globals.gid; pmix_globals.mypeer->info->pid = pmix_globals.pid; /* select our psec compat module - the selection will be based * on the corresponding envars that should have been passed * to us at launch */ evar = getenv("PMIX_SECURITY_MODE"); pmix_globals.mypeer->nptr->compat.psec = pmix_psec_base_assign_module(evar); if (NULL == pmix_globals.mypeer->nptr->compat.psec) { PMIX_ERROR_LOG(PMIX_ERR_INIT); return PMIX_ERR_INIT; } /* the server will be using the same */ pmix_client_globals.myserver->nptr->compat.psec = pmix_globals.mypeer->nptr->compat.psec; /* set the buffer type - the selection will be based * on the corresponding envars that should have been passed * to us at launch */ evar = getenv("PMIX_BFROP_BUFFER_TYPE"); if (NULL == evar) { /* just set to our default */ pmix_globals.mypeer->nptr->compat.type = pmix_bfrops_globals.default_type; } else if (0 == strcmp(evar, "PMIX_BFROP_BUFFER_FULLY_DESC")) { pmix_globals.mypeer->nptr->compat.type = PMIX_BFROP_BUFFER_FULLY_DESC; } else { pmix_globals.mypeer->nptr->compat.type = PMIX_BFROP_BUFFER_NON_DESC; } /* the server will be using the same */ pmix_client_globals.myserver->nptr->compat.type = pmix_globals.mypeer->nptr->compat.type; /* select the gds compat module we will use to interact with * our server- the selection will be based * on the corresponding envars that should have been passed * to us at launch */ evar = getenv("PMIX_GDS_MODULE"); if (NULL != evar) { PMIX_INFO_LOAD(&ginfo, PMIX_GDS_MODULE, evar, PMIX_STRING); pmix_client_globals.myserver->nptr->compat.gds = pmix_gds_base_assign_module(&ginfo, 1); PMIX_INFO_DESTRUCT(&ginfo); } else { pmix_client_globals.myserver->nptr->compat.gds = pmix_gds_base_assign_module(NULL, 0); } if (NULL == pmix_client_globals.myserver->nptr->compat.gds) { PMIX_ERROR_LOG(PMIX_ERR_INIT); return PMIX_ERR_INIT; } /* now select a GDS module for our own internal use - the user may * have passed down a directive for this purpose. If they did, then * use it. Otherwise, we want the "hash" module */ found = false; if (info != NULL) { for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_GDS_MODULE)) { PMIX_INFO_LOAD(&ginfo, PMIX_GDS_MODULE, info[n].value.data.string, PMIX_STRING); found = true; break; } } } if (!found) { PMIX_INFO_LOAD(&ginfo, PMIX_GDS_MODULE, "hash", PMIX_STRING); } pmix_globals.mypeer->nptr->compat.gds = pmix_gds_base_assign_module(&ginfo, 1); if (NULL == pmix_globals.mypeer->nptr->compat.gds) { PMIX_INFO_DESTRUCT(&ginfo); PMIX_ERROR_LOG(PMIX_ERR_INIT); return PMIX_ERR_INIT; } PMIX_INFO_DESTRUCT(&ginfo); /* attempt to connect to a server */ rc = pmix_ptl.connect_to_peer((struct pmix_peer_t *) pmix_client_globals.myserver, info, ninfo, &suri); if (PMIX_SUCCESS != rc) { /* mark that we couldn't connect to a server */ pmix_client_globals.singleton = true; /* initialize our data values */ rc = pmix_tool_init_info(); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* set our server ID to be ourselves */ pmix_client_globals.myserver->info->pname.nspace = strdup(pmix_globals.myid.nspace); pmix_client_globals.myserver->info->pname.rank = pmix_globals.myid.rank; pmix_client_globals.myserver->nptr->nspace = strdup(pmix_globals.myid.nspace); pmix_client_globals.myserver->info->uid = pmix_globals.uid; pmix_client_globals.myserver->info->gid = pmix_globals.gid; // set the compat entries to the same as mine memcpy(&pmix_client_globals.myserver->nptr->compat, &pmix_globals.mypeer->nptr->compat, sizeof(pmix_personality_t)); /* mark that the server is unreachable */ unreach = true; } else { /* send a request for our job info - we do this as a non-blocking * transaction because some systems cannot handle very large * blocking operations and error out if we try them. */ req = PMIX_NEW(pmix_buffer_t); PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, req, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(req); free(suri); return rc; } /* send to the server */ PMIX_CONSTRUCT(&cb, pmix_cb_t); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, req, job_data, (void *) &cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); free(suri); return rc; } /* wait for the data to return */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; PMIX_DESTRUCT(&cb); if (PMIX_SUCCESS != rc) { return rc; } } /* store our server's ID */ if (!pmix_client_globals.singleton && NULL != pmix_client_globals.myserver && NULL != pmix_client_globals.myserver->info) { kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_SERVER_NSPACE); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_STRING; kptr->value->data.string = strdup(pmix_client_globals.myserver->info->pname.nspace); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } PMIX_RELEASE(kptr); // maintain accounting kptr = PMIX_NEW(pmix_kval_t); kptr->key = strdup(PMIX_SERVER_RANK); PMIX_VALUE_CREATE(kptr->value, 1); kptr->value->type = PMIX_PROC_RANK; kptr->value->data.rank = pmix_client_globals.myserver->info->pname.rank; PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); PMIX_RELEASE(kptr); // maintain accounting if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* store the URI for subsequent lookups */ PMIX_KVAL_NEW(kptr, PMIX_SERVER_URI); kptr->value->type = PMIX_STRING; pmix_asprintf(&kptr->value->data.string, "%s.%u;%s", pmix_client_globals.myserver->info->pname.nspace, pmix_client_globals.myserver->info->pname.rank, suri); free(suri); PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, PMIX_INTERNAL, kptr); PMIX_RELEASE(kptr); // maintain accounting if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } // enable show_help subsystem pmix_atomic_store_int(&pmix_show_help_enabled, 1); /* retrieve our topology as a number of APIs utilize it */ if (!pmix_globals.external_topology && NULL == pmix_globals.topology.topology) { rc = pmix_hwloc_setup_topology(NULL, 0); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } /* look for a debugger attach key */ pmix_strncpy(wildcard.nspace, pmix_globals.myid.nspace, PMIX_MAX_NSLEN); wildcard.rank = PMIX_RANK_WILDCARD; PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.proc = &wildcard; cb.key = PMIX_DEBUG_STOP_IN_INIT; cb.scope = PMIX_GLOBAL; cb.copy = true; PMIX_INFO_LOAD(&ginfo, PMIX_OPTIONAL, NULL, PMIX_BOOL); // no memory allocated cb.info = &ginfo; cb.ninfo = 1; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb); if (PMIX_SUCCESS == rc) { pmix_rank_t rank; kv = (pmix_kval_t*)pmix_list_remove_first(&cb.kvs); PMIX_DESTRUCT(&cb); if (PMIX_BOOL == kv->value->type) { if (kv->value->data.flag) { rank = PMIX_RANK_WILDCARD; } else { rank = PMIX_RANK_UNDEF; } } else if (PMIX_PROC_RANK == kv->value->type) { rank = kv->value->data.rank; } else { pmix_output(0, "DEBUG STOP_IN_INIT FOUND, BUT VALUE UNRECOGNIZED: %s", PMIx_Data_type_string(kv->value->type)); return PMIX_ERR_BAD_PARAM; } PMIX_RELEASE(kv); // done with this value pmix_output_verbose(2, pmix_client_globals.base_output, "[%s:%d] RECEIVED %s FOR RANK %s (%s)", pmix_globals.myid.nspace, pmix_globals.myid.rank, PMIx_Get_attribute_name(kv->key), PMIX_RANK_PRINT(rank), PMIx_Data_type_string(kv->value->type)); /* if the value was found and we are involved, then we need to wait * for debugger attach here */ if (PMIX_RANK_WILDCARD == rank || pmix_globals.myid.rank == rank) { /* register for the debugger release notification */ PMIX_CONSTRUCT_LOCK(&releaselock); PMIX_INFO_LOAD(&evinfo[0], PMIX_EVENT_RETURN_OBJECT, &releaselock, PMIX_POINTER); PMIX_INFO_LOAD(&evinfo[1], PMIX_EVENT_HDLR_NAME, "WAIT-FOR-DEBUGGER", PMIX_STRING); PMIX_INFO_LOAD(&evinfo[2], PMIX_EVENT_ONESHOT, NULL, PMIX_BOOL); pmix_output_verbose(2, pmix_client_globals.event_output, "[%s:%d] REGISTERING WAIT FOR DEBUGGER", pmix_globals.myid.nspace, pmix_globals.myid.rank); cd = PMIX_NEW(pmix_rshift_caddy_t); cd->codes = malloc(sizeof(int)); cd->codes[0] = PMIX_DEBUGGER_RELEASE; cd->ncodes = 1; cd->info = evinfo; cd->ninfo = 3; cd->evhdlr = notification_fn; cd->evregcbfn = mycbfn; cd->cbdata = cd; PMIX_RETAIN(cd); // so pmix_internal_reg_event_hdlr doesn't wind up releasing it PMIX_THREADSHIFT(cd, pmix_internal_reg_event_hdlr); PMIX_WAIT_THREAD(&cd->lock); rc = cd->status; PMIX_RELEASE(cd); PMIX_INFO_DESTRUCT(&evinfo[0]); PMIX_INFO_DESTRUCT(&evinfo[1]); PMIX_INFO_DESTRUCT(&evinfo[2]); if (0 > rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT_LOCK(&releaselock); return rc; } /* notify the host that we are waiting */ PMIX_INFO_LOAD(&evinfo[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&evinfo[1], PMIX_BREAKPOINT, "pmix-init", PMIX_STRING); PMIX_INFO_LOAD(&evinfo[2], PMIX_EVENT_DO_NOT_CACHE, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&evinfo[3], PMIX_EVENT_CUSTOM_RANGE, pmix_client_globals.myserver, PMIX_PROC); scd = PMIX_NEW(pmix_shift_caddy_t); scd->status = PMIX_READY_FOR_DEBUG; scd->proc = &pmix_globals.myid; scd->range = PMIX_RANGE_CUSTOM; scd->info = evinfo; scd->ninfo = 4; scd->cbfunc.opcbfn = NULL; scd->cbdata = NULL; PMIX_THREADSHIFT(scd, pmix_internal_notify_event); PMIX_WAIT_THREAD(&scd->lock); rc = scd->status; PMIX_RELEASE(scd); PMIX_INFO_DESTRUCT(&evinfo[0]); PMIX_INFO_DESTRUCT(&evinfo[1]); PMIX_INFO_DESTRUCT(&evinfo[2]); PMIX_INFO_DESTRUCT(&evinfo[3]); if (PMIX_SUCCESS != rc) { // failed to notify ready-for-debug PMIX_ERROR_LOG(rc); PMIX_DESTRUCT_LOCK(&releaselock); return rc; } /* wait for release to arrive */ PMIX_WAIT_THREAD(&releaselock); PMIX_DESTRUCT_LOCK(&releaselock); } } else { pmix_output_verbose(2, pmix_client_globals.base_output, "[%s:%d] NO DEBUGGER WAITING", pmix_globals.myid.nspace, pmix_globals.myid.rank); PMIX_DESTRUCT(&cb); } /* check to see if we need to notify anyone */ if (NULL != info) { _check_for_notify(info, ninfo); } /* register the client supported attrs */ rc = pmix_register_client_attrs(); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } // mark ourselves as initialized pmix_atomic_set_bool(&pmix_globals.initialized); if (unreach) { return PMIX_ERR_UNREACH; } else { return PMIX_SUCCESS; } } PMIX_EXPORT int PMIx_Initialized(void) { return pmix_atomic_check_bool(&pmix_globals.initialized); } typedef struct { pmix_lock_t lock; pmix_event_t ev; bool active; } pmix_client_timeout_t; /* timer callback */ static void fin_timeout(int sd, short args, void *cbdata) { pmix_client_timeout_t *tev; tev = (pmix_client_timeout_t *) cbdata; pmix_output_verbose(2, pmix_client_globals.base_output, "pmix:client finwait timeout fired"); PMIX_HIDE_UNUSED_PARAMS(sd, args); if (tev->active) { tev->active = false; PMIX_WAKEUP_THREAD(&tev->lock); } } /* callback for finalize completion */ static void finwait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_client_timeout_t *tev; tev = (pmix_client_timeout_t *) cbdata; pmix_output_verbose(2, pmix_client_globals.base_output, "pmix:client finwait_cbfunc received"); PMIX_HIDE_UNUSED_PARAMS(pr, hdr, buf); if (tev->active) { tev->active = false; PMIX_WAKEUP_THREAD(&tev->lock); } } PMIX_EXPORT pmix_status_t PMIx_Finalize(const pmix_info_t info[], size_t ninfo) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_FINALIZE_CMD; pmix_status_t rc; size_t n; pmix_client_timeout_t tev; struct timeval tv; pmix_peer_t *peer; int i; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } i = pmix_atomic_fetch_add(&client_init_cntr, -1); if (1 < i) { return PMIX_SUCCESS; } // mark we are no longer initialized pmix_atomic_unset_bool(&pmix_globals.initialized); pmix_globals.init_called = false; pmix_output_verbose(2, pmix_client_globals.base_output, "%s:%d pmix:client finalize called", pmix_globals.myid.nspace, pmix_globals.myid.rank); /* mark that I called finalize */ pmix_globals.mypeer->finalized = true; if (0 <= pmix_client_globals.myserver->sd) { /* check to see if we are supposed to execute a * blocking fence prior to actually finalizing */ if (NULL != info && 0 < ninfo) { for (n = 0; n < ninfo; n++) { if (0 == strcmp(PMIX_EMBED_BARRIER, info[n].key)) { if (PMIX_INFO_TRUE(&info[n])) { rc = PMIx_Fence(NULL, 0, NULL, 0); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } break; } } } /* setup a cmd message to notify the PMIx * server that we are normally terminating */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } pmix_output_verbose(2, pmix_client_globals.base_output, "%s:%d pmix:client sending finalize sync to server", pmix_globals.myid.nspace, pmix_globals.myid.rank); /* setup a timer to protect ourselves should the server be unable * to answer for some reason */ PMIX_CONSTRUCT_LOCK(&tev.lock); pmix_event_assign(&tev.ev, pmix_globals.evbase, -1, 0, fin_timeout, &tev); tev.active = true; PMIX_POST_OBJECT(&tev); tv.tv_sec = pmix_server_client_fintime; tv.tv_usec = 0; pmix_event_add(&tev.ev, &tv); /* send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, finwait_cbfunc, (void *) &tev); if (PMIX_SUCCESS != rc) { return rc; } /* wait for the ack to return */ PMIX_WAIT_THREAD(&tev.lock); PMIX_DESTRUCT_LOCK(&tev.lock); if (tev.active) { pmix_event_del(&tev.ev); } pmix_output_verbose(2, pmix_client_globals.base_output, "%s:%d pmix:client finalize sync received", pmix_globals.myid.nspace, pmix_globals.myid.rank); } /* wait here until all active events have been processed */ PMIx_Progress_thread_stop(NULL, 0); /* flush anything that is still trying to be written out */ pmix_iof_static_dump_output(&pmix_client_globals.iof_stdout); pmix_iof_static_dump_output(&pmix_client_globals.iof_stderr); PMIX_DESTRUCT(&pmix_client_globals.iof_stdout); PMIX_DESTRUCT(&pmix_client_globals.iof_stderr); PMIX_LIST_DESTRUCT(&pmix_client_globals.pending_requests); for (i = 0; i < pmix_client_globals.peers.size; i++) { peer = (pmix_peer_t *) pmix_pointer_array_get_item(&pmix_client_globals.peers, i); if (NULL != peer) { PMIX_RELEASE(peer); } } PMIX_DESTRUCT(&pmix_client_globals.peers); if (pmix_client_globals.singleton) { PMIX_LIST_DESTRUCT(&pmix_server_globals.iof); PMIX_LIST_DESTRUCT(&pmix_server_globals.iof_residuals); } if (0 <= pmix_client_globals.myserver->sd) { CLOSE_THE_SOCKET(pmix_client_globals.myserver->sd); } if (NULL != pmix_client_globals.myserver) { PMIX_RELEASE(pmix_client_globals.myserver); } pmix_rte_finalize(); if (NULL != pmix_globals.mypeer) { PMIX_RELEASE(pmix_globals.mypeer); } /* finalize the class/object system */ pmix_class_finalize(); return PMIX_SUCCESS; } PMIX_EXPORT pmix_status_t PMIx_Abort(int flag, const char msg[], pmix_proc_t procs[], size_t nprocs) { pmix_buffer_t *bfr; pmix_cmd_t cmd = PMIX_ABORT_CMD; pmix_status_t rc; pmix_lock_t reglock; pmix_output_verbose(2, pmix_client_globals.base_output, "pmix:client abort called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* if we are a server (and not a tool), then try to * handle this directly */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { if (NULL != pmix_host_server.abort) { rc = pmix_host_server.abort(&pmix_globals.myid, pmix_globals.mypeer->info->server_object, flag, msg, procs, nprocs, NULL, NULL); } else { rc = PMIX_ERR_NOT_SUPPORTED; } return rc; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } /* create a buffer to hold the message */ bfr = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, bfr, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); return rc; } /* pack the status flag */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, bfr, &flag, 1, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); return rc; } /* pack the string message - a NULL is okay */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, bfr, &msg, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); return rc; } /* pack the number of procs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, bfr, &nprocs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); return rc; } /* pack any provided procs */ if (0 < nprocs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, bfr, procs, nprocs, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(bfr); return rc; } } /* send to the server */ PMIX_CONSTRUCT_LOCK(®lock); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, bfr, wait_cbfunc, (void *) ®lock); if (PMIX_SUCCESS != rc) { PMIX_DESTRUCT_LOCK(®lock); return rc; } /* wait for the release */ PMIX_WAIT_THREAD(®lock); PMIX_DESTRUCT_LOCK(®lock); return PMIX_SUCCESS; } static void _putfn(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_status_t rc; pmix_kval_t *kv = NULL; uint8_t *tmp; size_t len; /* need to acquire the cb object from its originating thread */ PMIX_ACQUIRE_OBJECT(cb); PMIX_HIDE_UNUSED_PARAMS(sd, args); if (PMIX_CHECK_KEY(cb, PMIX_QUALIFIED_VALUE)) { /* type must be a data array */ if (PMIX_DATA_ARRAY != cb->value->type) { rc = PMIX_ERR_BAD_PARAM; goto done; } } /* setup to xfer the data */ kv = PMIX_NEW(pmix_kval_t); kv->key = strdup(cb->key); // need to copy as the input belongs to the user kv->value = (pmix_value_t *) malloc(sizeof(pmix_value_t)); if (PMIX_STRING_SIZE_CHECK(cb->value)) { /* compress large strings */ if (pmix_compress.compress_string(cb->value->data.string, &tmp, &len)) { if (NULL == tmp) { PMIX_ERROR_LOG(PMIX_ERR_NOMEM); rc = PMIX_ERR_NOMEM; PMIX_ERROR_LOG(rc); goto done; } kv->value->type = PMIX_COMPRESSED_STRING; kv->value->data.bo.bytes = (char *) tmp; kv->value->data.bo.size = len; rc = PMIX_SUCCESS; } else { PMIX_BFROPS_VALUE_XFER(rc, pmix_globals.mypeer, kv->value, cb->value); } } else { PMIX_BFROPS_VALUE_XFER(rc, pmix_globals.mypeer, kv->value, cb->value); } if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto done; } /* store it */ PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, &pmix_globals.myid, cb->scope, kv); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } /* mark that fresh values have been stored so we know * to commit them later */ pmix_globals.commits_pending = true; done: if (NULL != kv) { PMIX_RELEASE(kv); // maintain accounting } cb->pstatus = rc; /* post the data so the receiving thread can acquire it */ PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } PMIX_EXPORT pmix_status_t PMIx_Put(pmix_scope_t scope, const char key[], pmix_value_t *val) { pmix_cb_t *cb; pmix_status_t rc; pmix_output_verbose(2, pmix_client_globals.base_output, "pmix: executing put for key %s type %s", key, PMIx_Data_type_string(val->type)); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (NULL == key || PMIX_MAX_KEYLEN < pmix_keylen(key)) { return PMIX_ERR_BAD_PARAM; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object */ cb = PMIX_NEW(pmix_cb_t); cb->scope = scope; cb->key = (char *) key; cb->value = val; /* pass this into the event library for thread protection */ PMIX_THREADSHIFT(cb, _putfn); /* wait for the result */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->pstatus; PMIX_RELEASE(cb); return rc; } static void _commitfn(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_status_t rc; pmix_scope_t scope; pmix_buffer_t *msgout, bkt; pmix_cmd_t cmd = PMIX_COMMIT_CMD; pmix_kval_t *kv; /* need to acquire the cb object from its originating thread */ PMIX_ACQUIRE_OBJECT(cb); PMIX_HIDE_UNUSED_PARAMS(sd, args); msgout = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msgout, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msgout); goto error; } /* if we haven't already done it, ensure we have committed our values */ if (pmix_globals.commits_pending) { /* fetch and pack the local values */ scope = PMIX_LOCAL; /* allow the GDS module to pass us this info * as a local connection as this data would * only go to another local client */ cb->proc = &pmix_globals.myid; cb->scope = scope; cb->copy = false; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, cb); if (PMIX_SUCCESS == rc) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msgout, &scope, 1, PMIX_SCOPE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msgout); goto error; } PMIX_CONSTRUCT(&bkt, pmix_buffer_t); PMIX_LIST_FOREACH(kv, &cb->kvs, pmix_kval_t) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, &bkt, kv, 1, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&bkt); PMIX_RELEASE(msgout); goto error; } } /* now pack the result */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msgout, &bkt, 1, PMIX_BUFFER); PMIX_DESTRUCT(&bkt); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msgout); goto error; } } /* fetch and pack the remote values */ scope = PMIX_REMOTE; /* we need real copies here as this data will * go to remote procs - so a connection will * not suffice */ cb->proc = &pmix_globals.myid; cb->scope = scope; cb->copy = true; PMIX_LIST_DESTRUCT(&cb->kvs); PMIX_CONSTRUCT(&cb->kvs, pmix_list_t); PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, cb); if (PMIX_SUCCESS == rc) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msgout, &scope, 1, PMIX_SCOPE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msgout); goto error; } PMIX_CONSTRUCT(&bkt, pmix_buffer_t); PMIX_LIST_FOREACH(kv, &cb->kvs, pmix_kval_t) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, &bkt, kv, 1, PMIX_KVAL); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_DESTRUCT(&bkt); PMIX_RELEASE(msgout); goto error; } } /* now pack the result */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msgout, &bkt, 1, PMIX_BUFFER); PMIX_DESTRUCT(&bkt); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msgout); goto error; } } /* record that all committed data to-date has been sent */ pmix_globals.commits_pending = false; } /* always send, even if we have nothing to contribute, so the server knows * that we contributed whatever we had */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msgout, wait_cbfunc, (void *) &cb->lock); if (PMIX_SUCCESS == rc) { /* we should wait for the callback, so don't * modify the active flag */ cb->pstatus = PMIX_SUCCESS; return; } error: cb->pstatus = rc; /* post the data so the receiving thread can acquire it */ PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } PMIX_EXPORT pmix_status_t PMIx_Commit(void) { pmix_cb_t *cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we are a singleton, there is nothing to do */ if (pmix_client_globals.singleton) { return PMIX_SUCCESS; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* if we are a server (but not a tool), or we aren't connected, don't attempt to send */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { return PMIX_SUCCESS; // not an error } if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } /* create a callback object */ cb = PMIX_NEW(pmix_cb_t); /* pass this into the event library for thread protection */ PMIX_THREADSHIFT(cb, _commitfn); /* wait for the result */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->pstatus; PMIX_RELEASE(cb); return rc; } pmix-6.1.1~rc2/src/client/pmix_client_get.c0000664000175000017500000014261515203536752021071 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2021 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2022 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "src/class/pmix_list.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/gds/gds.h" #include "src/mca/pcompress/base/base.h" #include "src/mca/ptl/base/base.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_name_fns.h" #include "src/util/pmix_output.h" #include "pmix_client_ops.h" static pmix_buffer_t *_pack_get(pmix_cb_t *cb, pmix_rank_t rank, pmix_cmd_t cmd); static void get_data(int sd, short args, void *cbdata); static void _getnb_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static void _value_cbfunc(pmix_status_t status, pmix_value_t *kv, void *cbdata); static pmix_status_t process_values(pmix_cb_t *cb); static pmix_status_t refresh_cache(const pmix_proc_t *proc); static pmix_status_t process_request(const pmix_proc_t *proc, const char key[], const pmix_info_t info[], size_t ninfo, pmix_get_logic_t *lg, pmix_value_t **val) { pmix_status_t rc; pmix_value_t *ival; size_t n, nprocs; pmix_proc_t *procs; /* if the proc is NULL, then the caller is assuming * that the key is universally unique within the caller's * own nspace. This most likely indicates that the code * was originally written for a legacy version of PMI. * * If the key is NULL, then the caller wants all * data from the specified proc. Again, this likely * indicates use of a legacy version of PMI. * * Either case is supported. However, we don't currently * support the case where -both- values are NULL */ if (NULL == proc && NULL == key) { pmix_output_verbose(2, pmix_client_globals.get_output, "pmix: get_nb value error - both proc and key are NULL"); return PMIX_ERR_BAD_PARAM; } /* if the key is NULL, the rank cannot be WILDCARD as * we cannot return all info from every rank */ if (NULL != proc && PMIX_RANK_WILDCARD == proc->rank && NULL == key) { pmix_output_verbose(2, pmix_client_globals.get_output, "pmix: get_nb value error - WILDCARD rank and key is NULL"); return PMIX_ERR_BAD_PARAM; } if (NULL != key) { /* see if they are asking about a specific type of info */ if (pmix_check_node_info(key)) { lg->nodeinfo = true; } else if (pmix_check_app_info(key)) { lg->appinfo = true; } else if (pmix_check_session_info(key)) { lg->sessioninfo = true; } } for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_GET_POINTER_VALUES)) { /* they want a pointer to the answer */ if (NULL == val) { return PMIX_ERR_BAD_PARAM; } lg->pntrval = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_GET_STATIC_VALUES)) { /* they want a static response (i.e., they provided the storage) */ if (NULL == val || NULL == *val) { return PMIX_ERR_BAD_PARAM; } lg->stval = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_OPTIONAL)) { lg->optional = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_IMMEDIATE)) { lg->immediate = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_DATA_SCOPE)) { lg->scope = info[n].value.data.scope; } else if (PMIX_CHECK_KEY(&info[n], PMIX_GET_REFRESH_CACHE)) { /* immediately query the server */ lg->refresh_cache = PMIX_INFO_TRUE(&info[n]); } else if (PMIX_CHECK_KEY(&info[n], PMIX_JOB_INFO)) { /* regardless of the default setting, they want us * to get it from the job realm */ lg->nodeinfo = false; lg->appinfo = false; lg->sessioninfo = false; /* have to let the loop continue in case there are * other relevant directives - e.g., refresh_cache */ } else if (PMIX_CHECK_KEY(&info[n], PMIX_NODE_INFO)) { /* regardless of the default setting, they want us * to get it from the node realm */ lg->nodedirective = true; lg->nodeinfo = true; lg->appinfo = false; lg->sessioninfo = false; } else if (PMIX_CHECK_KEY(&info[n], PMIX_APP_INFO)) { /* regardless of the default setting, they want us * to get it from the app realm */ lg->appdirective = true; lg->appinfo = true; lg->nodeinfo = false; lg->sessioninfo = false; } else if (PMIX_CHECK_KEY(info, PMIX_SESSION_INFO)) { /* regardless of the default setting, they want us * to get it from the session realm */ lg->sessiondirective = true; lg->sessioninfo = true; lg->nodeinfo = false; lg->appinfo = false; } else if (PMIX_CHECK_KEY(&info[n], PMIX_HOSTNAME)) { lg->hostname = info[n].value.data.string; } else if (PMIX_CHECK_KEY(&info[n], PMIX_NODEID)) { rc = PMIx_Value_get_number(&info[n].value, &lg->nodeid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_APPNUM)) { rc = PMIx_Value_get_number(&info[n].value, &lg->appnum, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } else if (PMIX_CHECK_KEY(&info[n], PMIX_SESSION_ID)) { rc = PMIx_Value_get_number(&info[n].value, &lg->sessionid, PMIX_UINT32); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } } /* see if they just want their own process ID */ if (NULL == proc && PMIx_Check_key(key, PMIX_PROCID)) { if (lg->stval) { ival = *val; ival->type = PMIX_PROC; ival->data.proc = (pmix_proc_t *) malloc(sizeof(pmix_proc_t)); PMIX_LOAD_PROCID(ival->data.proc, pmix_globals.myid.nspace, pmix_globals.myid.rank); } else if (lg->pntrval) { (*val) = &pmix_globals.myidval; } else { PMIX_VALUE_CREATE(ival, 1); if (NULL == ival) { return PMIX_ERR_NOMEM; } ival->type = PMIX_PROC; ival->data.proc = (pmix_proc_t *) malloc(sizeof(pmix_proc_t)); PMIX_LOAD_PROCID(ival->data.proc, pmix_globals.myid.nspace, pmix_globals.myid.rank); *val = ival; } return PMIX_OPERATION_SUCCEEDED; } /* see if they just want our version */ if (NULL != key && PMIx_Check_key(key, PMIX_VERSION_NUMERIC)) { if (lg->stval) { ival = *val; ival->type = PMIX_UINT32; ival->data.uint32 = PMIX_NUMERIC_VERSION; } else { PMIX_VALUE_CREATE(ival, 1); if (NULL == ival) { return PMIX_ERR_NOMEM; } ival->type = PMIX_UINT32; ival->data.uint32 = PMIX_NUMERIC_VERSION; *val = ival; } return PMIX_OPERATION_SUCCEEDED; } /* if the given proc param is NULL, or the nspace is * empty, then the caller is referencing our own nspace */ if (NULL == proc || 0 == strlen(proc->nspace)) { PMIX_LOAD_NSPACE(lg->p.nspace, pmix_globals.myid.nspace); } else { PMIX_LOAD_NSPACE(lg->p.nspace, proc->nspace); } /* if the proc param is NULL, then we are seeking a key that * must be globally unique, so communicate this to the hash * functions with the UNDEF rank */ if (NULL == proc) { // if they want node or app info, then use our rank if (lg->nodeinfo || lg->appinfo) { lg->p.rank = pmix_globals.myid.rank; } else { lg->p.rank = PMIX_RANK_UNDEF; } } else { lg->p.rank = proc->rank; } /* if they passed our nspace and an INVALID rank, and are asking * for PMIX_RANK, then they are asking for our process rank */ if (PMIX_RANK_INVALID == lg->p.rank && PMIX_CHECK_NSPACE(lg->p.nspace, pmix_globals.myid.nspace) && NULL != key && PMIx_Check_key(key, PMIX_RANK)) { if (lg->stval) { ival = *val; ival->type = PMIX_PROC_RANK; ival->data.rank = pmix_globals.myid.rank; } else if (lg->pntrval) { (*val) = &pmix_globals.myrankval; } else { PMIX_VALUE_CREATE(ival, 1); if (NULL == ival) { return PMIX_ERR_NOMEM; } ival->type = PMIX_PROC_RANK; ival->data.rank = pmix_globals.myid.rank; *val = ival; } return PMIX_OPERATION_SUCCEEDED; } /* if they passed a group in the nspace of proc, * replace it with the translated proc. */ if (!PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && proc != NULL && 0 != strlen(proc->nspace)) { rc = pmix_client_convert_group_procs(proc, 1, &procs, &nprocs); if (PMIX_SUCCESS != rc) { return rc; } if (1 < nprocs) { /* we can't support multi-proc gets */ PMIX_PROC_FREE(procs, nprocs); return PMIX_ERR_BAD_PARAM; } /* transfer it across in case it was changed */ memcpy(&lg->p, &procs[0], sizeof(pmix_proc_t)); PMIX_PROC_FREE(procs, nprocs); } /* indicate that everything was okay */ return PMIX_SUCCESS; } PMIX_EXPORT pmix_status_t PMIx_Get(const pmix_proc_t *proc, const char key[], const pmix_info_t info[], size_t ninfo, pmix_value_t **val) { pmix_cb_t *cb; pmix_get_logic_t *lg; pmix_status_t rc; pmix_output_verbose(2, pmix_client_globals.get_output, "pmix:client get for %s key %s", (NULL == proc) ? "NULL" : PMIX_NAME_PRINT(proc), (NULL == key) ? "NULL" : key); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } if (NULL != key && PMIX_MAX_KEYLEN < pmix_keylen(key)) { return PMIX_ERR_BAD_PARAM; } lg = PMIX_NEW(pmix_get_logic_t); rc = process_request(proc, key, info, ninfo, lg, val); if (PMIX_OPERATION_SUCCEEDED == rc) { /* the value has already been prepped */ PMIX_RELEASE(lg); return PMIX_SUCCESS; } else if (PMIX_SUCCESS != rc) { *val = NULL; PMIX_RELEASE(lg); return rc; } /* if we are to refresh the cache, go do that */ if (lg->refresh_cache) { rc = refresh_cache(proc); if (PMIX_SUCCESS != rc) { // couldn't refresh for some reason PMIX_RELEASE(lg); return rc; } } /* the request is good - let's go get the data */ cb = PMIX_NEW(pmix_cb_t); cb->lg = lg; cb->key = (char*)key; cb->info = (pmix_info_t*)info; cb->ninfo = ninfo; cb->cbfunc.valuefn = _value_cbfunc; cb->cbdata = cb; /* MUST threadshift here to avoid touching global * data while in the user's thread */ PMIX_THREADSHIFT(cb, get_data); /* wait for the data to be obtained */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } if (PMIX_SUCCESS == rc && NULL != cb->value) { if (lg->stval) { PMIx_Value_xfer(*val, cb->value); } else { *val = cb->value; cb->value = NULL; } } else { *val = NULL; } PMIX_RELEASE(lg); PMIX_RELEASE(cb); pmix_output_verbose(2, pmix_client_globals.get_output, "pmix:client get completed with status %s", PMIx_Error_string(rc)); return rc; } static void gcbfn(int sd, short args, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); cb->cbfunc.valuefn(cb->status, cb->value, cb->cbdata); PMIX_RELEASE(cb->lg); PMIX_RELEASE(cb); } PMIX_EXPORT pmix_status_t PMIx_Get_nb(const pmix_proc_t *proc, const char key[], const pmix_info_t info[], size_t ninfo, pmix_value_cbfunc_t cbfunc, void *cbdata) { pmix_cb_t *cb; pmix_status_t rc; pmix_get_logic_t *lg; pmix_value_t *val; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (NULL == cbfunc) { /* no way to return the result! */ return PMIX_ERR_BAD_PARAM; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } if (NULL != key && PMIX_MAX_KEYLEN < pmix_keylen(key)) { return PMIX_ERR_BAD_PARAM; } lg = PMIX_NEW(pmix_get_logic_t); rc = process_request(proc, key, info, ninfo, lg, &val); if (PMIX_OPERATION_SUCCEEDED == rc) { /* the value has already been prepped - threadshift to return result */ cb = PMIX_NEW(pmix_cb_t); cb->status = PMIX_SUCCESS; cb->value = val; cb->cbfunc.valuefn = cbfunc; cb->cbdata = cbdata; PMIX_THREADSHIFT(cb, gcbfn); PMIX_RELEASE(lg); return PMIX_SUCCESS; } else if (PMIX_SUCCESS != rc) { /* it's a true error */ PMIX_RELEASE(lg); return rc; } /* if we are to refresh the cache, go do that */ if (lg->refresh_cache) { rc = refresh_cache(proc); if (PMIX_SUCCESS != rc) { // couldn't refresh for some reason PMIX_RELEASE(lg); return rc; } } /* the request is good - let's go get the data */ cb = PMIX_NEW(pmix_cb_t); cb->lg = lg; cb->key = (char*)key; cb->info = (pmix_info_t*)info; cb->ninfo = ninfo; cb->scope = lg->scope; cb->cbfunc.valuefn = cbfunc; cb->cbdata = cbdata; // flag that we need to use an intermediate return point cb->checked = true; /* MUST threadshift here to avoid touching global * data while in the user's thread */ PMIX_THREADSHIFT(cb, get_data); pmix_output_verbose(2, pmix_client_globals.get_output, "pmix:client get_nb in progress"); return rc; } static void _value_cbfunc(pmix_status_t status, pmix_value_t *kv, void *cbdata) { pmix_cb_t *cb; pmix_status_t rc; PMIX_ACQUIRE_OBJECT(cb); cb = (pmix_cb_t *) cbdata; cb->status = status; if (PMIX_SUCCESS == status) { PMIX_BFROPS_COPY(rc, pmix_client_globals.myserver, (void **)&cb->value, kv, PMIX_VALUE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); } } PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); } static pmix_buffer_t *_pack_get(pmix_cb_t *cb, pmix_rank_t rank, pmix_cmd_t cmd) { pmix_buffer_t *msg; pmix_status_t rc; pmix_info_t *immediate; size_t n, nimm; char *nspace = cb->proc->nspace; /* nope - see if we can get it */ msg = PMIX_NEW(pmix_buffer_t); /* pack the get cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return NULL; } /* pack the request information - we'll get the entire blob * for this proc, so we don't need to pass the key */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nspace, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return NULL; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &rank, 1, PMIX_PROC_RANK); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return NULL; } /* pack the number of info structs */ if (cb->lg->add_immediate) { nimm = cb->ninfo + 1; PMIX_INFO_CREATE(immediate, nimm); for (n=0; n < cb->ninfo; n++) { PMIX_INFO_XFER(&immediate[n], &cb->info[n]); } PMIX_INFO_LOAD(&immediate[n], PMIX_IMMEDIATE, NULL, PMIX_BOOL); cb->info = immediate; cb->ninfo = nimm; cb->infocopy = true; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cb->ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return NULL; } if (0 < cb->ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cb->info, cb->ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return NULL; } } if (NULL != cb->key) { /* pack the key */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cb->key, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return NULL; } } return msg; } /* this callback is coming from the ptl recv, and thus * is occurring inside of our progress thread - hence, no * need to thread shift */ static void _getnb_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_cb_t *cb2; pmix_status_t rc, ret = PMIX_ERR_NOT_FOUND; pmix_value_t *val = NULL; int32_t cnt; pmix_kval_t *kv; pmix_get_logic_t *lg; pmix_info_t *iptr; PMIX_HIDE_UNUSED_PARAMS(pr, hdr); PMIX_ACQUIRE_OBJECT(cb); pmix_output_verbose(2, pmix_client_globals.get_output, "pmix: get_nb callback recvd"); if (NULL == cb || NULL == cb->lg) { /* nothing we can do */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return; } lg = cb->lg; /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { pmix_output_verbose(2, pmix_client_globals.get_output, "pmix: get_nb server lost connection"); goto done; } /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); pmix_list_remove_item(&pmix_client_globals.pending_requests, &cb->super); PMIX_RELEASE(cb); return; } if (PMIX_SUCCESS != ret) { pmix_output_verbose(2, pmix_client_globals.get_output, "pmix: get_nb server returned %s", PMIx_Error_string(ret)); goto done; } /* store this into our GDS component associated * with the server - if it is the hash component, * the buffer will include a copy of the data. If * it is the shmem component, it will contain just * the memory address info */ PMIX_GDS_ACCEPT_KVS_RESP(rc, pmix_globals.mypeer, buf); done: /* now search any pending requests (including the one this was in * response to) to see if they can be met. Note that this function * will only be called if the user requested a specific key - we * don't support calls to "get" for a NULL key */ pmix_output_verbose(2, pmix_client_globals.get_output, "pmix: get_nb looking for requested key"); PMIX_LIST_FOREACH_SAFE (cb, cb2, &pmix_client_globals.pending_requests, pmix_cb_t) { if (PMIX_CHECK_NSPACE(lg->p.nspace, cb->pname.nspace) && cb->pname.rank == lg->p.rank) { pmix_list_remove_item(&pmix_client_globals.pending_requests, &cb->super); if (PMIX_SUCCESS != ret) { if (cb->checked) { cb->status = ret; gcbfn(0, 0, cb); } else { cb->cbfunc.valuefn(ret, NULL, cb->cbdata); } continue; } /* we have the data for this proc - see if we can find the key */ cb->proc = &lg->p; cb->scope = PMIX_SCOPE_UNDEF; pmix_output_verbose(2, pmix_client_globals.get_output, "pmix: get_nb searching for key %s for rank %s", cb->key, PMIX_RANK_PRINT(cb->proc->rank)); PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, cb); if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } else if (PMIX_SUCCESS != rc && PMIX_RANK_UNDEF == cb->proc->rank) { // try again with wildcard rank pmix_rank_t saverank; saverank = cb->proc->rank; cb->proc->rank = PMIX_RANK_WILDCARD; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, cb); if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } cb->proc->rank = saverank; } if (PMIX_SUCCESS != rc) { /* if we are both using the "hash" component, then the server's peer * will simply be pointing at the same hash tables as my peer - no * no point in checking there again */ if (!PMIX_GDS_CHECK_COMPONENT(pmix_client_globals.myserver, "hash")) { pmix_output_verbose(2, pmix_client_globals.get_output, "pmix: get_nb searching for key %s for proc %s, - %s", cb->key, PMIX_NAME_PRINT(cb->proc), pmix_client_globals.myserver->nptr->compat.gds->name); PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, cb); if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } else if (PMIX_SUCCESS != rc && PMIX_RANK_UNDEF == cb->proc->rank) { // try again with wildcard pmix_rank_t saverank; saverank = cb->proc->rank; cb->proc->rank = PMIX_RANK_WILDCARD; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, cb); if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } cb->proc->rank = saverank; } } } if (PMIX_SUCCESS == rc) { if (1 != pmix_list_get_size(&cb->kvs)) { rc = PMIX_ERR_INVALID_VAL; val = NULL; } else { kv = (pmix_kval_t *) pmix_list_remove_first(&cb->kvs); if (PMIX_CHECK_KEY(kv, PMIX_QUALIFIED_VALUE)) { // extract the actual value iptr = (pmix_info_t*)kv->value->data.darray->array; PMIX_VALUE_CREATE(val, 1); PMIx_Value_xfer(val, &iptr[0].value); PMIX_RELEASE(kv); } else { val = kv->value; kv->value = NULL; // protect the value PMIX_RELEASE(kv); } } } if (cb->checked) { cb->status = rc; cb->value = val; gcbfn(0, 0, cb); } else { cb->cbfunc.valuefn(rc, val, cb->cbdata); } } } } static pmix_status_t process_values(pmix_cb_t *cb) { pmix_list_t *kvs = &cb->kvs; pmix_kval_t *kv; pmix_value_t *val; pmix_info_t *info, *iptr; size_t ninfo, n; if (NULL != cb->key && 1 == pmix_list_get_size(kvs)) { kv = (pmix_kval_t *) pmix_list_get_first(kvs); if (PMIX_CHECK_KEY(kv, PMIX_QUALIFIED_VALUE)) { // extract the actual value iptr = (pmix_info_t*)kv->value->data.darray->array; cb->value = &iptr[0].value; } else { cb->value = kv->value; } kv->value = NULL; // protect the value return PMIX_SUCCESS; } /* we will return the data as an array of pmix_info_t * in the kvs pmix_value_t */ PMIX_VALUE_CREATE(val, 1); if (NULL == val) { return PMIX_ERR_NOMEM; } val->type = PMIX_DATA_ARRAY; val->data.darray = (pmix_data_array_t *) malloc(sizeof(pmix_data_array_t)); if (NULL == val->data.darray) { PMIX_VALUE_RELEASE(val); return PMIX_ERR_NOMEM; } val->data.darray->type = PMIX_INFO; val->data.darray->size = 0; val->data.darray->array = NULL; ninfo = pmix_list_get_size(kvs); PMIX_INFO_CREATE(info, ninfo); if (NULL == info) { PMIX_VALUE_RELEASE(val); return PMIX_ERR_NOMEM; } /* copy the list elements */ n = 0; PMIX_LIST_FOREACH (kv, kvs, pmix_kval_t) { if (PMIX_CHECK_KEY(kv, PMIX_QUALIFIED_VALUE)) { // extract the actual value iptr = (pmix_info_t*)kv->value->data.darray->array; pmix_strncpy(info[n].key, iptr[0].key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&info[n].value, &iptr[0].value); } else { pmix_strncpy(info[n].key, kv->key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&info[n].value, kv->value); } ++n; } val->data.darray->size = ninfo; val->data.darray->array = info; cb->value = val; return PMIX_SUCCESS; } static void get_data(int sd, short args, void *cbdata) { pmix_cb_t *cb, cb2; pmix_cb_t *cbret; pmix_buffer_t *msg; pmix_status_t rc; pmix_proc_t proc; pmix_get_logic_t *lg; pmix_info_t optional, *iptr; size_t nfo, n; pmix_kval_t *kv; PMIX_HIDE_UNUSED_PARAMS(sd, args); PMIX_ACQUIRE_OBJECT(cb); cb = (pmix_cb_t*)cbdata; lg = cb->lg; iptr = cb->info; nfo = cb->ninfo; pmix_output_verbose(2, pmix_client_globals.get_output, "pmix:client:get_data value for proc %s key %s", PMIX_NAME_PRINT(&lg->p), (NULL == cb->key) ? "NULL" : cb->key); /* check the data provided to us by the server first */ cb->proc = &lg->p; cb->scope = lg->scope; PMIX_INFO_LOAD(&optional, PMIX_OPTIONAL, NULL, PMIX_BOOL); if (lg->nodeinfo) { pmix_output_verbose(2, pmix_client_globals.get_output, "pmix:client:get_data value requesting node-level info for proc %s key %s", PMIX_NAME_PRINT(&lg->p), (NULL == cb->key) ? "NULL" : cb->key); if (NULL == lg->hostname && UINT32_MAX == lg->nodeid) { /* if they didn't specify the target node, then see if they * specified a proc */ if (PMIX_RANK_IS_VALID(cb->proc->rank)) { /* if this is us, then see if we know our info */ if (PMIX_CHECK_PROCID(cb->proc, &pmix_globals.myid)) { if (NULL != pmix_globals.hostname) { lg->hostname = strdup(pmix_globals.hostname); } if (UINT32_MAX != pmix_globals.nodeid) { lg->nodeid = pmix_globals.nodeid; } } if (NULL == lg->hostname) { PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = cb->proc; cb2.key = PMIX_HOSTNAME; cb2.info = &optional; cb2.ninfo = 1; if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) { PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb2); } else { PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); } if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs); PMIX_DESTRUCT(&cb2); if (NULL != kv) { // will never be NULL lg->hostname = strdup(kv->value->data.string); PMIX_RELEASE(kv); } else { lg->hostname = strdup("unknown"); } } } if (UINT32_MAX == lg->nodeid) { /* try for the nodeid */ PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = cb->proc; cb2.key = PMIX_NODEID; cb2.info = &optional; cb2.ninfo = 1; if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) { PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb2); } else { PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); } if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs); PMIX_DESTRUCT(&cb2); if (NULL != kv) { // will never be NULL rc = PMIx_Value_get_number(kv->value, &lg->nodeid, PMIX_UINT32); PMIX_RELEASE(kv); } else { rc = PMIX_ERROR; } if (PMIX_SUCCESS != rc) { cb->status = rc; goto done; } } } // set the rank to undefined since this request is // required to ignore the procID cb->proc->rank = PMIX_RANK_UNDEF; } else { /* it's an invalid rank - assume they are asking about this node. * This is consistent with prior releases */ cb->proc->rank = PMIX_RANK_UNDEF; lg->hostname = strdup(pmix_globals.hostname); lg->nodeid = pmix_globals.nodeid; } } /* if they were asking for hostname, then we are done */ if (PMIx_Check_key(cb->key, PMIX_HOSTNAME)) { if (NULL != lg->hostname) { cb->status = PMIX_SUCCESS; PMIX_VALUE_CREATE(cb->value, 1); PMIX_VALUE_LOAD(cb->value, lg->hostname, PMIX_STRING); } else { cb->status = PMIX_ERR_NOT_FOUND; } goto done; } /* if they were asking for nodeid, then we are done */ if (PMIx_Check_key(cb->key, PMIX_NODEID)) { if (UINT32_MAX != lg->nodeid) { cb->status = PMIX_SUCCESS; PMIX_VALUE_CREATE(cb->value, 1); PMIX_VALUE_LOAD(cb->value, &lg->nodeid, PMIX_UINT32); } else { cb->status = PMIX_ERR_NOT_FOUND; } goto done; } /* we have to look for the info, so we need to tell the GDS * that this is a nodeinfo request and pass the * nodename or nodeid */ if (lg->nodedirective) { /* just need to add the hostname/nodeid */ nfo = cb->ninfo + 2; PMIX_INFO_CREATE(iptr, nfo); for (n=0; n < cb->ninfo; n++) { PMIX_INFO_XFER(&iptr[n], &cb->info[n]); } if (NULL != lg->hostname) { PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_HOSTNAME, lg->hostname, PMIX_STRING); } else { PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_NODEID, &lg->nodeid, PMIX_UINT32); } PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_OPTIONAL, NULL, PMIX_BOOL); cb->infocopy = true; } else { /* need to add directive and hostname/nodeid */ nfo = cb->ninfo + 3; PMIX_INFO_CREATE(iptr, nfo); for (n=0; n < cb->ninfo; n++) { PMIX_INFO_XFER(&iptr[n], &cb->info[n]); } PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_NODE_INFO, NULL, PMIX_BOOL); if (NULL != lg->hostname) { PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_HOSTNAME, lg->hostname, PMIX_STRING); } else { PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_HOSTNAME, &lg->nodeid, PMIX_UINT32); } PMIX_INFO_LOAD(&iptr[cb->ninfo+2], PMIX_OPTIONAL, NULL, PMIX_BOOL); cb->infocopy = true; } goto doget; } if (lg->appinfo) { /* if they didn't provide an appnum, then we have to look it up */ if (UINT32_MAX == lg->appnum) { /* if they didn't specify the target app, then see if they * specified a proc */ if (PMIX_RANK_IS_VALID(cb->proc->rank)) { /* if this is us, then we know our appnum */ if (PMIX_CHECK_PROCID(cb->proc, &pmix_globals.myid)) { lg->appnum = pmix_globals.appnum; } else { PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = cb->proc; cb2.key = PMIX_APPNUM; cb2.info = &optional; cb2.ninfo = 1; if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) { PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb2); } else { PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); } if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs); PMIX_DESTRUCT(&cb2); rc = PMIx_Value_get_number(kv->value, &lg->appnum, PMIX_UINT32); PMIX_RELEASE(kv); if (PMIX_SUCCESS != rc) { cb->status = rc; goto done; } } else { /* couldn't find this proc's appnum - nothing we can do */ cb->status = PMIX_ERR_NOT_FOUND; goto done; } } // set the rank to undefined since this request is // required to ignore the procID cb->proc->rank = PMIX_RANK_UNDEF; } else { /* rank is invalid - assume they want info about our app. * This is consistent with prior releases */ cb->proc->rank = PMIX_RANK_UNDEF; lg->appnum = pmix_globals.appnum; } } /* we get here with a valid appnum - if that is what they were * asking for, then we are done */ if (0 == strcmp(cb->key, PMIX_APPNUM)) { cb->status = PMIX_SUCCESS; PMIX_VALUE_CREATE(cb->value, 1); PMIX_VALUE_LOAD(cb->value, &lg->appnum, PMIX_UINT32); goto done; } /* setup the request */ if (lg->appdirective) { /* just need to add the appnum */ nfo = cb->ninfo + 2; PMIX_INFO_CREATE(iptr, nfo); for (n=0; n < cb->ninfo; n++) { PMIX_INFO_XFER(&iptr[n], &cb->info[n]); } PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_APPNUM, &lg->appnum, PMIX_UINT32); PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_OPTIONAL, NULL, PMIX_BOOL); cb->infocopy = true; } else { /* need to add directive and appnum */ nfo = cb->ninfo + 3; PMIX_INFO_CREATE(iptr, nfo); for (n=0; n < cb->ninfo; n++) { PMIX_INFO_XFER(&iptr[n], &cb->info[n]); } PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_APP_INFO, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_APPNUM, &lg->appnum, PMIX_UINT32); PMIX_INFO_LOAD(&iptr[cb->ninfo+2], PMIX_OPTIONAL, NULL, PMIX_BOOL); cb->infocopy = true; } goto doget; } if (lg->sessioninfo) { /* if they didn't provide a sessionid, then we have to look it up */ if (UINT32_MAX == lg->sessionid) { /* if they didn't specify the target session, then see if they * specified a proc */ if (PMIX_RANK_IS_VALID(cb->proc->rank)) { /* if this is us, then we know our info */ if (PMIX_CHECK_PROCID(cb->proc, &pmix_globals.myid)) { lg->sessionid = pmix_globals.sessionid; } else { PMIX_CONSTRUCT(&cb2, pmix_cb_t); cb2.proc = cb->proc; cb2.key = PMIX_SESSION_ID; cb2.info = &optional; cb2.ninfo = 1; PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2); if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) { kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs); PMIX_DESTRUCT(&cb2); rc = PMIx_Value_get_number(kv->value, &lg->sessionid, PMIX_UINT32); PMIX_RELEASE(kv); if (PMIX_SUCCESS != rc) { cb->status = rc; goto done; } } } } else { /* rank is invalid - assume they want info about our session. * This is consistent with prior releases */ cb->proc->rank = PMIX_RANK_UNDEF; lg->sessionid = pmix_globals.sessionid; } } /* if they were asking for sessionid, then we are done */ if (0 == strcmp(cb->key, PMIX_SESSION_ID)) { cb->status = PMIX_SUCCESS; PMIX_VALUE_CREATE(cb->value, 1); PMIX_VALUE_LOAD(cb->value, &lg->sessionid, PMIX_UINT32); goto done; } /* setup the request */ if (lg->sessiondirective) { /* just need to add the sessionid */ nfo = cb->ninfo + 2; PMIX_INFO_CREATE(iptr, nfo); for (n=0; n < cb->ninfo; n++) { PMIX_INFO_XFER(&iptr[n], &cb->info[n]); } PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_SESSION_ID, &lg->sessionid, PMIX_UINT32); PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_OPTIONAL, NULL, PMIX_BOOL); cb->infocopy = true; } else { /* need to add directive and sessionid */ nfo = cb->ninfo + 3; PMIX_INFO_CREATE(iptr, nfo); for (n=0; n < cb->ninfo; n++) { PMIX_INFO_XFER(&iptr[n], &cb->info[n]); } PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_SESSION_INFO, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_SESSION_ID, &lg->sessionid, PMIX_UINT32); PMIX_INFO_LOAD(&iptr[cb->ninfo+2], PMIX_OPTIONAL, NULL, PMIX_BOOL); cb->infocopy = true; } goto doget; } doget: cb->info = iptr; cb->ninfo = nfo; PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, cb); if (PMIX_SUCCESS == rc) { pmix_output_verbose(5, pmix_client_globals.get_output, "pmix:client data found in server-provided data"); cb->status = process_values(cb); goto done; } pmix_output_verbose(5, pmix_client_globals.get_output, "pmix:client data NOT found in server-provided data"); /* if we are both using the "hash" component, then the server's peer * will simply be pointing at the same hash tables as my peer - no * no point in checking there again */ if (!PMIX_GDS_CHECK_COMPONENT(pmix_client_globals.myserver, "hash")) { /* check the data in my hash module */ PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, cb); if (PMIX_SUCCESS == rc) { pmix_output_verbose(5, pmix_client_globals.get_output, "pmix:client data found in internal hash data"); cb->status = process_values(cb); goto done; } } pmix_output_verbose(5, pmix_client_globals.get_output, "pmix:client requested data NOT found"); /* we may wind up requesting the data using a different rank as an * indicator of the breadth of data we want, but we will need to * get the specific data someone requested later. So setup a tmp * process ID */ memcpy(&proc, &lg->p, sizeof(pmix_proc_t)); cb->pname.nspace = strdup(lg->p.nspace); cb->pname.rank = lg->p.rank; /* we didn't find the data in either the server or the internal hash * components. If this is a NULL or reserved key, then we do NOT go * up to the server unless special circumstances require it */ if (NULL == cb->key) { /* if the server is pre-v3.2, or we are asking about the * job-level info from another namespace, then we have to * request the data */ if (PMIX_PEER_IS_EARLIER(pmix_client_globals.myserver, 3, 1, 100) || !PMIX_CHECK_NSPACE(lg->p.nspace, pmix_globals.myid.nspace)) { /* flag that we want all of the job-level info */ proc.rank = PMIX_RANK_WILDCARD; } } else if (PMIX_CHECK_RESERVED_KEY(cb->key)) { /* this is a reserved key - we should have had this info, but * it is possible that some system don't provide it, thereby * causing the app to manually distribute it. We will therefore * request it from the server, but do so under the "immediate" * use-case, adding that flag if they didn't already include it */ pmix_output_verbose(5, pmix_client_globals.get_output, "pmix:client reserved key not locally found"); if (!lg->immediate) { lg->add_immediate = true; } } /* if we got here, then we don't have the data for this proc. If we * are a server, or we are not connected, then there is * nothing more we can do */ if ((PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) || !pmix_atomic_check_bool(&pmix_globals.connected)) { cb->status = PMIX_ERR_NOT_FOUND; goto done; } /* if the data is available in a different scope, then * let the user know */ if (PMIX_ERR_EXISTS_OUTSIDE_SCOPE == rc) { cb->status = rc; goto done; } /* we also have to check the user's directives to see if they do not want * us to attempt to retrieve it from the server */ if (lg->optional) { /* they don't want us to try and retrieve it */ pmix_output_verbose(2, pmix_client_globals.get_output, "PMIx_Get key=%s for rank = %u, namespace = %s was not found - request was optional", cb->key, cb->pname.rank, cb->pname.nspace); cb->status = rc; goto done; } /* see if we already have a request in place with the server for data from * this nspace:rank. If we do, then no need to ask again as the * request will return _all_ data from that proc */ PMIX_LIST_FOREACH (cbret, &pmix_client_globals.pending_requests, pmix_cb_t) { if (PMIX_CHECK_NAMES(&cbret->pname, &proc)) { pmix_output_verbose(2, pmix_client_globals.get_output, "%s ADDING REQUEST TO PENDING %s:%s KEY %s", PMIX_NAME_PRINT(&pmix_globals.myid), cb->proc->nspace, PMIX_RANK_PRINT(proc.rank), cb->key); /* we do have a pending request, but we still need to track this * outstanding request so we can satisfy it once the data is returned */ pmix_list_append(&pmix_client_globals.pending_requests, &cb->super); return; } } /* we don't have a pending request, so let's create one */ msg = _pack_get(cb, proc.rank, PMIX_GETNB_CMD); if (NULL == msg) { cb->status = PMIX_ERROR; PMIX_ERROR_LOG(cb->status); goto done; } pmix_output_verbose(2, pmix_client_globals.get_output, "%s REQUESTING DATA FROM SERVER FOR %s:%s KEY %s", PMIX_NAME_PRINT(&pmix_globals.myid), cb->proc->nspace, PMIX_RANK_PRINT(proc.rank), PMIx_Get_attribute_string(cb->key)); /* track the callback object */ pmix_list_append(&pmix_client_globals.pending_requests, &cb->super); /* send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, _getnb_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { pmix_list_remove_item(&pmix_client_globals.pending_requests, &cb->super); cb->status = PMIX_ERROR; goto done; } return; done: /* we made a lot of changes to cb, so ensure they get * written out before we return */ PMIX_POST_OBJECT(cb); if (cb->checked) { gcbfn(0, 0, cb); } else { cb->cbfunc.valuefn(cb->status, cb->value, cb->cbdata); } return; } static void refcb(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; int32_t cnt; pmix_status_t rc, ret; pmix_kval_t kv; PMIX_HIDE_UNUSED_PARAMS(pr, hdr); PMIX_ACQUIRE_OBJECT(cb); if (NULL == cb) { /* nothing we can do */ PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return; } /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { pmix_output_verbose(2, pmix_client_globals.get_output, "pmix: refcb server lost connection"); ret = PMIX_ERR_LOST_CONNECTION; goto done; } /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); ret = rc; goto done; } // unpack and store any returned data PMIX_CONSTRUCT(&kv, pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &kv, &cnt, PMIX_KVAL); while (PMIX_SUCCESS == rc) { PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, cb->proc, PMIX_INTERNAL, &kv); PMIX_DESTRUCT(&kv); PMIX_CONSTRUCT(&kv, pmix_kval_t); cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &kv, &cnt, PMIX_KVAL); } PMIX_DESTRUCT(&kv); if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) { ret = PMIX_SUCCESS; } else { ret = rc; } done: cb->status = ret; /* release the lock */ PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); return; } static pmix_status_t refresh_cache(const pmix_proc_t *p) { pmix_cb_t *cb; pmix_buffer_t *msg; pmix_status_t rc; pmix_cmd_t cmd = PMIX_REFRESH_CACHE; char *nspace = (char*)p->nspace; pmix_output_verbose(2, pmix_client_globals.get_output, "%s REQUESTING CACHE REFRESH BY SERVER FOR PROC %s", PMIX_NAME_PRINT(&pmix_globals.myid), PMIX_NAME_PRINT(p)); /* pack a quick message to the server asking it * to refresh our cache */ msg = PMIX_NEW(pmix_buffer_t); PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nspace, 1, PMIX_STRING); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &p->rank, 1, PMIX_PROC_RANK); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } cb = PMIX_NEW(pmix_cb_t); cb->proc = (pmix_proc_t*)p; /* send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, refcb, (void *)cb); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cb); return rc; } PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; PMIX_RELEASE(cb); return rc; } pmix-6.1.1~rc2/src/client/pmix_client_fence.c0000664000175000017500000002276215203536752021372 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/include/pmix_stdint.h" #include "include/pmix.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "src/class/pmix_list.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/ptl/ptl.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "pmix_client_ops.h" static pmix_status_t unpack_return(pmix_buffer_t *data); static pmix_status_t pack_fence(pmix_buffer_t *msg, pmix_cmd_t cmd, const pmix_proc_t *procs, size_t nprocs, const pmix_info_t *info, size_t ninfo); static void wait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata); static void op_cbfunc(pmix_status_t status, void *cbdata); PMIX_EXPORT pmix_status_t PMIx_Fence(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo) { pmix_cb_t *cb; pmix_status_t rc; pmix_output_verbose(2, pmix_client_globals.fence_output, "pmix: executing fence"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we are a singleton, there is nothing to do */ if (pmix_client_globals.singleton) { return PMIX_SUCCESS; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_cb_t); /* push the message into our event base to send to the server */ rc = PMIx_Fence_nb(procs, nprocs, info, ninfo, op_cbfunc, cb); if (PMIX_SUCCESS != rc && PMIX_OPERATION_SUCCEEDED != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cb); return rc; } if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } else { /* wait for the fence to complete */ PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; } PMIX_RELEASE(cb); pmix_output_verbose(2, pmix_client_globals.fence_output, "pmix: fence released"); return rc; } PMIX_EXPORT pmix_status_t PMIx_Fence_nb(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_FENCENB_CMD; pmix_status_t rc; pmix_cb_t *cb; pmix_proc_t rg, *rgs; size_t nrg; bool created = false; pmix_output_verbose(2, pmix_client_globals.fence_output, "pmix: fence_nb called"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } /* if we are a singleton, there is nothing to do */ if (pmix_client_globals.singleton) { return PMIX_OPERATION_SUCCEEDED; } /* if we aren't connected, don't attempt to send */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* check for bozo input */ if (NULL == procs && 0 != nprocs) { return PMIX_ERR_BAD_PARAM; } /* if we are given a NULL proc, then the caller is referencing * all procs within our own nspace */ if (NULL == procs) { pmix_strncpy(rg.nspace, pmix_globals.myid.nspace, PMIX_MAX_NSLEN); rg.rank = PMIX_RANK_WILDCARD; rgs = &rg; nrg = 1; } else { // if they are referencing a group, then replace that group with // the actual proc(s) rc = pmix_client_convert_group_procs(procs, nprocs, &rgs, &nrg); if (PMIX_SUCCESS != rc) { return rc; } created = true; } msg = PMIX_NEW(pmix_buffer_t); if (PMIX_SUCCESS != (rc = pack_fence(msg, cmd, rgs, nrg, info, ninfo))) { PMIX_RELEASE(msg); if (created) { PMIX_PROC_FREE(rgs, nrg); } return rc; } if (created) { PMIX_PROC_FREE(rgs, nrg); } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ cb = PMIX_NEW(pmix_cb_t); cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, wait_cbfunc, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); PMIX_RELEASE(cb); } if (NULL == cbfunc) { PMIX_WAIT_THREAD(&cb->lock); rc = cb->status; PMIX_RELEASE(cb); } return rc; } static pmix_status_t unpack_return(pmix_buffer_t *data) { pmix_status_t rc; pmix_status_t ret; int32_t cnt; pmix_output_verbose(2, pmix_client_globals.fence_output, "client:unpack fence called"); /* unpack the status code */ cnt = 1; PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, data, &ret, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } pmix_output_verbose(2, pmix_client_globals.fence_output, "client:unpack fence received status %s", PMIx_Error_string(ret)); if (PMIX_OPERATION_SUCCEEDED == ret) { ret = PMIX_SUCCESS; } else if (PMIX_SUCCESS != ret) { return ret; } /* provide an opportunity to store any data (or at least how to access * any data) that was included in the fence */ PMIX_GDS_RECV_MODEX_COMPLETE(rc, pmix_client_globals.myserver, data); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } return ret; } static pmix_status_t pack_fence(pmix_buffer_t *msg, pmix_cmd_t cmd, const pmix_proc_t *procs, size_t nprocs, const pmix_info_t *info, size_t ninfo) { pmix_status_t rc; /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack the number of procs */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nprocs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack any provided procs - must always be at least one (our own) */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, procs, nprocs, PMIX_PROC); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack the number of info */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } /* pack any provided info - may be NULL */ if (NULL != info && 0 < ninfo) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); return rc; } } return PMIX_SUCCESS; } static void wait_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(pr, hdr); pmix_output_verbose(2, pmix_client_globals.fence_output, "pmix: fence_nb callback recvd"); if (NULL == cb) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); return; } /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { rc = PMIX_ERR_UNREACH; } else { rc = unpack_return(buf); } /* if a callback was provided, execute it */ if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(rc, cb->cbdata); PMIX_RELEASE(cb); } else { cb->status = rc; PMIX_WAKEUP_THREAD(&cb->lock); } } static void op_cbfunc(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; cb->status = status; PMIX_WAKEUP_THREAD(&cb->lock); } pmix-6.1.1~rc2/src/client/pmix_client_fabric.c0000664000175000017500000003201515203536752021530 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "src/include/pmix_types.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "src/class/pmix_list.h" #include "src/client/pmix_client_ops.h" #include "src/mca/pnet/base/base.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" void PMIx_Fabric_construct(pmix_fabric_t *p) { p->name = NULL; p->index = SIZE_MAX; p->info = NULL; p->ninfo = 0; p->module = NULL; } static void fcb(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; size_t n; cb->status = status; if (PMIX_SUCCESS == status && 0 < ninfo) { PMIX_INFO_CREATE(cb->fabric->info, ninfo); cb->fabric->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&cb->fabric->info[n], &info[n]); } } if (NULL != release_fn) { release_fn(release_cbdata); } /* release the caller */ if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(status, cb->cbdata); PMIX_RELEASE(cb); } else { PMIX_WAKEUP_THREAD(&cb->lock); } } static void frecv(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; pmix_status_t rc; int cnt; PMIX_HIDE_UNUSED_PARAMS(hdr); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:fabric recv from server with %d bytes", (int) buf->bytes_used); /* a zero-byte buffer indicates that this recv is being * completed due to a lost connection */ if (PMIX_BUFFER_IS_EMPTY(buf)) { rc = PMIX_ERR_UNREACH; goto complete; } /* unpack the status */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cb->status, &cnt, PMIX_STATUS); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (PMIX_SUCCESS != cb->status) { goto complete; } /* unpack any returned data */ cnt = 1; PMIX_BFROPS_UNPACK(rc, peer, buf, &cb->fabric->ninfo, &cnt, PMIX_SIZE); if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) { PMIX_ERROR_LOG(rc); goto complete; } if (0 < cb->fabric->ninfo) { PMIX_INFO_CREATE(cb->fabric->info, cb->fabric->ninfo); cnt = cb->fabric->ninfo; PMIX_BFROPS_UNPACK(rc, peer, buf, cb->fabric->info, &cnt, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); goto complete; } } complete: pmix_output_verbose(2, pmix_globals.debug_output, "pmix:fabric recv from server releasing"); /* release the caller */ if (NULL != cb->cbfunc.opfn) { cb->cbfunc.opfn(rc, cb->cbdata); PMIX_RELEASE(cb); } else { PMIX_WAKEUP_THREAD(&cb->lock); } } static void mycbfunc(pmix_status_t status, void *cbdata) { pmix_cb_t *cb = (pmix_cb_t *) cbdata; PMIX_ACQUIRE_OBJECT(cb); cb->status = status; PMIX_POST_OBJECT(cb); PMIX_WAKEUP_THREAD(&cb->lock); return; } PMIX_EXPORT pmix_status_t PMIx_Fabric_register(pmix_fabric_t *fabric, const pmix_info_t directives[], size_t ndirs) { pmix_cb_t cb; pmix_status_t rc; pmix_output_verbose(2, pmix_globals.debug_output, "pmix:fabric register"); if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* create a callback object so we can be notified when * the non-blocking operation is complete */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.fabric = fabric; rc = PMIx_Fabric_register_nb(fabric, directives, ndirs, mycbfunc, &cb); if (PMIX_OPERATION_SUCCEEDED == rc) { PMIX_DESTRUCT(&cb); return PMIX_SUCCESS; } else if (PMIX_SUCCESS != rc) { /* got an error */ PMIX_DESTRUCT(&cb); return rc; } /* wait for the data to return */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; /* the fabric info was directly filled into the fabric object */ PMIX_DESTRUCT(&cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:fabric register completed"); return rc; } PMIX_EXPORT pmix_status_t PMIx_Fabric_register_nb(pmix_fabric_t *fabric, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_cb_t *cb; pmix_status_t rc; pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_FABRIC_REGISTER_CMD; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* if I am a scheduler or a server (but not a tool), * then I should be able to support this myself */ if ((PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) || PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { rc = pmix_pnet.register_fabric(fabric, directives, ndirs, cbfunc, cbdata); return rc; } /* otherwise, I need to send it to * a daemon for processing */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } /* if we are a client, then relay this request to the server */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the directives */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } if (NULL != directives && 0 < ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, directives, ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ if (NULL != cbfunc) { cb = PMIX_NEW(pmix_cb_t); cb->fabric = fabric; cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; } else { cb = (pmix_cb_t *) cbdata; } /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, frecv, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); if (NULL != cbfunc) { PMIX_RELEASE(cb); } } return rc; } PMIX_EXPORT pmix_status_t PMIx_Fabric_update(pmix_fabric_t *fabric) { pmix_cb_t cb; pmix_status_t rc; if (!pmix_atomic_check_bool(&pmix_globals.initialized)) { return PMIX_ERR_INIT; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } pmix_output_verbose(2, pmix_globals.debug_output, "pmix:fabric update"); /* create a callback object so we can be notified when * the non-blocking operation is complete */ PMIX_CONSTRUCT(&cb, pmix_cb_t); cb.fabric = fabric; if (PMIX_SUCCESS != (rc = PMIx_Fabric_update_nb(fabric, NULL, &cb))) { PMIX_DESTRUCT(&cb); return rc; } /* wait for the data to return */ PMIX_WAIT_THREAD(&cb.lock); rc = cb.status; /* the fabric info was directly filled into the fabric object */ PMIX_DESTRUCT(&cb); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:fabric update completed"); return rc; } PMIX_EXPORT pmix_status_t PMIx_Fabric_update_nb(pmix_fabric_t *fabric, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_cb_t *cb; pmix_status_t rc; pmix_buffer_t *msg; pmix_cmd_t cmd = PMIX_FABRIC_UPDATE_CMD; /* if I am a scheduler server, then I should be able * to support this myself */ if (PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { rc = pmix_pnet.update_fabric(fabric); return rc; } if (pmix_atomic_check_bool(&pmix_globals.progress_thread_stopped)) { return PMIX_ERR_NOT_AVAILABLE; } /* otherwise, if we are a server, then see if we can pass * it up to our host so they can send it to the scheduler */ if (PMIX_PEER_IS_SERVER(pmix_globals.mypeer) && !PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) { if (NULL == pmix_host_server.fabric) { return PMIX_ERR_NOT_SUPPORTED; } if (NULL != cbfunc) { cb = PMIX_NEW(pmix_cb_t); cb->fabric = fabric; cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; } else { cb = (pmix_cb_t *) cbdata; } cb->infocopy = true; PMIX_INFO_CREATE(cb->info, 1); cb->ninfo = 1; PMIX_INFO_LOAD(&cb->info[0], PMIX_FABRIC_INDEX, &fabric->index, PMIX_SIZE); rc = pmix_host_server.fabric(&pmix_globals.myid, PMIX_FABRIC_UPDATE_INFO, cb->info, 1, fcb, (void *) cb); if (PMIX_SUCCESS != rc && NULL != cbfunc) { PMIX_RELEASE(cb); } return rc; } /* finally, if I am a tool or client, then I need to send it to * a daemon for processing */ if (!pmix_atomic_check_bool(&pmix_globals.connected)) { return PMIX_ERR_UNREACH; } /* if we are a client, then relay this request to the server */ msg = PMIX_NEW(pmix_buffer_t); /* pack the cmd */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* pack the fabric index */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &fabric->index, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); return rc; } /* create a callback object as we need to pass it to the * recv routine so we know which callback to use when * the return message is recvd */ if (NULL != cbfunc) { cb = PMIX_NEW(pmix_cb_t); cb->fabric = fabric; cb->cbfunc.opfn = cbfunc; cb->cbdata = cbdata; } else { cb = (pmix_cb_t *) cbdata; } /* push the message into our event base to send to the server */ PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, frecv, (void *) cb); if (PMIX_SUCCESS != rc) { PMIX_RELEASE(msg); if (NULL != cbfunc) { PMIX_RELEASE(cb); } } return rc; } PMIX_EXPORT pmix_status_t PMIx_Fabric_deregister(pmix_fabric_t *fabric) { pmix_status_t rc; rc = PMIx_Fabric_deregister_nb(fabric, NULL, NULL); if (PMIX_OPERATION_SUCCEEDED == rc) { rc = PMIX_SUCCESS; } return rc; } PMIX_EXPORT pmix_status_t PMIx_Fabric_deregister_nb(pmix_fabric_t *fabric, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(cbfunc, cbdata); /* if I am a scheduler server, then I should be able * to support this myself */ if (PMIX_PEER_IS_SCHEDULER(pmix_globals.mypeer)) { rc = pmix_pnet.deregister_fabric(fabric); if (PMIX_SUCCESS == rc) { rc = PMIX_OPERATION_SUCCEEDED; } return rc; } /* otherwise, just remove any storage in it */ if (NULL != fabric->info) { PMIX_INFO_FREE(fabric->info, fabric->ninfo); } return PMIX_OPERATION_SUCCEEDED; } pmix-6.1.1~rc2/src/include/0000775000175000017500000000000015203536752015707 5ustar alastairalastairpmix-6.1.1~rc2/src/include/pmix_atomic.h0000664000175000017500000001037315203536752020375 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2011 Sandia National Laboratories. All rights reserved. * Copyright (c) 2011-2017 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) Amazon.com, Inc. or its affiliates. All Rights * reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file * * Atomic operations. * * This API is patterned after the FreeBSD kernel atomic interface * (which is influenced by Intel's ia64 architecture). The * FreeBSD interface is documented at * * http://www.freebsd.org/cgi/man.cgi?query=atomic&sektion=9 * * Only the necessary subset of functions are implemented here. * * The following #defines will be true / false based on * assembly support: * * - \c PMIX_HAVE_ATOMIC_MEM_BARRIER atomic memory barriers * - \c PMIX_HAVE_ATOMIC_SPINLOCKS atomic spinlocks * - \c PMIX_HAVE_ATOMIC_MATH_32 if 32 bit add/sub/compare-exchange can be done "atomically" * - \c PMIX_HAVE_ATOMIC_MATH_64 if 64 bit add/sub/compare-exchange can be done "atomically" * * Note that for the Atomic math, atomic add/sub may be implemented as * C code using pmix_atomic_compare_exchange. The appearance of atomic * operation will be upheld in these cases. */ #ifndef PMIX_SYS_ATOMIC_H #define PMIX_SYS_ATOMIC_H 1 #include "src/include/pmix_config.h" #include "src/include/pmix_stdatomic.h" #include static inline void pmix_atomic_wmb(void) { atomic_thread_fence(memory_order_release); } static inline void pmix_atomic_rmb(void) { # if defined(PMIX_ATOMIC_X86_64) /* work around a bug in older gcc versions (observed in gcc 6.x) * where acquire seems to get treated as a no-op instead of being * equivalent to __asm__ __volatile__("": : :"memory") on x86_64 */ __asm__ __volatile__("" : : : "memory"); # else atomic_thread_fence(memory_order_acquire); # endif } #define PMIX_ATOMIC_DEFINE_OP(type, bits, operator, name) \ static inline type \ pmix_atomic_fetch_##name##_##bits(pmix_atomic_##type *addr, type value) \ { \ return atomic_fetch_##name##_explicit( \ addr, value, memory_order_relaxed); \ } \ \ static inline type \ pmix_atomic_##name##_fetch_##bits(pmix_atomic_##type *addr, type value) \ { \ return atomic_fetch_##name##_explicit( \ addr, value, memory_order_relaxed) operator value; \ } PMIX_ATOMIC_DEFINE_OP(int32_t, 32, +, add) PMIX_ATOMIC_DEFINE_OP(int32_t, 32, &, and) PMIX_ATOMIC_DEFINE_OP(int32_t, 32, |, or) PMIX_ATOMIC_DEFINE_OP(int32_t, 32, ^, xor) PMIX_ATOMIC_DEFINE_OP(int32_t, 32, -, sub) #endif /* PMIX_SYS_ATOMIC_H */ pmix-6.1.1~rc2/src/include/pmix_stdatomic.h0000664000175000017500000000341615203536752021110 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2018 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2020 Cisco Systems, Inc. All rights reserved * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2021 Amazon.com, Inc. or its affiliates. * All Rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_STDATOMIC_H #define PMIX_STDATOMIC_H #include "pmix_stdint.h" #include #ifdef HAVE_STDATOMIC_H #include #endif typedef atomic_int pmix_atomic_int_t; typedef atomic_long pmix_atomic_long_t; typedef _Atomic bool pmix_atomic_bool_t; typedef _Atomic int32_t pmix_atomic_int32_t; typedef _Atomic uint32_t pmix_atomic_uint32_t; typedef _Atomic int64_t pmix_atomic_int64_t; typedef _Atomic uint64_t pmix_atomic_uint64_t; typedef _Atomic size_t pmix_atomic_size_t; typedef _Atomic ssize_t pmix_atomic_ssize_t; typedef _Atomic intptr_t pmix_atomic_intptr_t; typedef _Atomic uintptr_t pmix_atomic_uintptr_t; #define pmix_atomic_store_int(addr, val) __atomic_store_n(addr, val, __ATOMIC_RELAXED) #define pmix_atomic_load_int(addr) __atomic_load_n(addr, __ATOMIC_RELAXED) #define pmix_atomic_set_bool(addr) atomic_store(addr, true) #define pmix_atomic_unset_bool(addr) atomic_store(addr, false) #define pmix_atomic_check_bool(addr) atomic_load(addr) #define pmix_atomic_fetch_add(addr, val) __atomic_fetch_add(addr, val, __ATOMIC_SEQ_CST) #define pmix_atomic_test_and_set(addr) __atomic_test_and_set(addr, __ATOMIC_SEQ_CST) #endif pmix-6.1.1~rc2/src/include/pmix_portable_platform.h0000664000175000017500000000073115203536752022632 0ustar alastairalastair/* * Copyright (c) 2021 Amazon.com, Inc. or its affiliates. All Rights * reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * Wrapper around GASNet's gasnet_portable_platform.h to avoid * compiler warnings */ #ifndef PMIX_PORTABLE_PLATFORM_H #define PMIX_PORTABLE_PLATFORM_H 1 #include "src/include/pmix_portable_platform_real.h" #endif pmix-6.1.1~rc2/src/include/pmix_prefetch.h0000664000175000017500000000211315203536752020712 0ustar alastairalastair/* * Copyright (c) 2004-2006 The Regents of the University of California. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file * * Compiler-specific prefetch functions * * A small set of prefetch / prediction interfaces for using compiler * directives to improve memory prefetching and branch prediction */ #ifndef PMIX_PREFETCH_H #define PMIX_PREFETCH_H #include "src/include/pmix_config.h" #if PMIX_C_HAVE_BUILTIN_EXPECT # define PMIX_LIKELY(expression) __builtin_expect(!!(expression), 1) # define PMIX_UNLIKELY(expression) __builtin_expect(!!(expression), 0) #else # define PMIX_LIKELY(expression) (expression) # define PMIX_UNLIKELY(expression) (expression) #endif #if PMIX_C_HAVE_BUILTIN_PREFETCH # define PMIX_PREFETCH(address, rw, locality) __builtin_prefetch(address, rw, locality) #else # define PMIX_PREFETCH(address, rw, locality) #endif #endif pmix-6.1.1~rc2/src/include/pmix_portable_platform_real.h0000664000175000017500000012631015203536752023637 0ustar alastairalastair/* $Source: bitbucket.org:berkeleylab/gasnet.git/other/portable_platform.h $ * Description: Portable platform detection header * Copyright 2006, Dan Bonachea * Copyright 2018, The Regents of the University of California * Terms of Use: In ADDITION to the license information in license.txt, * anyone redistributing this header agrees not to change any part of this notice, or * the version handshake in the header versioning section below. * Furthermore, redistributed copies of any portion of this header must * not appear within files named "portable_platform.h" or "gasnet_portable_platform.h", * unless it is embedded within a complete copy of the GASNet distribution. * These restrictions are designed to prevent conflicts for end users * who compose multiple projects using the PLATFORM_ namespace. * * The canonical version of this header is hosted in the GASNet project at: * https://bitbucket.org/berkeleylab/gasnet * * Developers who clone this header into their own project are HIGHLY encouraged to * contribute any improvements (especially addition of new platforms) back to the * canonical version, for the benefit of the community. * Contributions and bug reports should be directed to: * https://gasnet-bugs.lbl.gov or gasnet-staff@lbl.gov */ /* ------------------------------------------------------------------------------------ */ /* Header versioning: DO NOT CHANGE ANYTHING IN THIS SECTION * The license terms for this header prohibit modifying this section in ANY way. Clones should continue to advertise a PLATFORM_HEADER_VERSION equal to the canonical version they cloned, and should not modify the handshake logic which ensures the highest canonical header version is used. */ /* Publish and enforce version number for the public interface to this header */ /* YOU ARE NOT PERMITTED TO CHANGE THIS SECTION WITHOUT DIRECT APPROVAL FROM DAN BONACHEA */ #if !defined(_PORTABLE_PLATFORM_H) || !defined(PLATFORM_HEADER_VERSION) \ || _PORTABLE_PLATFORM_H != PLATFORM_HEADER_VERSION \ || PLATFORM_HEADER_VERSION < 22 #undef PLATFORM_HEADER_VERSION #define PLATFORM_HEADER_VERSION 22 #undef _PORTABLE_PLATFORM_H #define _PORTABLE_PLATFORM_H PLATFORM_HEADER_VERSION /* End Header versioning handshake */ /* ------------------------------------------------------------------------------------ */ /* make sure that previously-included older/broken clones of this header do not pollute our namespace */ #undef PLATFORM_COMPILER_FAMILYNAME #undef PLATFORM_COMPILER_FAMILYID #undef PLATFORM_COMPILER_ID #undef PLATFORM_COMPILER_VERSION #undef PLATFORM_COMPILER_VERSION_STR #undef PLATFORM_COMPILER_VERSION_INT #undef PLATFORM_COMPILER_IDSTR #undef PLATFORM_COMPILER_VERSION_GT #undef PLATFORM_COMPILER_VERSION_GE #undef PLATFORM_COMPILER_VERSION_EQ #undef PLATFORM_COMPILER_VERSION_LE #undef PLATFORM_COMPILER_VERSION_LT #undef PLATFORM_COMPILER_C_LANGLVL #undef PLATFORM_COMPILER_CXX_LANGLVL #undef PLATFORM_COMPILER_INTEL #undef PLATFORM_COMPILER_INTEL_C #undef PLATFORM_COMPILER_INTEL_CXX #undef PLATFORM_COMPILER_PATHSCALE #undef PLATFORM_COMPILER_PATHSCALE_C #undef PLATFORM_COMPILER_PATHSCALE_CXX #undef PLATFORM_COMPILER_PGI #undef PLATFORM_COMPILER_PGI_C #undef PLATFORM_COMPILER_PGI_CXX #undef PLATFORM_COMPILER_XLC #undef PLATFORM_COMPILER_XLC_C #undef PLATFORM_COMPILER_XLC_CXX #undef PLATFORM_COMPILER_COMPAQ #undef PLATFORM_COMPILER_COMPAQ_C #undef PLATFORM_COMPILER_COMPAQ_CXX #undef PLATFORM_COMPILER_SUN #undef PLATFORM_COMPILER_SUN_C #undef PLATFORM_COMPILER_SUN_CXX #undef PLATFORM_COMPILER_HP #undef PLATFORM_COMPILER_HP_C #undef PLATFORM_COMPILER_HP_CXX #undef PLATFORM_COMPILER_SGI #undef PLATFORM_COMPILER_SGI_C #undef PLATFORM_COMPILER_SGI_CXX #undef PLATFORM_COMPILER_CRAY #undef PLATFORM_COMPILER_CRAY_C #undef PLATFORM_COMPILER_CRAY_CXX #undef PLATFORM_COMPILER_KAI #undef PLATFORM_COMPILER_KAI_C #undef PLATFORM_COMPILER_KAI_CXX #undef PLATFORM_COMPILER_MTA #undef PLATFORM_COMPILER_MTA_C #undef PLATFORM_COMPILER_MTA_CXX #undef PLATFORM_COMPILER_NECSX #undef PLATFORM_COMPILER_NECSX_C #undef PLATFORM_COMPILER_NECSX_CXX #undef PLATFORM_COMPILER_MICROSOFT #undef PLATFORM_COMPILER_MICROSOFT_C #undef PLATFORM_COMPILER_MICROSOFT_CXX #undef PLATFORM_COMPILER_TINY #undef PLATFORM_COMPILER_TINY_C #undef PLATFORM_COMPILER_TINY_CXX #undef PLATFORM_COMPILER_LCC #undef PLATFORM_COMPILER_LCC_C #undef PLATFORM_COMPILER_LCC_CXX #undef PLATFORM_COMPILER_OPEN64 #undef PLATFORM_COMPILER_OPEN64_C #undef PLATFORM_COMPILER_OPEN64_CXX #undef PLATFORM_COMPILER_PCC #undef PLATFORM_COMPILER_PCC_C #undef PLATFORM_COMPILER_PCC_CXX #undef PLATFORM_COMPILER_CLANG #undef PLATFORM_COMPILER_CLANG_C #undef PLATFORM_COMPILER_CLANG_CXX #undef PLATFORM_COMPILER_NVHPC #undef PLATFORM_COMPILER_NVHPC_C #undef PLATFORM_COMPILER_NVHPC_CXX #undef PLATFORM_COMPILER_GNU #undef PLATFORM_COMPILER_GNU_C #undef PLATFORM_COMPILER_GNU_CXX #undef PLATFORM_COMPILER_UNKNOWN #undef PLATFORM_OS_FAMILYNAME #undef PLATFORM_OS_SUBFAMILYNAME #undef PLATFORM_OS_CATAMOUNT #undef PLATFORM_OS_BGP #undef PLATFORM_OS_BGQ #undef PLATFORM_OS_K42 #undef PLATFORM_OS_UCLINUX #undef PLATFORM_OS_LINUX #undef PLATFORM_OS_CNL #undef PLATFORM_OS_SUBFAMILY_CNL #undef PLATFORM_OS_WSL #undef PLATFORM_OS_SUBFAMILY_WSL #undef PLATFORM_OS_BLRTS #undef PLATFORM_OS_CYGWIN #undef PLATFORM_OS_MSWINDOWS #undef PLATFORM_OS_AIX #undef PLATFORM_OS_TRU64 #undef PLATFORM_OS_FREEBSD #undef PLATFORM_OS_NETBSD #undef PLATFORM_OS_OPENBSD #undef PLATFORM_OS_SOLARIS #undef PLATFORM_OS_DARWIN #undef PLATFORM_OS_IRIX #undef PLATFORM_OS_HPUX #undef PLATFORM_OS_UNICOS #undef PLATFORM_OS_MTA #undef PLATFORM_OS_SUPERUX #undef PLATFORM_OS_UNKNOWN #undef PLATFORM_ARCH_FAMILYNAME #undef PLATFORM_ARCH_32 #undef _PLATFORM_ARCH_32 #undef PLATFORM_ARCH_64 #undef _PLATFORM_ARCH_64 #undef PLATFORM_ARCH_BIG_ENDIAN #undef _PLATFORM_ARCH_BIG_ENDIAN #undef PLATFORM_ARCH_LITTLE_ENDIAN #undef _PLATFORM_ARCH_LITTLE_ENDIAN #undef PLATFORM_ARCH_POWERPC #undef PLATFORM_ARCH_MIC #undef PLATFORM_ARCH_X86_64 #undef PLATFORM_ARCH_IA64 #undef PLATFORM_ARCH_X86 #undef PLATFORM_ARCH_ALPHA #undef PLATFORM_ARCH_MIPS #undef PLATFORM_ARCH_SPARC #undef PLATFORM_ARCH_PARISC #undef PLATFORM_ARCH_CRAYX1 #undef PLATFORM_ARCH_CRAYT3E #undef PLATFORM_ARCH_MTA #undef PLATFORM_ARCH_NECSX #undef PLATFORM_ARCH_MICROBLAZE #undef PLATFORM_ARCH_ARM #undef PLATFORM_ARCH_AARCH64 #undef PLATFORM_ARCH_TILE #undef PLATFORM_ARCH_S390 #undef PLATFORM_ARCH_RISCV #undef PLATFORM_ARCH_UNKNOWN /* prevent known old/broken versions of this header from loading */ #undef OMPI_PORTABLE_PLATFORM_H #define OMPI_PORTABLE_PLATFORM_H #undef OPAL_PORTABLE_PLATFORM_H #define OPAL_PORTABLE_PLATFORM_H /* ------------------------------------------------------------------------------------ */ /* most of this file was written based on information in vendor documents, system headers, and inspecting verbose compiler output. Another useful source of information: http://predef.sourceforge.net/ */ /* ------------------------------------------------------------------------------------ */ /* helpers */ #undef _PLATFORM_STRINGIFY_HELPER #define _PLATFORM_STRINGIFY_HELPER(x) #x #undef PLATFORM_STRINGIFY #define PLATFORM_STRINGIFY(x) _PLATFORM_STRINGIFY_HELPER(x) /* ------------------------------------------------------------------------------------ */ /* Compiler detection */ /* PLATFORM_COMPILER_: defined to 1 if compiler is a given family, undef otherwise PLATFORM_COMPILER__C PLATFORM_COMPILER__CXX defined to 1 if compiler is a given family, and is the C or C++ compiler, respectively PLATFORM_COMPILER_FAMILYNAME: unquoted token which provides the compiler family name PLATFORM_COMPILER_FAMILYID: defined to a positive integral value which is unique to a given compiler family or zero if the compiler is unrecognized PLATFORM_COMPILER_ID: same as PLATFORM_COMPILER_FAMILYID, except C and C++ compilers are differentiated PLATFORM_COMPILER_VERSION: defined to an integral expression which is guaranteed to be monotonically non-decreasing with increasing compiler versions. Will be zero for unrecognized compilers. The exact encoding of compiler version tuples into this constant may occasionally change when this header is upgraded, so code should use the (in)equality macros below to check against particular compiler versions, instead of embedding an encoded constant. PLATFORM_COMPILER_VERSION_STR: A string representation of the compiler version, which may contain additional info PLATFORM_COMPILER_VERSION_[GT,GE,EQ,LE,LT](maj,min,pat): evaluate to non-zero iff the compiler version in use is respectively greater-than, greater-or-equal, equal, less-or-equal, less-than the provided version components PLATFORM_COMPILER_IDSTR: a string which uniquely identifies recognized compilers PLATFORM_COMPILER_C_LANGLVL and PLATFORM_COMPILER_CXX_LANGLVL: (in PLATFORM_HEADER_VERSION >= 5) defined to a positive integral value corresponding to the C or C++ (respectively) language standard to which the current compiler advertises conformance. Otherwise undef (in particular at most one of these is defined in a given compilation). */ #if defined(__INTEL_COMPILER) #define PLATFORM_COMPILER_INTEL 1 #define PLATFORM_COMPILER_FAMILYNAME INTEL #define PLATFORM_COMPILER_FAMILYID 2 #ifdef __cplusplus #define PLATFORM_COMPILER_INTEL_CXX 1 #else #define PLATFORM_COMPILER_INTEL_C 1 #endif /* Intel compiler version "patch number" * ------------------------------------- * Intel compiler versioning is unfortunately complicated by behavioral changes. * Versions prior to Intel 14.0.0 (Sept 2013) lacked a preprocessor symbol to supply the "update" number. * Version 14.0.0 and later supply a __INTEL_COMPILER_UPDATE symbol, but sadly several releases of Version 19 * report the wrong value in this field (bug 3876). * For now, the "patch" field of the PLATFORM_COMPILER_VERSION for Intel is the release package BUILD DATE, * in the same decimal YYYYMMDD format as __INTEL_COMPILER_BUILD_DATE, as this is the only indicator that has * remained reliably stable/correct across versions. * So for example to check for icc --version "19.0.1.144 20181018" or later, pass: * PLATFORM_COMPILER_VERSION_GE(19, 0, 20181018) * NOTE 1: this build-date is unfortunately OS-DEPENDENT, sometimes differing by several days or weeks * between the Linux and OSX releases. For a complete mapping, see: * https://software.intel.com/en-us/articles/intel-compiler-and-composer-update-version-numbers-to-compiler-version-number-mapping * NOTE 2: some of the build-date entries in the table linked above have been observed to be incorrect, * so when possible it's safest to verify the build-date from `icc --version` on both Linux and macOS. */ #undef _PLATFORM_INTEL_COMPILER_BUILD_DATE #undef _PLATFORM_COMPILER_INTEL_MIN_BUILDDATE #define _PLATFORM_COMPILER_INTEL_MIN_BUILDDATE 19900000 /* year 1990: corresponds roughly to Intel v4.5 (1992) */ /* MIN_BUILDDATE is used to normalize build dates to a bit-saving range for the encoding * Intel officially supports the current release and two prior (currently back to 2016) * Our 1990 floor corresponds to Intel v4.x that only worked on MS-DOS and predates both Linux and BSD-based macOS */ #ifdef __INTEL_COMPILER_BUILD_DATE #define _PLATFORM_INTEL_COMPILER_BUILD_DATE __INTEL_COMPILER_BUILD_DATE #else #define _PLATFORM_INTEL_COMPILER_BUILD_DATE _PLATFORM_COMPILER_INTEL_MIN_BUILDDATE #endif /* Intel patch number is a decimal build date: YYYYMMDD - do NOT pass the "update number" */ #define PLATFORM_COMPILER_VERSION_INT(maj,min,pat) \ (((((maj) * 100) + (min)) << 19) | \ ((pat) < _PLATFORM_COMPILER_INTEL_MIN_BUILDDATE ? \ 0 : ((pat)-_PLATFORM_COMPILER_INTEL_MIN_BUILDDATE))) #undef _PLATFORM__INTEL_COMPILER #if __INTEL_COMPILER == 9999 /* Seen in 20110811 release of 12.1.0 - overflows VERSION_INT() */ #define _PLATFORM__INTEL_COMPILER 1201 #else #define _PLATFORM__INTEL_COMPILER __INTEL_COMPILER #endif #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(_PLATFORM__INTEL_COMPILER/100, _PLATFORM__INTEL_COMPILER%100, _PLATFORM_INTEL_COMPILER_BUILD_DATE) #define PLATFORM_COMPILER_VERSION_STR \ PLATFORM_STRINGIFY(_PLATFORM__INTEL_COMPILER) "." PLATFORM_STRINGIFY(_PLATFORM_INTEL_COMPILER_BUILD_DATE) #elif defined(__PATHSCALE__) #define PLATFORM_COMPILER_PATHSCALE 1 #define PLATFORM_COMPILER_FAMILYNAME PATHSCALE #define PLATFORM_COMPILER_FAMILYID 3 #ifdef __cplusplus #define PLATFORM_COMPILER_PATHSCALE_CXX 1 #else #define PLATFORM_COMPILER_PATHSCALE_C 1 #endif #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(__PATHCC__,__PATHCC_MINOR__,__PATHCC_PATCHLEVEL__+0) #define PLATFORM_COMPILER_VERSION_STR __PATHSCALE__ #elif defined(__NVCOMPILER) /* Must occur prior to PGI and CLANG */ #define PLATFORM_COMPILER_NVHPC 1 #define PLATFORM_COMPILER_FAMILYNAME NVHPC #define PLATFORM_COMPILER_FAMILYID 20 #ifdef __cplusplus #define PLATFORM_COMPILER_NVHPC_CXX 1 #else #define PLATFORM_COMPILER_NVHPC_C 1 #endif #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(__NVCOMPILER_MAJOR__,__NVCOMPILER_MINOR__,__NVCOMPILER_PATCHLEVEL__) #define PLATFORM_COMPILER_VERSION_STR \ PLATFORM_STRINGIFY(__NVCOMPILER_MAJOR__) "." PLATFORM_STRINGIFY(__NVCOMPILER_MINOR__) "-" PLATFORM_STRINGIFY(__NVCOMPILER_PATCHLEVEL__) #elif defined(__PGI) #define PLATFORM_COMPILER_PGI 1 #define PLATFORM_COMPILER_FAMILYNAME PGI #define PLATFORM_COMPILER_FAMILYID 4 #ifdef __cplusplus #define PLATFORM_COMPILER_PGI_CXX 1 #else #define PLATFORM_COMPILER_PGI_C 1 #endif #if __PGIC__ == 99 /* bug 2230: PGI versioning was broken for some platforms in 7.0 no way to know exact version, but provide something slightly more accurate */ #define PLATFORM_COMPILER_VERSION 0x070000 #define PLATFORM_COMPILER_VERSION_STR "7.?-?" #elif defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(__PGIC__,__PGIC_MINOR__,__PGIC_PATCHLEVEL__) #define PLATFORM_COMPILER_VERSION_STR \ PLATFORM_STRINGIFY(__PGIC__) "." PLATFORM_STRINGIFY(__PGIC_MINOR__) "-" PLATFORM_STRINGIFY(__PGIC_PATCHLEVEL__) #else /* PGI before 6.1-4 lacks any version ID preprocessor macros - so use this filthy hack */ #ifdef PLATFORM_PGI_IS_ANCIENT /* Include below might fail for ancient versions lacking this header, but testing shows it works back to at least 5.1-3 (Nov 2003), and based on docs probably back to 3.2 (Sep 2000) */ #define PLATFORM_COMPILER_VERSION 0 #elif defined(__x86_64__) /* bug 1753 - 64-bit omp.h upgrade happenned in <6.0-8,6.1-1] */ #include "omp.h" #if defined(_PGOMP_H) /* 6.1.1 or newer */ #define PLATFORM_COMPILER_VERSION 0x060101 #define PLATFORM_COMPILER_VERSION_STR ">=6.1-1" #else /* 6.0.8 or older */ #define PLATFORM_COMPILER_VERSION 0 #define PLATFORM_COMPILER_VERSION_STR "<=6.0-8" #endif #else /* 32-bit omp.h upgrade happenned in <5.2-4,6.0-8] */ #include "omp.h" #if defined(_PGOMP_H) /* 6.0-8 or newer */ #define PLATFORM_COMPILER_VERSION 0x060008 #define PLATFORM_COMPILER_VERSION_STR ">=6.0-8" #else /* 5.2-4 or older */ #define PLATFORM_COMPILER_VERSION 0 #define PLATFORM_COMPILER_VERSION_STR "<=5.2-4" #endif #endif #endif #elif defined(__xlC__) || defined(__ibmxl__) #define PLATFORM_COMPILER_XLC 1 #define PLATFORM_COMPILER_FAMILYNAME XLC #define PLATFORM_COMPILER_FAMILYID 5 #ifdef __cplusplus #define PLATFORM_COMPILER_XLC_CXX 1 #else #define PLATFORM_COMPILER_XLC_C 1 #endif #ifdef __ibmxl_version__ #define PLATFORM_COMPILER_VERSION \ (__ibmxl_version__ << 24 | __ibmxl_release__ << 16 | \ __ibmxl_modification__ << 8 | __ibmxl_ptf_fix_level__) #define PLATFORM_COMPILER_VERSION_STR \ PLATFORM_STRINGIFY(__ibmxl_version__) "." PLATFORM_STRINGIFY(__ibmxl_release__) "." PLATFORM_STRINGIFY(__ibmxl_modification__) "." PLATFORM_STRINGIFY(__ibmxl_ptf_fix_level__) #else #ifdef __xlC_ver__ #define PLATFORM_COMPILER_VERSION (__xlC__ << 16 | __xlC_ver__) #else #define PLATFORM_COMPILER_VERSION (__xlC__ << 16) #endif #ifdef __xlc__ #define PLATFORM_COMPILER_VERSION_STR __xlc__ #else #define PLATFORM_COMPILER_VERSION_STR PLATFORM_STRINGIFY(__xlC__) #endif #endif #define PLATFORM_COMPILER_VERSION_INT(maj,min,pat) \ ( ((maj) << 24) | ((min) << 16) | ((pat) << 8) ) #elif defined(__DECC) || defined(__DECCXX) #define PLATFORM_COMPILER_COMPAQ 1 #define PLATFORM_COMPILER_FAMILYNAME COMPAQ #define PLATFORM_COMPILER_FAMILYID 6 #ifdef __cplusplus #define PLATFORM_COMPILER_COMPAQ_CXX 1 #else #define PLATFORM_COMPILER_COMPAQ_C 1 #endif #if defined(__DECC_VER) #define PLATFORM_COMPILER_VERSION __DECC_VER #elif defined(__DECCXX_VER) #define PLATFORM_COMPILER_VERSION __DECCXX_VER #endif #define PLATFORM_COMPILER_VERSION_INT(maj,min,pat) \ ( ((maj) * 10000000) + ((min) * 100000) + (90000) + (pat) ) /* 90000 = official ver, 80000 = customer special ver, 60000 = field test ver */ #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) #define PLATFORM_COMPILER_SUN 1 #define PLATFORM_COMPILER_FAMILYNAME SUN #define PLATFORM_COMPILER_FAMILYID 7 #ifdef __cplusplus #define PLATFORM_COMPILER_SUN_CXX 1 #else #define PLATFORM_COMPILER_SUN_C 1 #endif #if defined(__SUNPRO_C) && __SUNPRO_C > 0 #define PLATFORM_COMPILER_VERSION __SUNPRO_C #elif defined(__SUNPRO_CC) && __SUNPRO_CC > 0 #define PLATFORM_COMPILER_VERSION __SUNPRO_CC #endif /* Sun version numbers look like hex but are actually a sloppy concatenation of decimal version numbers * leading to weird discontinuities in the version space, luckily it remains monotonic (so far) */ #define PLATFORM_COMPILER_VERSION_INT(maj,min,pat) ( \ (min) < 10 ? \ ( ((maj) << 8) | ((min) << 4) | (pat) ) : \ ( ((maj) << 12) | (((min)/10) << 8) | (((min)%10) << 4) | (pat) ) ) #elif defined(__HP_cc) || defined(__HP_aCC) #define PLATFORM_COMPILER_HP 1 #define PLATFORM_COMPILER_FAMILYNAME HP #define PLATFORM_COMPILER_FAMILYID 8 #ifdef __cplusplus #define PLATFORM_COMPILER_HP_CXX 1 #else #define PLATFORM_COMPILER_HP_C 1 #endif #if defined(__HP_cc) && __HP_cc > 0 #define PLATFORM_COMPILER_VERSION __HP_cc #elif defined(__HP_aCC) && __HP_aCC > 0 #define PLATFORM_COMPILER_VERSION __HP_aCC #endif #define PLATFORM_COMPILER_VERSION_INT(maj,min,pat) \ ( ((maj) << 16) | ((min) << 8) | (pat) ) #elif defined(_SGI_COMPILER_VERSION) || \ (defined(_COMPILER_VERSION) && defined(__sgi) && !defined(__GNUC__)) /* 7.3.0 and earlier lack _SGI_COMPILER_VERSION */ #define PLATFORM_COMPILER_SGI 1 #define PLATFORM_COMPILER_FAMILYNAME SGI #define PLATFORM_COMPILER_FAMILYID 9 #ifdef __cplusplus #define PLATFORM_COMPILER_SGI_CXX 1 #else #define PLATFORM_COMPILER_SGI_C 1 #endif #if defined(_SGI_COMPILER_VERSION) && _SGI_COMPILER_VERSION > 0 #define PLATFORM_COMPILER_VERSION _SGI_COMPILER_VERSION #elif defined(_COMPILER_VERSION) && _COMPILER_VERSION > 0 #define PLATFORM_COMPILER_VERSION _COMPILER_VERSION #endif #define PLATFORM_COMPILER_VERSION_INT(maj,min,pat) \ ( ((maj) << 8) | ((min) << 4) | (pat) ) #elif defined(_CRAYC) #define PLATFORM_COMPILER_CRAY 1 #define PLATFORM_COMPILER_FAMILYNAME CRAY #define PLATFORM_COMPILER_FAMILYID 10 #ifdef __cplusplus #define PLATFORM_COMPILER_CRAY_CXX 1 #else #define PLATFORM_COMPILER_CRAY_C 1 #endif #if defined(_RELEASE_MAJOR) && defined(_RELEASE_MINOR) /* XE, XK, XC */ #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(_RELEASE_MAJOR,_RELEASE_MINOR,0) #elif defined(_RELEASE) && defined(_RELEASE_MINOR) /* X1 and XT */ #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(_RELEASE,_RELEASE_MINOR,0) #elif defined(_RELEASE) /* T3E */ #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(_RELEASE,0,0) #endif #ifdef _RELEASE_STRING /* X1 and XT, XK, XC */ #define PLATFORM_COMPILER_VERSION_STR _RELEASE_STRING #endif #elif defined(__KCC) #define PLATFORM_COMPILER_KAI 1 #define PLATFORM_COMPILER_FAMILYNAME KAI #define PLATFORM_COMPILER_FAMILYID 11 #ifdef __cplusplus #define PLATFORM_COMPILER_KAI_CXX 1 #else #define PLATFORM_COMPILER_KAI_C 1 #endif #elif defined(__MTA__) #define PLATFORM_COMPILER_MTA 1 #define PLATFORM_COMPILER_FAMILYNAME MTA #define PLATFORM_COMPILER_FAMILYID 12 #ifdef __cplusplus #define PLATFORM_COMPILER_MTA_CXX 1 #else #define PLATFORM_COMPILER_MTA_C 1 #endif #elif defined(_SX) #define PLATFORM_COMPILER_NECSX 1 #define PLATFORM_COMPILER_FAMILYNAME NECSX #define PLATFORM_COMPILER_FAMILYID 13 #ifdef __cplusplus #define PLATFORM_COMPILER_NECSX_CXX 1 #else #define PLATFORM_COMPILER_NECSX_C 1 #endif #elif defined(_MSC_VER) #define PLATFORM_COMPILER_MICROSOFT 1 #define PLATFORM_COMPILER_FAMILYNAME MICROSOFT #define PLATFORM_COMPILER_FAMILYID 14 #ifdef __cplusplus #define PLATFORM_COMPILER_MICROSOFT_CXX 1 #else #define PLATFORM_COMPILER_MICROSOFT_C 1 #endif #define PLATFORM_COMPILER_VERSION _MSC_VER #elif defined(__TINYC__) #define PLATFORM_COMPILER_TINY 1 #define PLATFORM_COMPILER_FAMILYNAME TINY #define PLATFORM_COMPILER_FAMILYID 15 #ifdef __cplusplus #define PLATFORM_COMPILER_TINY_CXX 1 #else #define PLATFORM_COMPILER_TINY_C 1 #endif #elif defined(__LCC__) #define PLATFORM_COMPILER_LCC 1 #define PLATFORM_COMPILER_FAMILYNAME LCC #define PLATFORM_COMPILER_FAMILYID 16 #ifdef __cplusplus #define PLATFORM_COMPILER_LCC_CXX 1 #else #define PLATFORM_COMPILER_LCC_C 1 #endif #elif defined(__OPENCC__) #define PLATFORM_COMPILER_OPEN64 1 #define PLATFORM_COMPILER_FAMILYNAME OPEN64 #define PLATFORM_COMPILER_FAMILYID 17 #ifdef __cplusplus #define PLATFORM_COMPILER_OPEN64_CXX 1 #else #define PLATFORM_COMPILER_OPEN64_C 1 #endif /* Note: can't use __OPENCC_PATCHLEVEL__ because it is sometimes non-integer (eg 3.2). Adding a cast would not result in a preprocessor constant expression. */ #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(__OPENCC__,__OPENCC_MINOR__,0) #define PLATFORM_COMPILER_VERSION_STR __OPEN64__ #elif defined(__PCC__) #define PLATFORM_COMPILER_PCC 1 #define PLATFORM_COMPILER_FAMILYNAME PCC #define PLATFORM_COMPILER_FAMILYID 18 #ifdef __cplusplus #define PLATFORM_COMPILER_PCC_CXX 1 #else #define PLATFORM_COMPILER_PCC_C 1 #endif #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(__PCC__,__PCC_MINOR__,__PCC_MINORMINOR__) #define PLATFORM_COMPILER_VERSION_STR \ PLATFORM_STRINGIFY(__PCC__) "." PLATFORM_STRINGIFY(__PCC_MINOR__) "." PLATFORM_STRINGIFY(__PCC_MINORMINOR__) #elif defined(__clang__) #define PLATFORM_COMPILER_CLANG 1 #define PLATFORM_COMPILER_FAMILYNAME CLANG #define PLATFORM_COMPILER_FAMILYID 19 #ifdef __cplusplus #define PLATFORM_COMPILER_CLANG_CXX 1 #else #define PLATFORM_COMPILER_CLANG_C 1 #endif #ifdef __clang_version__ /* clang 2.7 (gcc 4.2.1 compliant) and earlier lacked specific version identification */ #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(__clang_major__,__clang_minor__,__clang_patchlevel__) #define PLATFORM_COMPILER_VERSION_STR __clang_version__ #endif /* NOTE: PLATFORM_COMPILER_FAMILYID "20" is allocted to NVHPC, appearing earlier */ #else /* unknown compiler */ #define PLATFORM_COMPILER_UNKNOWN 1 #endif /* this stanza comes last, because many vendor compilers lie and claim to be GNU C for compatibility reasons and/or because they share a frontend */ #undef _PLATFORM_COMPILER_GNU_VERSION_STR #undef __PLATFORM_COMPILER_GNU_VERSION_STR #if defined(__GNUC__) #undef PLATFORM_COMPILER_UNKNOWN #ifndef PLATFORM_COMPILER_FAMILYID #define PLATFORM_COMPILER_GNU 1 #define PLATFORM_COMPILER_FAMILYNAME GNU #define PLATFORM_COMPILER_FAMILYID 1 #ifdef __cplusplus #define PLATFORM_COMPILER_GNU_CXX 1 #else #define PLATFORM_COMPILER_GNU_C 1 #endif #if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) #elif defined(__GNUC_MINOR__) /* older versions of egcs lack __GNUC_PATCHLEVEL__ */ #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(__GNUC__,__GNUC_MINOR__,0) #else #define PLATFORM_COMPILER_VERSION \ PLATFORM_COMPILER_VERSION_INT(__GNUC__,0,0) #endif #define PLATFORM_COMPILER_VERSION_STR __PLATFORM_COMPILER_GNU_VERSION_STR #else #define _PLATFORM_COMPILER_GNU_VERSION_STR __PLATFORM_COMPILER_GNU_VERSION_STR #endif /* gather any advertised GNU version number info, even for non-gcc compilers */ #if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) #define __PLATFORM_COMPILER_GNU_VERSION_STR \ PLATFORM_STRINGIFY(__GNUC__) "." PLATFORM_STRINGIFY(__GNUC_MINOR__) "." PLATFORM_STRINGIFY(__GNUC_PATCHLEVEL__) #elif defined(__GNUC_MINOR__) #define __PLATFORM_COMPILER_GNU_VERSION_STR \ PLATFORM_STRINGIFY(__GNUC__) "." PLATFORM_STRINGIFY(__GNUC_MINOR__) ".?" #else #define __PLATFORM_COMPILER_GNU_VERSION_STR \ PLATFORM_STRINGIFY(__GNUC__) ".?.?" #endif #elif defined(PLATFORM_COMPILER_UNKNOWN) /* unknown compiler */ #define PLATFORM_COMPILER_FAMILYNAME UNKNOWN #define PLATFORM_COMPILER_FAMILYID 0 #endif /* defaulting */ #ifndef PLATFORM_COMPILER_VERSION #define PLATFORM_COMPILER_VERSION 0 /* don't know */ #endif #ifndef PLATFORM_COMPILER_VERSION_STR #define PLATFORM_COMPILER_VERSION_STR PLATFORM_STRINGIFY(PLATFORM_COMPILER_VERSION) #endif #ifndef PLATFORM_COMPILER_VERSION_INT #define PLATFORM_COMPILER_VERSION_INT(maj,min,pat) \ (((maj) << 16) | ((min) << 8) | (pat)) #endif /* version check macros */ #define PLATFORM_COMPILER_VERSION_GT(maj,min,pat) \ PLATFORM_COMPILER_VERSION > PLATFORM_COMPILER_VERSION_INT(maj,min,pat) #define PLATFORM_COMPILER_VERSION_GE(maj,min,pat) \ PLATFORM_COMPILER_VERSION >= PLATFORM_COMPILER_VERSION_INT(maj,min,pat) #define PLATFORM_COMPILER_VERSION_EQ(maj,min,pat) \ PLATFORM_COMPILER_VERSION == PLATFORM_COMPILER_VERSION_INT(maj,min,pat) #define PLATFORM_COMPILER_VERSION_LE(maj,min,pat) \ PLATFORM_COMPILER_VERSION <= PLATFORM_COMPILER_VERSION_INT(maj,min,pat) #define PLATFORM_COMPILER_VERSION_LT(maj,min,pat) \ PLATFORM_COMPILER_VERSION < PLATFORM_COMPILER_VERSION_INT(maj,min,pat) /* misc feature detection */ #ifdef __cplusplus #define PLATFORM_COMPILER_ID (10000+PLATFORM_COMPILER_FAMILYID) #else #define PLATFORM_COMPILER_ID PLATFORM_COMPILER_FAMILYID #endif /* default language spec conformance detection */ #if !defined(PLATFORM_COMPILER_C_LANGLVL) && !defined(PLATFORM_COMPILER_CXX_LANGLVL) #if defined(__cplusplus) && (__cplusplus > 0) /* C++98 or newer */ #define PLATFORM_COMPILER_CXX_LANGLVL __cplusplus #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ > 0) /* C95 or newer */ #define PLATFORM_COMPILER_C_LANGLVL __STDC_VERSION__ #elif defined(__STDC__) && !defined(__cplusplus) && !defined(__STDC_VERSION__) /* C89/C90 */ #define PLATFORM_COMPILER_C_LANGLVL 199000L #else /* unknown - leave both undef */ #endif #endif #undef _PLATFORM_COMPILER_STD_STDC #ifdef __STDC__ #define _PLATFORM_COMPILER_STD_STDC "__STDC__" #else #define _PLATFORM_COMPILER_STD_STDC "-" #endif #undef _PLATFORM_COMPILER_STD_STDC_VERSION #ifdef __STDC_VERSION__ #define _PLATFORM_COMPILER_STD_STDC_VERSION ",__STDC_VERSION__=" PLATFORM_STRINGIFY(__STDC_VERSION__) #else #define _PLATFORM_COMPILER_STD_STDC_VERSION #endif #undef _PLATFORM_COMPILER_STD_STDC_EXT #ifdef __STDC_EXT__ #define _PLATFORM_COMPILER_STD_STDC_EXT ",__STDC_EXT__=" PLATFORM_STRINGIFY(__STDC_EXT__) #else #define _PLATFORM_COMPILER_STD_STDC_EXT #endif #undef _PLATFORM_COMPILER_STD_CPLUSPLUS #ifdef __cplusplus #define _PLATFORM_COMPILER_STD_CPLUSPLUS ",__cplusplus=" PLATFORM_STRINGIFY(__cplusplus) #else #define _PLATFORM_COMPILER_STD_CPLUSPLUS #endif #undef _PLATFORM_COMPILER_MISC_VERSION_STR #ifndef _PLATFORM_COMPILER_MISC_VERSION_STR #ifdef __VERSION__ #define _PLATFORM_COMPILER_MISC_VERSION_STR "|misc:" __VERSION__ #else #define _PLATFORM_COMPILER_MISC_VERSION_STR #endif #endif #undef _PLATFORM_COMPILER_GNU_VERSION_STR_HELP #ifdef _PLATFORM_COMPILER_GNU_VERSION_STR #define _PLATFORM_COMPILER_GNU_VERSION_STR_HELP "|GNU:" _PLATFORM_COMPILER_GNU_VERSION_STR #else #define _PLATFORM_COMPILER_GNU_VERSION_STR_HELP #endif #define PLATFORM_COMPILER_IDSTR \ "|COMPILER_FAMILY:" \ PLATFORM_STRINGIFY(PLATFORM_COMPILER_FAMILYNAME) \ "|COMPILER_VERSION:" PLATFORM_COMPILER_VERSION_STR \ "|COMPILER_FAMILYID:" \ PLATFORM_STRINGIFY(PLATFORM_COMPILER_FAMILYID) \ _PLATFORM_COMPILER_GNU_VERSION_STR_HELP \ "|STD:" _PLATFORM_COMPILER_STD_STDC \ _PLATFORM_COMPILER_STD_STDC_VERSION \ _PLATFORM_COMPILER_STD_STDC_EXT \ _PLATFORM_COMPILER_STD_CPLUSPLUS \ _PLATFORM_COMPILER_MISC_VERSION_STR \ "|" /* ------------------------------------------------------------------------------------ */ /* OS detection */ /* PLATFORM_OS_: defined to a positive value if OS belongs to a given family, undef otherwise PLATFORM_OS_FAMILYNAME: unquoted token which provides the OS family name Some systems also define a subfamily: PLATFORM_OS_SUBFAMILY_: positive value or undef PLATFORM_OS_SUBFAMILYNAME: unquoted token for subfamily name or undef */ #if defined(__LIBCATAMOUNT__) || defined(__QK_USER__) #define PLATFORM_OS_CATAMOUNT 1 #define PLATFORM_OS_FAMILYNAME CATAMOUNT #elif defined(GASNETI_ARCH_BGP) || defined(__bgp__) #define PLATFORM_OS_BGP 1 #define PLATFORM_OS_FAMILYNAME BGP #elif defined(GASNETI_ARCH_BGQ) || defined(__bgq__) #define PLATFORM_OS_BGQ 1 #define PLATFORM_OS_FAMILYNAME BGQ #elif defined(__K42) #define PLATFORM_OS_K42 1 #define PLATFORM_OS_FAMILYNAME K42 #elif defined(__uClinux__) #define PLATFORM_OS_UCLINUX 1 #define PLATFORM_OS_FAMILYNAME UCLINUX #elif defined(__linux) || defined(__linux__) || defined(__gnu_linux__) #define PLATFORM_OS_LINUX 1 #define PLATFORM_OS_FAMILYNAME LINUX #if defined(GASNETI_ARCH_WSL) #define PLATFORM_OS_SUBFAMILY_WSL 1 #define PLATFORM_OS_SUBFAMILYNAME WSL #elif defined(__CRAYXT_COMPUTE_LINUX_TARGET) /* NOTE: As of 2022-07 this is ONLY defined for the Cray cc/CC wrappers, and not the raw PrgEnv compilers */ #define PLATFORM_OS_SUBFAMILY_CNL 1 #define PLATFORM_OS_SUBFAMILYNAME CNL #endif #elif defined(__blrts) || defined(__blrts__) || defined(__gnu_blrts__) #define PLATFORM_OS_BLRTS 1 #define PLATFORM_OS_FAMILYNAME BLRTS #elif defined(__CYGWIN__) #define PLATFORM_OS_CYGWIN 1 #define PLATFORM_OS_FAMILYNAME CYGWIN #elif defined(_WIN32) #define PLATFORM_OS_MSWINDOWS 1 #define PLATFORM_OS_FAMILYNAME MSWINDOWS #elif defined(_AIX) #define PLATFORM_OS_AIX 1 #define PLATFORM_OS_FAMILYNAME AIX #elif defined(__osf__) || defined(__digital__) #define PLATFORM_OS_TRU64 1 #define PLATFORM_OS_FAMILYNAME TRU64 #elif defined(__FreeBSD) || defined(__FreeBSD__) #define PLATFORM_OS_FREEBSD 1 #define PLATFORM_OS_FAMILYNAME FREEBSD #elif defined(__NetBSD) || defined(__NetBSD__) #define PLATFORM_OS_NETBSD 1 #define PLATFORM_OS_FAMILYNAME NETBSD #elif defined(__OpenBSD__) #define PLATFORM_OS_OPENBSD 1 #define PLATFORM_OS_FAMILYNAME OPENBSD #elif defined(__sun) || defined(__sun__) #define PLATFORM_OS_SOLARIS 1 #define PLATFORM_OS_FAMILYNAME SOLARIS #elif (defined(__APPLE__) && defined(__MACH__)) || \ defined(__osx86__) /* PGI on OSX */ #define PLATFORM_OS_DARWIN 1 #define PLATFORM_OS_FAMILYNAME DARWIN #elif defined(__sgi) || defined(__sgi__) #define PLATFORM_OS_IRIX 1 #define PLATFORM_OS_FAMILYNAME IRIX #elif defined(__hpux) || defined(__hpux__) #define PLATFORM_OS_HPUX 1 #define PLATFORM_OS_FAMILYNAME HPUX #elif defined(_CRAY) || defined(_UNICOSMP) #define PLATFORM_OS_UNICOS 1 #define PLATFORM_OS_FAMILYNAME UNICOS #elif defined(__MTA__) #define PLATFORM_OS_MTA 1 #define PLATFORM_OS_FAMILYNAME MTA #elif defined(_SX) #define PLATFORM_OS_SUPERUX 1 #define PLATFORM_OS_FAMILYNAME SUPERUX #else #define PLATFORM_OS_UNKNOWN 1 #define PLATFORM_OS_FAMILYNAME UNKNOWN #endif /* ------------------------------------------------------------------------------------ */ /* Architecture detection */ /* PLATFORM_ARCH_: defined to positive value if CPU belongs to a given family, undef otherwise PLATFORM_ARCH_FAMILYNAME: unquoted token which provides the CPU family name PLATFORM_ARCH_32 - 32-bit pointers PLATFORM_ARCH_64 - 64-bit pointers PLATFORM_ARCH_BIG_ENDIAN - big-endian word order PLATFORM_ARCH_LITTLE_ENDIAN - little-endian word order defined to positive value if CPU is known to have the indicated property, undef otherwise */ #if defined(__ppc64) || defined(__ppc64__) || \ defined(__PPC64) || defined(__PPC64__) || \ defined(__powerpc64) || defined(__powerpc64__) #define PLATFORM_ARCH_POWERPC 1 #define PLATFORM_ARCH_FAMILYNAME POWERPC #define _PLATFORM_ARCH_64 1 #define _PLATFORM_ARCH_BIG_ENDIAN 1 #elif defined(_POWER) || \ defined(__PPC) || defined(__PPC__) || \ defined(__powerpc) || defined(__powerpc__) || \ defined(__ppc) || defined(__ppc__) || \ defined(__POWERPC__) #define PLATFORM_ARCH_POWERPC 1 #define PLATFORM_ARCH_FAMILYNAME POWERPC #define _PLATFORM_ARCH_32 1 #define _PLATFORM_ARCH_BIG_ENDIAN 1 #elif defined(_ARCH_PPC) || defined(_ARCH_PPC64) #define PLATFORM_ARCH_POWERPC 1 #define PLATFORM_ARCH_FAMILYNAME POWERPC #define _PLATFORM_ARCH_BIG_ENDIAN 1 #elif defined(__KNC__) || defined(__MIC__) #define PLATFORM_ARCH_MIC 1 #define PLATFORM_ARCH_FAMILYNAME MIC #define _PLATFORM_ARCH_64 1 #define _PLATFORM_ARCH_LITTLE_ENDIAN 1 #elif defined(__x86_64) || defined(__x86_64__) || \ defined(__athlon) || defined(__athlon__) || \ defined(__amd64) || defined(__amd64__) #define PLATFORM_ARCH_X86_64 1 #define PLATFORM_ARCH_FAMILYNAME X86_64 #define _PLATFORM_ARCH_64 1 #define _PLATFORM_ARCH_LITTLE_ENDIAN 1 #elif defined(__ia64__) || defined(__ia64) #define PLATFORM_ARCH_IA64 1 #define PLATFORM_ARCH_FAMILYNAME IA64 #define _PLATFORM_ARCH_64 1 #if defined(PLATFORM_OS_LINUX) || defined(PLATFORM_OS_FREEBSD) #define _PLATFORM_ARCH_LITTLE_ENDIAN 1 #elif defined(PLATFORM_OS_HPUX) #define _PLATFORM_ARCH_BIG_ENDIAN 1 #else /* Unknown. Hope one of the other mechanisms can sort it out. */ #endif #elif defined(__i386__) || defined(__i386) || \ defined(__i486__) || defined(__i486) || \ defined(__i586__) || defined(__i586) || \ defined(__i686__) || defined(__i686) || \ defined(__pentiumpro) || defined(__pentiumpro__) || \ defined(_M_IX86) #define PLATFORM_ARCH_X86 1 #define PLATFORM_ARCH_FAMILYNAME X86 #define _PLATFORM_ARCH_32 1 #define _PLATFORM_ARCH_LITTLE_ENDIAN 1 #elif defined(__alpha) || defined(__alpha__) #define PLATFORM_ARCH_ALPHA 1 #define PLATFORM_ARCH_FAMILYNAME ALPHA #define _PLATFORM_ARCH_64 1 #define _PLATFORM_ARCH_LITTLE_ENDIAN 1 #elif defined(_mips) || defined(__mips) || defined(__mips__) || \ defined(__host_mips) || defined(__host_mips__) || \ defined(_MIPS_ARCH) || defined(__R4000) #define PLATFORM_ARCH_MIPS 1 #define PLATFORM_ARCH_FAMILYNAME MIPS #ifdef _MIPSEL /* MIPS cores support both little and big endian modes */ /* SiCortex */ #define _PLATFORM_ARCH_LITTLE_ENDIAN 1 #else /* IRIX */ #define _PLATFORM_ARCH_BIG_ENDIAN 1 #endif #ifdef _MIPS_SZPTR #if _MIPS_SZPTR == 32 #define _PLATFORM_ARCH_32 1 #elif _MIPS_SZPTR == 64 #define _PLATFORM_ARCH_64 1 #endif #endif #elif defined(__sparc) || defined(__sparc__) || \ defined(__sparclet__) || defined(__sparclite__) || \ defined(__sparcv8) || defined(__sparcv9) #define PLATFORM_ARCH_SPARC 1 #define PLATFORM_ARCH_FAMILYNAME SPARC #define _PLATFORM_ARCH_BIG_ENDIAN 1 #elif defined(__hppa) || defined(__hppa__) || \ defined(__parisc) || defined(__parisc__) || \ defined(_PA_RISC1_1) || defined(_PA_RISC2_0) #define PLATFORM_ARCH_PARISC 1 #define PLATFORM_ARCH_FAMILYNAME PARISC #define _PLATFORM_ARCH_BIG_ENDIAN 1 #elif defined(__crayx1) #define PLATFORM_ARCH_CRAYX1 1 #define PLATFORM_ARCH_FAMILYNAME CRAYX1 #define _PLATFORM_ARCH_BIG_ENDIAN 1 #define _PLATFORM_ARCH_64 1 #elif defined(_CRAYT3E) #define PLATFORM_ARCH_CRAYT3E 1 #define PLATFORM_ARCH_FAMILYNAME CRAYT3E #define _PLATFORM_ARCH_BIG_ENDIAN 1 #define _PLATFORM_ARCH_64 1 #elif defined(__MTA__) #define PLATFORM_ARCH_MTA 1 #define PLATFORM_ARCH_FAMILYNAME MTA #elif defined(_SX) #define PLATFORM_ARCH_NECSX 1 #define PLATFORM_ARCH_FAMILYNAME NECSX #elif defined(__MICROBLAZE__) #define PLATFORM_ARCH_MICROBLAZE 1 #define PLATFORM_ARCH_FAMILYNAME MICROBLAZE #define _PLATFORM_ARCH_BIG_ENDIAN 1 #define _PLATFORM_ARCH_32 1 #elif defined(__arm__) #define PLATFORM_ARCH_ARM 1 #define PLATFORM_ARCH_FAMILYNAME ARM #define _PLATFORM_ARCH_32 1 #if defined(__ARMEB__) #define _PLATFORM_ARCH_BIG_ENDIAN 1 #elif defined(__ARMEL__) #define _PLATFORM_ARCH_LITTLE_ENDIAN 1 #endif #elif defined(__aarch64__) #define PLATFORM_ARCH_AARCH64 1 #define PLATFORM_ARCH_FAMILYNAME AARCH64 #if defined(__AARCH64EB__) #define _PLATFORM_ARCH_BIG_ENDIAN 1 #elif defined(__AARCH64EL__) #define _PLATFORM_ARCH_LITTLE_ENDIAN 1 #endif #elif defined(__tile__) #define PLATFORM_ARCH_TILE 1 #define PLATFORM_ARCH_FAMILYNAME TILE #define _PLATFORM_ARCH_LITTLE_ENDIAN 1 #if defined(__tilegx__) #define _PLATFORM_ARCH_64 1 #else #define _PLATFORM_ARCH_32 1 #endif #elif defined(__s390__) #define PLATFORM_ARCH_S390 1 #define PLATFORM_ARCH_FAMILYNAME S390 #define _PLATFORM_ARCH_BIG_ENDIAN 1 #if defined(__s390x__) #define _PLATFORM_ARCH_64 1 #else #define _PLATFORM_ARCH_32 1 #endif #elif defined(__riscv) #define PLATFORM_ARCH_RISCV 1 #define PLATFORM_ARCH_FAMILYNAME RISCV #define _PLATFORM_ARCH_LITTLE_ENDIAN 1 #if __riscv_xlen == 32 #define _PLATFORM_ARCH_32 1 #else /* (__riscv_xlen == 64) || (__riscv_xlen == 128) */ #define _PLATFORM_ARCH_64 1 #endif #else /* unknown CPU */ #define PLATFORM_ARCH_UNKNOWN 1 #define PLATFORM_ARCH_FAMILYNAME UNKNOWN #endif /* generic chip properties */ #if defined(PLATFORM_ARCH_BIG_ENDIAN) || defined(PLATFORM_ARCH_LITTLE_ENDIAN) #error internal error in endianness configuration #endif /* PLATFORM_ARCH_{BIG,LITTLE}_ENDIAN: first detect common preprocessor defines then default to any arch-specific value provided */ #if defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) || \ ( __BYTE_ORDER__ > 0 && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ) #define PLATFORM_ARCH_BIG_ENDIAN 1 #elif defined(__LITTLE_ENDIAN__) || defined(WORDS_LITTLEENDIAN) || \ ( __BYTE_ORDER__ > 0 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ) #define PLATFORM_ARCH_LITTLE_ENDIAN 1 #elif defined(_PLATFORM_ARCH_BIG_ENDIAN) #define PLATFORM_ARCH_BIG_ENDIAN 1 #elif defined(_PLATFORM_ARCH_LITTLE_ENDIAN) #define PLATFORM_ARCH_LITTLE_ENDIAN 1 #endif #undef _PLATFORM_ARCH_BIG_ENDIAN #undef _PLATFORM_ARCH_LITTLE_ENDIAN #if defined(PLATFORM_ARCH_BIG_ENDIAN) && defined(PLATFORM_ARCH_LITTLE_ENDIAN) #error conflicting endianness information #endif /* PLATFORM_ARCH_{32,64}: first trust SIZEOF_VOID_P, which is most likely to be accurate next, detect common 32/64 preprocessor defines finally default to any arch-specific value provided */ #if defined(PLATFORM_ARCH_64) || defined(PLATFORM_ARCH_32) #error internal error in bit width configuration #endif #if SIZEOF_VOID_P == 8 #define PLATFORM_ARCH_64 1 #elif SIZEOF_VOID_P == 4 #define PLATFORM_ARCH_32 1 #elif defined(_LP64) || defined(__LP64__) || \ defined(__arch64__) || defined(__64BIT__) || \ __INTPTR_MAX__ > 2147483647 #define PLATFORM_ARCH_64 1 #elif defined(_ILP32) || defined(__ILP32__) || \ defined(__arch32__) || defined(__32BIT__) || \ __INTPTR_MAX__ == 2147483647 #define PLATFORM_ARCH_32 1 #elif defined(_PLATFORM_ARCH_64) #define PLATFORM_ARCH_64 1 #elif defined(_PLATFORM_ARCH_32) #define PLATFORM_ARCH_32 1 #endif #undef _PLATFORM_ARCH_64 #undef _PLATFORM_ARCH_32 #if defined(PLATFORM_ARCH_64) && defined(PLATFORM_ARCH_32) #error conflicting bit width information #elif !defined(PLATFORM_ARCH_64) && !defined(PLATFORM_ARCH_32) #error missing bit width information #endif /* ------------------------------------------------------------------------------------ */ /* handy test code that can be parsed after preprocess or executed to show platform results */ #ifdef PLATFORM_SHOW #include #include const char * COMPILER_FAMILYNAME = PLATFORM_STRINGIFY(PLATFORM_COMPILER_FAMILYNAME) , * COMPILER_FAMILYID = PLATFORM_STRINGIFY(PLATFORM_COMPILER_FAMILYID) , * COMPILER_VERSION_STR = PLATFORM_COMPILER_VERSION_STR , * COMPILER_IDSTR = PLATFORM_COMPILER_IDSTR , * OS_FAMILYNAME = PLATFORM_STRINGIFY(PLATFORM_OS_FAMILYNAME) , * ARCH_FAMILYNAME = PLATFORM_STRINGIFY(PLATFORM_ARCH_FAMILYNAME) ; int main(void) { #define PLATFORM_DISP(x) printf("PLATFORM_"#x"=%s\n",x) #define PLATFORM_DISPI(x) printf("PLATFORM_"#x"=%li\n",(long int)PLATFORM_##x) #define PLATFORM_DISPX(x) printf("PLATFORM_"#x"=0x%lx\n",(long int)PLATFORM_##x) PLATFORM_DISP(COMPILER_FAMILYNAME); PLATFORM_DISP(COMPILER_FAMILYID); PLATFORM_DISPI(COMPILER_ID); PLATFORM_DISPX(COMPILER_VERSION); PLATFORM_DISP(COMPILER_VERSION_STR); PLATFORM_DISP(COMPILER_IDSTR); #ifdef PLATFORM_COMPILER_C_LANGLVL PLATFORM_DISPI(COMPILER_C_LANGLVL); #elif defined(PLATFORM_COMPILER_CXX_LANGLVL) PLATFORM_DISPI(COMPILER_CXX_LANGLVL); #else printf("WARNING: Missing PLATFORM_COMPILER_C(XX)_LANGLVL!"); #endif PLATFORM_DISP(OS_FAMILYNAME); #ifdef PLATFORM_OS_SUBFAMILYNAME { const char * OS_SUBFAMILYNAME = PLATFORM_STRINGIFY(PLATFORM_OS_SUBFAMILYNAME); PLATFORM_DISP(OS_SUBFAMILYNAME); } #endif PLATFORM_DISP(ARCH_FAMILYNAME); #ifdef PLATFORM_ARCH_32 PLATFORM_DISPI(ARCH_32); assert(sizeof(void *) == 4); #else PLATFORM_DISPI(ARCH_64); assert(sizeof(void *) == 8); #endif { int x = 0x00FF; unsigned char *p = (unsigned char *)&x; #ifdef PLATFORM_ARCH_BIG_ENDIAN PLATFORM_DISPI(ARCH_BIG_ENDIAN); assert(*p == 0); #else PLATFORM_DISPI(ARCH_LITTLE_ENDIAN); assert(*p == 0xFF); #endif } return 0; } #endif /* ------------------------------------------------------------------------------------ */ #endif pmix-6.1.1~rc2/src/include/pmix_stdint.h0000664000175000017500000000674615203536752020437 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2023 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2018 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * This file includes the C99 stdint.h file if available, and otherwise * defines fixed-width types according to the SIZEOF information * gathered by configure. */ #ifndef PMIX_STDINT_H #define PMIX_STDINT_H 1 #include "src/include/pmix_config.h" /* * Include what we can and define what is missing. */ #include #include #ifdef HAVE_SYS_TYPES_H # include #endif /* 128-bit */ #ifdef HAVE_INT128_T typedef int128_t pmix_int128_t; typedef uint128_t pmix_uint128_t; # define HAVE_PMIX_INT128_T 1 #elif defined(HAVE___INT128) /* suppress warning about __int128 type */ # pragma GCC diagnostic push /* Clang won't quietly accept "-pedantic", but GCC versions older than ~4.8 * won't quietly accept "-Wpedanic". The whole "#pragma GCC diagnostic ..." * facility only was added to GCC as of version 4.6. */ # if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 6) # pragma GCC diagnostic ignored "-Wpedantic" # else # pragma GCC diagnostic ignored "-pedantic" # endif typedef __int128 pmix_int128_t; typedef unsigned __int128 pmix_uint128_t; # pragma GCC diagnostic pop # define HAVE_PMIX_INT128_T 1 #else # define HAVE_PMIX_INT128_T 0 #endif /* Pointers */ #if SIZEOF_VOID_P == SIZEOF_INT # ifndef HAVE_INTPTR_T typedef signed int intptr_t; # endif # ifndef HAVE_UINTPTR_T typedef unsigned int uintptr_t; # endif #elif SIZEOF_VOID_P == SIZEOF_LONG # ifndef HAVE_INTPTR_T typedef signed long intptr_t; # endif # ifndef HAVE_UINTPTR_T typedef unsigned long uintptr_t; # endif #elif HAVE_LONG_LONG && defined(SIZEOF_LONG_LONG) && SIZEOF_VOID_P == SIZEOF_LONG_LONG # ifndef HAVE_INTPTR_T typedef signed long long intptr_t; # endif # ifndef HAVE_UINTPTR_T typedef unsigned long long uintptr_t; # endif #else # error Failed to define pointer-sized integer types #endif /* inttypes.h printf specifiers */ #include #ifndef PRIsize_t # if defined(ACCEPT_C99) # define PRIsize_t "zu" # elif SIZEOF_SIZE_T == SIZEOF_LONG # define PRIsize_t "lu" # elif defined(SIZEOF_LONG_LONG) && SIZEOF_SIZE_T == SIZEOF_LONG_LONG # define PRIsize_t "llu" # else # define PRIsize_t "u" # endif #endif #endif /* PMIX_STDINT_H */ pmix-6.1.1~rc2/src/include/pmix_globals.c0000664000175000017500000005336715203536752020551 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2014-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* THIS FILE IS INCLUDED SOLELY TO INSTANTIATE AND INIT/FINALIZE THE GLOBAL CLASSES */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/include/pmix_socket_errno.h" #include "src/include/pmix_stdint.h" #include "src/include/pmix_types.h" #include "src/include/pmix_dictionary.h" #include "src/include/pmix_globals.h" #ifdef HAVE_STRING_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include #if HAVE_SYS_STAT_H # include #endif /* HAVE_SYS_STAT_H */ #ifdef HAVE_DIRENT_H # include #endif /* HAVE_DIRENT_H */ #include "pmix_common.h" #include "src/class/pmix_hash_table.h" #include "src/class/pmix_list.h" #include "src/mca/bfrops/bfrops_types.h" #include "src/mca/bfrops/base/bfrop_base_tma.h" #include "src/threads/pmix_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_os_path.h" const char* PMIX_PROXY_VERSION = PMIX_PROXY_VERSION_STRING; const char* PMIX_PROXY_BUGREPORT = PMIX_PROXY_BUGREPORT_STRING; static void dirpath_destroy(char *path, pmix_cleanup_dir_t *cd, pmix_epilog_t *epi); static bool dirpath_is_empty(const char *path); static void nsenvcon(pmix_nspace_env_cache_t *p) { PMIX_CONSTRUCT(&p->envars, pmix_list_t); } static void nsenvdes(pmix_nspace_env_cache_t *p) { PMIX_LIST_DESTRUCT(&p->envars); } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_nspace_env_cache_t, pmix_list_item_t, nsenvcon, nsenvdes); static void encon(pmix_envar_list_item_t *p) { PMIX_ENVAR_CONSTRUCT(&p->envar); } static void endes(pmix_envar_list_item_t *p) { PMIX_ENVAR_DESTRUCT(&p->envar); } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_envar_list_item_t, pmix_list_item_t, encon, endes); PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_namelist_t, pmix_list_item_t, NULL, NULL); PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_proclist_t, pmix_list_item_t, NULL, NULL); PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_topo_obj_t, pmix_object_t, NULL, NULL); static void cfcon(pmix_cleanup_file_t *p) { p->path = NULL; } static void cfdes(pmix_cleanup_file_t *p) { if (NULL != p->path) { free(p->path); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_cleanup_file_t, pmix_list_item_t, cfcon, cfdes); static void cdcon(pmix_cleanup_dir_t *p) { p->path = NULL; p->recurse = false; p->leave_topdir = false; } static void cddes(pmix_cleanup_dir_t *p) { if (NULL != p->path) { free(p->path); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_cleanup_dir_t, pmix_list_item_t, cdcon, cddes); static void nscon(pmix_namespace_t *p) { p->nspace = NULL; memset(&p->version, 0, sizeof(p->version)); p->nprocs = 0; p->nlocalprocs = SIZE_MAX; p->all_registered = false; p->version_stored = false; p->job_info_recvd = false; p->jobbkt = NULL; p->ndelivered = 0; p->nfinalized = 0; PMIX_CONSTRUCT(&p->ranks, pmix_list_t); memset(&p->compat, 0, sizeof(p->compat)); PMIX_CONSTRUCT(&p->epilog.cleanup_dirs, pmix_list_t); PMIX_CONSTRUCT(&p->epilog.cleanup_files, pmix_list_t); PMIX_CONSTRUCT(&p->epilog.ignores, pmix_list_t); PMIX_CONSTRUCT(&p->setup_data, pmix_list_t); memset(&p->iof_flags, 0, sizeof(p->iof_flags)); PMIX_CONSTRUCT(&p->sinks, pmix_list_t); } static void nsdes(pmix_namespace_t *p) { if (NULL != p->nspace) { free(p->nspace); } if (NULL != p->jobbkt) { PMIX_RELEASE(p->jobbkt); } PMIX_LIST_DESTRUCT(&p->ranks); /* perform any epilog */ pmix_execute_epilog(&p->epilog); /* cleanup the epilog */ PMIX_LIST_DESTRUCT(&p->epilog.cleanup_dirs); PMIX_LIST_DESTRUCT(&p->epilog.cleanup_files); PMIX_LIST_DESTRUCT(&p->epilog.ignores); PMIX_LIST_DESTRUCT(&p->setup_data); if (NULL != p->iof_flags.file) { free(p->iof_flags.file); } if (NULL != p->iof_flags.directory) { free(p->iof_flags.directory); } PMIX_LIST_DESTRUCT(&p->sinks); } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_namespace_t, pmix_list_item_t, nscon, nsdes); static void ncdcon(pmix_nspace_caddy_t *p) { p->ns = NULL; } static void ncddes(pmix_nspace_caddy_t *p) { if (NULL != p->ns) { PMIX_RELEASE(p->ns); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_nspace_caddy_t, pmix_list_item_t, ncdcon, ncddes); static void keyindex_construct(pmix_keyindex_t *ki) { pmix_tma_t *const tma = pmix_obj_get_tma(&ki->super); ki->table = PMIX_NEW(pmix_pointer_array_t, tma); pmix_pointer_array_init(ki->table, 1024, INT_MAX, 128); ki->next_id = 0; } static void keyindex_destruct(pmix_keyindex_t *ki) { pmix_tma_t *const tma = pmix_obj_get_tma(&ki->super); for (int i = 0; i < ki->table->size; i++) { pmix_regattr_input_t *p = (pmix_regattr_input_t *)pmix_pointer_array_get_item(ki->table, i); if (NULL != p) { if (NULL != p->name) { pmix_tma_free(tma, p->name); } if (NULL != p->string) { pmix_tma_free(tma, p->string); } if (NULL != p->description) { pmix_bfrops_base_tma_argv_free(p->description, tma); } pmix_tma_free(tma, p); } } PMIX_RELEASE(ki->table); } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_keyindex_t, pmix_object_t, keyindex_construct, keyindex_destruct); static void info_con(pmix_rank_info_t *info) { info->peerid = -1; info->pid = -1; info->realuid = 0; info->uid = 0; info->realgid = 0; info->gid = 0; info->pname.nspace = NULL; info->pname.rank = PMIX_RANK_UNDEF; info->modex_recvd = false; info->proc_cnt = 0; info->server_object = NULL; } static void info_des(pmix_rank_info_t *info) { if (NULL != info->pname.nspace) { free(info->pname.nspace); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_rank_info_t, pmix_list_item_t, info_con, info_des); static void pcon(pmix_peer_t *p) { p->nptr = NULL; p->proc_type.type = PMIX_PROC_UNDEF; p->proc_type.major = PMIX_MAJOR_WILDCARD; p->proc_type.minor = PMIX_MINOR_WILDCARD; p->proc_type.release = PMIX_RELEASE_WILDCARD; p->proc_type.flag = 0; p->protocol = PMIX_PROTOCOL_UNDEF; p->finalized = false; p->info = NULL; p->proc_cnt = 0; p->index = 0; p->sd = -1; p->send_ev_active = false; p->recv_ev_active = false; PMIX_CONSTRUCT(&p->send_queue, pmix_list_t); p->send_msg = NULL; p->recv_msg = NULL; p->commit_cnt = 0; PMIX_CONSTRUCT(&p->epilog.cleanup_dirs, pmix_list_t); PMIX_CONSTRUCT(&p->epilog.cleanup_files, pmix_list_t); PMIX_CONSTRUCT(&p->epilog.ignores, pmix_list_t); p->dyn_tags_start = PMIX_PTL_TAG_DYNAMIC; p->dyn_tags_current = PMIX_PTL_TAG_DYNAMIC; p->dyn_tags_end = UINT32_MAX; } static void pdes(pmix_peer_t *p) { if (NULL != p->nptr) { PMIX_RELEASE(p->nptr); } if (0 <= p->sd) { CLOSE_THE_SOCKET(p->sd); } if (p->send_ev_active) { pmix_event_del(&p->send_event); } if (p->recv_ev_active) { pmix_event_del(&p->recv_event); } if (NULL != p->info) { PMIX_RELEASE(p->info); } PMIX_LIST_DESTRUCT(&p->send_queue); if (NULL != p->send_msg) { PMIX_RELEASE(p->send_msg); } if (NULL != p->recv_msg) { PMIX_RELEASE(p->recv_msg); } /* perform any epilog */ pmix_execute_epilog(&p->epilog); /* cleanup the epilog */ PMIX_LIST_DESTRUCT(&p->epilog.cleanup_dirs); PMIX_LIST_DESTRUCT(&p->epilog.cleanup_files); PMIX_LIST_DESTRUCT(&p->epilog.ignores); } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_peer_t, pmix_object_t, pcon, pdes); static void iofreqcon(pmix_iof_req_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); p->status = PMIX_SUCCESS; p->requestor = NULL; p->local_id = 0; p->remote_id = 0; p->procs = NULL; p->nprocs = 0; memset(&p->flags, 0, sizeof(pmix_iof_flags_t)); p->channels = PMIX_FWD_NO_CHANNELS; p->directives = NULL; p->ndirs = 0; p->cbfunc = NULL; p->regcbfunc = NULL; p->cbdata = NULL; } static void iofreqdes(pmix_iof_req_t *p) { PMIX_DESTRUCT_LOCK(&p->lock); if (NULL != p->requestor) { PMIX_RELEASE(p->requestor); } if (0 < p->nprocs) { PMIX_PROC_FREE(p->procs, p->nprocs); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_iof_req_t, pmix_object_t, iofreqcon, iofreqdes); static void scon(pmix_shift_caddy_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); p->codes = NULL; p->ncodes = 0; p->sessionid = UINT32_MAX; p->peer = NULL; p->proc = NULL; p->pname.nspace = NULL; p->pname.rank = PMIX_RANK_UNDEF; p->data = NULL; p->ndata = 0; p->key = NULL; p->infocopy = false; p->info = NULL; p->ninfo = 0; p->dircopy = false; p->directives = NULL; p->ndirs = 0; p->pdata = NULL; p->npdata = 0; p->range = PMIX_RANGE_UNDEF; p->bo = NULL; p->dist = NULL; p->ndist = 0; p->evhdlr = NULL; p->iofreq = NULL; p->kv = NULL; p->vptr = NULL; p->cd = NULL; p->tracker = NULL; p->enviro = false; p->cbfunc.relfn = NULL; p->cbdata = NULL; p->relcbdata = NULL; p->ref = 0; } static void scdes(pmix_shift_caddy_t *p) { PMIX_DESTRUCT_LOCK(&p->lock); if (NULL != p->peer) { PMIX_RELEASE(p->peer); } if (NULL != p->pname.nspace) { free(p->pname.nspace); } if (p->infocopy) { PMIX_INFO_FREE(p->info, p->ninfo); } if (p->dircopy) { PMIX_INFO_FREE(p->directives, p->ndirs); } if (NULL != p->kv) { PMIX_RELEASE(p->kv); } } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_shift_caddy_t, pmix_object_t, scon, scdes); static void lgcon(pmix_get_logic_t *p) { memset(&p->p, 0, sizeof(pmix_proc_t)); p->pntrval = false; p->stval = false; p->optional = false; p->immediate = false; p->add_immediate = false; p->refresh_cache = false; p->scope = PMIX_SCOPE_UNDEF; p->sessioninfo = false; p->sessiondirective = false; p->sessionid = UINT32_MAX; p->nodeinfo = false; p->nodedirective = false; p->hostname = NULL; p->nodeid = UINT32_MAX; p->appinfo = false; p->appdirective = false; p->appnum = UINT32_MAX; } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_get_logic_t, pmix_object_t, lgcon, NULL); static void cbcon(pmix_cb_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); p->status = PMIX_SUCCESS; p->checked = false; PMIX_CONSTRUCT(&p->data, pmix_buffer_t); p->cbfunc.ptlfn = NULL; p->cbdata = NULL; p->pname.nspace = NULL; p->pname.rank = PMIX_RANK_UNDEF; p->scope = PMIX_SCOPE_UNDEF; p->key = NULL; p->value = NULL; p->proc = NULL; p->procs = NULL; p->nprocs = 0; p->info = NULL; p->ninfo = 0; p->directives = NULL; p->ndirs = 0; p->dist = NULL; p->bo = NULL; p->infocopy = false; p->nvals = 0; PMIX_CONSTRUCT(&p->kvs, pmix_list_t); p->copy = false; p->lg = NULL; p->timer_running = false; p->fabric = NULL; p->topo = NULL; } static void cbdes(pmix_cb_t *p) { if (p->timer_running) { pmix_event_del(&p->ev); } if (NULL != p->pname.nspace) { free(p->pname.nspace); } PMIX_DESTRUCT(&p->data); if (p->infocopy) { PMIX_INFO_FREE(p->info, p->ninfo); } if (NULL != p->dist) { PMIX_DEVICE_DIST_FREE(p->dist, p->nvals); } PMIX_LIST_DESTRUCT(&p->kvs); } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_cb_t, pmix_list_item_t, cbcon, cbdes); PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_info_caddy_t, pmix_list_item_t, NULL, NULL); PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_peerlist_t, pmix_list_item_t, NULL, NULL); static void ifcon(pmix_infolist_t *p) { PMIX_INFO_CONSTRUCT(&p->info); } static void ifdes(pmix_infolist_t *p) { PMIX_INFO_DESTRUCT(&p->info); } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_infolist_t, pmix_list_item_t, ifcon, ifdes); static void qlcon(pmix_querylist_t *p) { PMIX_QUERY_CONSTRUCT(&p->query); } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_querylist_t, pmix_list_item_t, qlcon, NULL); static void qcon(pmix_query_caddy_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); p->host_called = false; p->queries = NULL; p->nqueries = 0; p->targets = NULL; p->ntargets = 0; p->info = NULL; p->ninfo = 0; PMIX_BYTE_OBJECT_CONSTRUCT(&p->bo); PMIX_CONSTRUCT(&p->results, pmix_list_t); p->nreplies = 0; p->nrequests = 0; p->cbfunc = NULL; p->valcbfunc = NULL; p->cbdata = NULL; p->relcbfunc = NULL; p->credcbfunc = NULL; p->validcbfunc = NULL; } static void qdes(pmix_query_caddy_t *p) { PMIX_DESTRUCT_LOCK(&p->lock); PMIX_BYTE_OBJECT_DESTRUCT(&p->bo); PMIX_PROC_FREE(p->targets, p->ntargets); PMIX_INFO_FREE(p->info, p->ninfo); PMIX_LIST_DESTRUCT(&p->results); } PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_query_caddy_t, pmix_object_t, qcon, qdes); static void ncon(pmix_notify_caddy_t *p) { PMIX_CONSTRUCT_LOCK(&p->lock); #if defined(__linux__) && PMIX_HAVE_CLOCK_GETTIME struct timespec tp; (void) clock_gettime(CLOCK_MONOTONIC, &tp); p->ts = tp.tv_sec; #else /* Fall back to gettimeofday() if we have nothing else */ struct timeval tv; gettimeofday(&tv, NULL); p->ts = tv.tv_sec; #endif p->room = -1; memset(p->source.nspace, 0, PMIX_MAX_NSLEN + 1); p->source.rank = PMIX_RANK_UNDEF; p->range = PMIX_RANGE_UNDEF; p->staylocal = false; p->targets = NULL; p->ntargets = 0; p->nleft = SIZE_MAX; p->affected = NULL; p->naffected = 0; p->nondefault = false; p->info = NULL; p->ninfo = 0; } static void ndes(pmix_notify_caddy_t *p) { PMIX_DESTRUCT_LOCK(&p->lock); if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->ninfo); } PMIX_PROC_FREE(p->affected, p->naffected); if (NULL != p->targets) { free(p->targets); } } PMIX_CLASS_INSTANCE(pmix_notify_caddy_t, pmix_object_t, ncon, ndes); pmix_dstor_t *pmix_dstor_new_tma(uint32_t index, pmix_tma_t *tma) { pmix_dstor_t *d = (pmix_dstor_t *)pmix_tma_malloc(tma, sizeof(pmix_dstor_t)); if (PMIX_LIKELY(NULL != d)) { d->index = index; d->qualindex = UINT32_MAX; d->value = NULL; } return d; } void pmix_dstor_release_tma(pmix_dstor_t *d, pmix_tma_t *tma) { if (NULL != d->value) { pmix_bfrops_base_tma_value_destruct(d->value, tma); pmix_tma_free(tma, d->value); } pmix_tma_free(tma, d); } static void grcon(pmix_group_t *p) { p->grpid = NULL; p->ctxid = SIZE_MAX; p->members = NULL; p->nmbrs = 0; } static void grdes(pmix_group_t *p) { if (NULL != p->grpid) { free(p->grpid); p->grpid = NULL; } p->ctxid = SIZE_MAX; if (NULL != p->members) { PMIX_PROC_FREE(p->members, p->nmbrs); p->members = NULL; } } PMIX_CLASS_INSTANCE(pmix_group_t, pmix_list_item_t, grcon, grdes); void pmix_execute_epilog(pmix_epilog_t *epi) { pmix_cleanup_file_t *cf, *cfnext; pmix_cleanup_dir_t *cd, *cdnext; DIR *tst; int rc; char **tmp; size_t n; /* start with any specified files */ PMIX_LIST_FOREACH_SAFE (cf, cfnext, &epi->cleanup_files, pmix_cleanup_file_t) { tmp = PMIx_Argv_split(cf->path, ','); for (n = 0; NULL != tmp[n]; n++) { rc = unlink(tmp[n]); if (0 > rc) { pmix_output_verbose(10, pmix_globals.debug_output, "File %s failed to unlink: %s", tmp[n], strerror(errno)); } } PMIx_Argv_free(tmp); pmix_list_remove_item(&epi->cleanup_files, &cf->super); PMIX_RELEASE(cf); } /* now cleanup the directories */ PMIX_LIST_FOREACH_SAFE (cd, cdnext, &epi->cleanup_dirs, pmix_cleanup_dir_t) { tmp = PMIx_Argv_split(cd->path, ','); for (n = 0; NULL != tmp[n]; n++) { tst = opendir(tmp[n]); if (NULL != tst) { closedir(tst); dirpath_destroy(tmp[n], cd, epi); } } PMIx_Argv_free(tmp); pmix_list_remove_item(&epi->cleanup_dirs, &cd->super); PMIX_RELEASE(cd); } } static void dirpath_destroy(char *path, pmix_cleanup_dir_t *cd, pmix_epilog_t *epi) { DIR *dp, *tst; struct dirent *ep; char *filenm; pmix_cleanup_file_t *cf; if (NULL == path) { /* protect against error */ return; } /* if this path is it to be ignored, then do so */ PMIX_LIST_FOREACH (cf, &epi->ignores, pmix_cleanup_file_t) { if (0 == strcmp(cf->path, path)) { return; } } /* Open up the directory */ dp = opendir(path); if (NULL == dp) { return; } while (NULL != (ep = readdir(dp))) { /* skip: * - . and .. */ if ((0 == strcmp(ep->d_name, ".")) || (0 == strcmp(ep->d_name, ".."))) { continue; } /* Create a pathname. This is not always needed, but it makes * for cleaner code just to create it here. Note that we are * allocating memory here, so we need to free it later on. */ filenm = pmix_os_path(false, path, ep->d_name, NULL); /* if this path is to be ignored, then do so */ PMIX_LIST_FOREACH (cf, &epi->ignores, pmix_cleanup_file_t) { if (0 == strcmp(cf->path, filenm)) { free(filenm); filenm = NULL; break; } } if (NULL == filenm) { continue; } /* Check to see if it is a directory */ tst = opendir(filenm); if (NULL != tst) { closedir(tst); /* * If not recursively descending, then if we find a directory then fail * since we were not told to remove it. */ if (!cd->recurse) { /* continue removing files */ free(filenm); continue; } else { /* Directories are recursively destroyed */ dirpath_destroy(filenm, cd, epi); free(filenm); } } else { /* Files are removed right here */ unlink(filenm); free(filenm); } } /* Done with this directory */ closedir(dp); /* If the directory is empty, then remove it unless we * were told to leave it */ if (0 == strcmp(path, cd->path) && cd->leave_topdir) { return; } if (dirpath_is_empty(path)) { rmdir(path); } } static bool dirpath_is_empty(const char *path) { DIR *dp; struct dirent *ep; if (NULL != path) { /* protect against error */ dp = opendir(path); if (NULL != dp) { while ((ep = readdir(dp))) { if ((0 != strcmp(ep->d_name, ".")) && (0 != strcmp(ep->d_name, ".."))) { closedir(dp); return false; } } closedir(dp); return true; } return false; } return true; } int pmix_event_assign(struct event *ev, pmix_event_base_t *evbase, int fd, short arg, event_callback_fn cbfn, void *cbd) { event_assign(ev, evbase, fd, arg, cbfn, cbd); return 0; } pmix_event_t *pmix_event_new(pmix_event_base_t *b, int fd, short fg, event_callback_fn cbfn, void *cbd) { pmix_event_t *ev = NULL; ev = event_new(b, fd, fg, (event_callback_fn) cbfn, cbd); return ev; } static void tcon(pmix_timer_t *p) { p->active = false; p->payload = NULL; } static void tdes(pmix_timer_t *p) { if (p->active) { pmix_event_del(&p->ev); p->active = false; } } PMIX_CLASS_INSTANCE(pmix_timer_t, pmix_object_t, tcon, tdes); #if PMIX_PICKY_COMPILERS void pmix_hide_unused_params(int x, ...) { va_list ap; (void)x; va_start(ap, x); va_end(ap); } #endif pmix-6.1.1~rc2/src/include/pmix_config_top.h0000664000175000017500000000271615203536752021252 0ustar alastairalastair/* * Copyright (c) 2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2013-2015 Intel, Inc. All rights reserved * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * This file is included at the top of pmix_config.h, and is * therefore a) before all the #define's that were output from * configure, and b) included in most/all files in PMIx. * * Since this file is *only* ever included by pmix_config.h, and * pmix_config.h already has #ifndef/#endif protection, there is no * need to #ifndef/#endif protection here. */ #ifndef PMIX_CONFIG_H # error "pmix_config_top.h should only be included from config.h(.in)" #endif /* The only purpose of this file is to undef the PACKAGE_ macros that are put in by autoconf/automake projects. Specifically, if you include a .h file from another project that defines these macros (e.g., gmp.h) and then include PMIX's config.h, you'll get a preprocessor conflict. So put these undef's here to protect us from other package's PACKAGE_ macros. Note that we can't put them directly in pmix_config.h (e.g., via AH_TOP) because they will be turned into #define's by autoconf. */ #undef PACKAGE_BUGREPORT #undef PACKAGE_NAME #undef PACKAGE_STRING #undef PACKAGE_TARNAME #undef PACKAGE_VERSION #undef PACKAGE_URL #undef HAVE_CONFIG_H pmix-6.1.1~rc2/src/include/Makefile.am0000664000175000017500000000763515203536752017756 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2007-2022 Cisco Systems, Inc. All rights reserved # Copyright (c) 2017 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # Copyright (c) 2022-2023 Triad National Security, LLC. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # The Automake BUILT_SOURCES hook ultimately calls # construct_dictionary.py to generate both pmix_dictionary.h and # pmix_dictionary.c. However, in a parallel "make" invocation, this # script could be executed twice simultaneously, which *could* lead to # the generated pmix_dictionary.* files being corrupted (i.e., two # invokcations simultaneously writing to these generated files). To # prevent that from happening, force this one Makefile to be run # serially via the .NOTPARALLEL target. This has two side-effects: # # 1. construct_dictionary.py will only be invokved once, because since # both targets are created in the first invocation, make won't need # to invoke it a second time for the second target. This is both # expected and good. # 2. There is a (very) minor performance implication for the # other make steps in this Makefile.am (i.e., they won't be run in # parallel). But this simple solution to avoid a devious potential # file corruption issue is an acceptable tradeoff. .NOTPARALLEL: include $(top_srcdir)/Makefile.openpmix-rules AM_CFLAGS = \ -DPMIX_PROXY_VERSION_STRING="\"@PMIX_VERSION@\"" \ -DPMIX_PROXY_BUGREPORT_STRING="\"@PMIX_PROXY_BUGREPORT_STRING@\"" pmixdir = $(pmixincludedir)/$(subdir) noinst_LTLIBRARIES = libpmixglobal.la libpmixglobal_la_SOURCES = \ pmix_globals.h \ pmix_globals.c \ pmix_dictionary.c \ pmix_frameworks.c \ pmix_event_strings.c headers = pmix_globals.h headers += \ pmix_atomic.h \ pmix_hash_string.h \ pmix_socket_errno.h \ pmix_stdatomic.h \ pmix_stdint.h \ pmix_prefetch.h \ pmix_types.h \ pmix_config.h \ pmix_config_top.h \ pmix_config_bottom.h \ pmix_portable_platform.h \ pmix_portable_platform_real.h \ pmix_frameworks.h \ pmix_dictionary.h \ pmix_event_strings.h nobase_pmix_HEADERS = $(headers) # Files that are generated here. libpmixglobal_gen = \ pmix_dictionary.h \ pmix_dictionary.c \ pmix_event_strings.h \ pmix_event_strings.c # Need to ensure that pmix_dictionary.h and pmix_dictionary.c are built first -- # before any other targets. BUILT_SOURCES = $(libpmixglobal_gen) $(libpmixglobal_gen): $(abs_top_srcdir)/include/pmix_common.h.in \ $(abs_top_srcdir)/include/pmix_deprecated.h \ $(abs_top_srcdir)/src/common/pmix_attributes.c $(PMIX_V_GEN) $(PYTHON) $(abs_top_srcdir)/contrib/construct_dictionary.py \ --root $(abs_top_srcdir) \ --out . $(PMIX_V_GEN) $(PYTHON) $(abs_top_srcdir)/contrib/construct_event_strings.py MAINTAINERCLEANFILES = $(libpmixglobal_gen) clean-local: rm -f pmix_dictionary.h pmix_dictionary.c pmix_event_strings.h pmix_event_strings.c pmix-6.1.1~rc2/src/include/pmix_hash_string.h0000664000175000017500000000454315203536752021434 0ustar alastairalastair/* * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file * * Simple macros to quickly compute a hash value from a string. * */ #ifndef PMIX_HASH_STRING_H #define PMIX_HASH_STRING_H /** * Compute the hash value and the string length simultaneously * * @param str (IN) The string which will be parsed (char*) * @param hash (OUT) Where the hash value will be stored (uint32_t) * @param length (OUT) The computed length of the string (uint32_t) */ #define PMIX_HASH_STRLEN(str, hash, length) \ do { \ register const char *_str = (str); \ register uint32_t _hash = 0; \ register uint32_t _len = 0; \ \ while (*_str) { \ _len++; \ _hash += *_str++; \ _hash += (_hash << 10); \ _hash ^= (_hash >> 6); \ } \ \ _hash += (_hash << 3); \ _hash ^= (_hash >> 11); \ (hash) = (_hash + (_hash << 15)); \ (length) = _len; \ } while (0) /** * Compute the hash value * * @param str (IN) The string which will be parsed (char*) * @param hash (OUT) Where the hash value will be stored (uint32_t) */ #define PMIX_HASH_STR(str, hash) \ do { \ register const char *_str = (str); \ register uint32_t _hash = 0; \ \ while (*_str) { \ _hash += *_str++; \ _hash += (_hash << 10); \ _hash ^= (_hash >> 6); \ } \ \ _hash += (_hash << 3); \ _hash ^= (_hash >> 11); \ (hash) = (_hash + (_hash << 15)); \ } while (0) #endif /* PMIX_HASH_STRING_H */ pmix-6.1.1~rc2/src/include/pmix_socket_errno.h0000664000175000017500000000164415203536752021617 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Intel, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_GET_SOCKET_ERROR_H #define PMIX_GET_SOCKET_ERROR_H #include #define pmix_socket_errno errno #endif /* PMIX_GET_ERROR_H */ pmix-6.1.1~rc2/src/include/pmix_config_bottom.h0000664000175000017500000004106715203536752021756 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2010 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2013 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_CONFIG_BOTTOM_H #define PMIX_CONFIG_BOTTOM_H /* * If we build a static library, Visual C define the _LIB symbol. In the * case of a shared library _USERDLL get defined. * */ #ifndef PMIX_BUILDING # define PMIX_BUILDING 1 #endif /* * Flex is trying to include the unistd.h file. As there is no configure * option or this, the flex generated files will try to include the file * even on platforms without unistd.h. Therefore, if we * know this file is not available, we can prevent flex from including it. */ #ifndef HAVE_UNISTD_H # define YY_NO_UNISTD_H #endif /*********************************************************************** * * code that should be in ompi_config_bottom.h regardless of build * status * **********************************************************************/ /* Do we have posix thread lib */ #define PMIX_HAVE_THREADS (PMIX_HAVE_POSIX_THREADS) /* * BEGIN_C_DECLS should be used at the beginning of your declarations, * so that C++ compilers don't mangle their names. Use END_C_DECLS at * the end of C declarations. */ #undef BEGIN_C_DECLS #undef END_C_DECLS #if defined(c_plusplus) || defined(__cplusplus) # define BEGIN_C_DECLS extern "C" { # define END_C_DECLS } #else # define BEGIN_C_DECLS /* empty */ # define END_C_DECLS /* empty */ #endif /* Defined to 1 on Linux */ #undef PMIX_LINUX_SYS /* Defined to 1 if the CPU_SET macro works */ #undef PMIX_HAVE_CPU_SET /* Defined to 1 if you have the `windows.h' header. */ #undef PMIX_HAVE_WINDOWS_H #undef pmix_pid_t #undef pmix_thread_t /* * Note: this is public. We can not assume anything from the compiler used * by the application and thus the PMIX_HAVE_* macros below are not * fetched from the autoconf result here. We only automatically use a few * well-known easy cases. */ /* Some handy constants to make the logic below a little more readable */ #if defined(__cplusplus) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR >= 4)) # define GXX_ABOVE_3_4 1 #else # define GXX_ABOVE_3_4 0 #endif #if !defined(__cplusplus) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)) # define GCC_ABOVE_2_95 1 #else # define GCC_ABOVE_2_95 0 #endif #if !defined(__cplusplus) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) # define GCC_ABOVE_2_96 1 #else # define GCC_ABOVE_2_96 0 #endif #if !defined(__cplusplus) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) # define GCC_ABOVE_3_3 1 #else # define GCC_ABOVE_3_3 0 #endif /** * The attribute definition should be included before any potential * usage. */ #if PMIX_HAVE_ATTRIBUTE_ALIGNED # define __pmix_attribute_aligned__(a) __attribute__((__aligned__(a))) # define __pmix_attribute_aligned_max__ __attribute__((__aligned__)) #else # define __pmix_attribute_aligned__(a) # define __pmix_attribute_aligned_max__ #endif /* Note that if we're compiling C++, then just use the "inline" keyword, since it's part of C++ */ #if defined(c_plusplus) || defined(__cplusplus) # define __pmix_inline inline #elif defined(_MSC_VER) || defined(__HP_cc) # define __pmix_inline __inline #else # define __pmix_inline __inline__ #endif #if PMIX_HAVE_ATTRIBUTE_ALWAYS_INLINE # define __pmix_attribute_always_inline__ __attribute__((__always_inline__)) #else # define __pmix_attribute_always_inline__ #endif #if PMIX_HAVE_ATTRIBUTE_COLD # define __pmix_attribute_cold__ __attribute__((__cold__)) #else # define __pmix_attribute_cold__ #endif #ifdef PMIX_HAVE_ATTRIBUTE_CONST # define __PMIX_HAVE_ATTRIBUTE_CONST PMIX_HAVE_ATTRIBUTE_CONST #elif defined(__GNUC__) # define __PMIX_HAVE_ATTRIBUTE_CONST (GXX_ABOVE_3_4 || GCC_ABOVE_2_95) #else # define __PMIX_HAVE_ATTRIBUTE_CONST 0 #endif #if __PMIX_HAVE_ATTRIBUTE_CONST # define __pmix_attribute_const __attribute__((__const__)) #else # define __pmix_attribute_const #endif #if PMIX_HAVE_ATTRIBUTE_CONST # define __pmix_attribute_const__ __attribute__((__const__)) #else # define __pmix_attribute_const__ #endif #ifdef PMIX_HAVE_ATTRIBUTE_DEPRECATED # define __PMIX_HAVE_ATTRIBUTE_DEPRECATED PMIX_HAVE_ATTRIBUTE_DEPRECATED #elif defined(__GNUC__) # define __PMIX_HAVE_ATTRIBUTE_DEPRECATED (GXX_ABOVE_3_4 || GCC_ABOVE_3_3) #else # define __PMIX_HAVE_ATTRIBUTE_DEPRECATED 0 #endif #if __PMIX_HAVE_ATTRIBUTE_DEPRECATED # define __pmix_attribute_deprecated __attribute__((__deprecated__)) #else # define __pmix_attribute_deprecated #endif #if PMIX_HAVE_ATTRIBUTE_DEPRECATED # define __pmix_attribute_deprecated__ __attribute__((__deprecated__)) #else # define __pmix_attribute_deprecated__ #endif #if PMIX_HAVE_ATTRIBUTE_FORMAT # define __pmix_attribute_format__(a, b, c) __attribute__((__format__(a, b, c))) #else # define __pmix_attribute_format__(a, b, c) #endif /* Use this __atribute__ on function-ptr declarations, only */ #if PMIX_HAVE_ATTRIBUTE_FORMAT_FUNCPTR # define __pmix_attribute_format_funcptr__(a, b, c) __attribute__((__format__(a, b, c))) #else # define __pmix_attribute_format_funcptr__(a, b, c) #endif #if PMIX_HAVE_ATTRIBUTE_HOT # define __pmix_attribute_hot__ __attribute__((__hot__)) #else # define __pmix_attribute_hot__ #endif #ifdef PMIX_HAVE_ATTRIBUTE_MALLOC # define __PMIX_HAVE_ATTRIBUTE_MALLOC PMIX_HAVE_ATTRIBUTE_MALLOC #elif defined(__GNUC__) # define __PMIX_HAVE_ATTRIBUTE_MALLOC (GXX_ABOVE_3_4 || GCC_ABOVE_2_96) #else # define __PMIX_HAVE_ATTRIBUTE_MALLOC 0 #endif #if __PMIX_HAVE_ATTRIBUTE_MALLOC # define __pmix_attribute_malloc __attribute__((__malloc__)) #else # define __pmix_attribute_malloc #endif #if PMIX_HAVE_ATTRIBUTE_MALLOC # define __pmix_attribute_malloc__ __attribute__((__malloc__)) #else # define __pmix_attribute_malloc__ #endif #ifdef PMIX_HAVE_ATTRIBUTE_MAY_ALIAS # define __PMIX_HAVE_ATTRIBUTE_MAY_ALIAS PMIX_HAVE_ATTRIBUTE_MAY_ALIAS #elif defined(__GNUC__) # define __PMIX_HAVE_ATTRIBUTE_MAY_ALIAS (GXX_ABOVE_3_4 || GCC_ABOVE_3_3) #else # define __PMIX_HAVE_ATTRIBUTE_MAY_ALIAS 0 #endif #if __PMIX_HAVE_ATTRIBUTE_MAY_ALIAS # define __pmix_attribute_may_alias __attribute__((__may_alias__)) #else # define __pmix_attribute_may_alias #endif #if PMIX_HAVE_ATTRIBUTE_MAY_ALIAS # define __pmix_attribute_may_alias__ __attribute__((__may_alias__)) #else # define __pmix_attribute_may_alias__ #endif #if PMIX_HAVE_ATTRIBUTE_NO_INSTRUMENT_FUNCTION # define __pmix_attribute_no_instrument_function__ __attribute__((__no_instrument_function__)) #else # define __pmix_attribute_no_instrument_function__ #endif #if PMIX_HAVE_ATTRIBUTE_NONNULL # define __pmix_attribute_nonnull__(a) __attribute__((__nonnull__(a))) # define __pmix_attribute_nonnull_all__ __attribute__((__nonnull__)) #else # define __pmix_attribute_nonnull__(a) # define __pmix_attribute_nonnull_all__ #endif #if PMIX_HAVE_ATTRIBUTE_NORETURN # define __pmix_attribute_noreturn__ __attribute__((__noreturn__)) #else # define __pmix_attribute_noreturn__ #endif /* Use this __atribute__ on function-ptr declarations, only */ #if PMIX_HAVE_ATTRIBUTE_NORETURN_FUNCPTR # define __pmix_attribute_noreturn_funcptr__ __attribute__((__noreturn__)) #else # define __pmix_attribute_noreturn_funcptr__ #endif #if PMIX_HAVE_ATTRIBUTE_PACKED # define __pmix_attribute_packed__ __attribute__((__packed__)) #else # define __pmix_attribute_packed__ #endif #ifdef PMIX_HAVE_ATTRIBUTE_PURE # define __PMIX_HAVE_ATTRIBUTE_PURE PMIX_HAVE_ATTRIBUTE_PURE #elif defined(__GNUC__) # define __PMIX_HAVE_ATTRIBUTE_PURE (GXX_ABOVE_3_4 || GCC_ABOVE_2_96) #else # define __PMIX_HAVE_ATTRIBUTE_PURE 0 #endif #if __PMIX_HAVE_ATTRIBUTE_PURE # define __pmix_attribute_pure __attribute__((__pure__)) #else # define __pmix_attribute_pure #endif #if PMIX_HAVE_ATTRIBUTE_PURE # define __pmix_attribute_pure__ __attribute__((__pure__)) #else # define __pmix_attribute_pure__ #endif #if PMIX_HAVE_ATTRIBUTE_SENTINEL # define __pmix_attribute_sentinel__ __attribute__((__sentinel__)) #else # define __pmix_attribute_sentinel__ #endif /* Maybe before gcc 2.95 too */ #ifdef PMIX_HAVE_ATTRIBUTE_UNUSED # define __PMIX_HAVE_ATTRIBUTE_UNUSED PMIX_HAVE_ATTRIBUTE_UNUSED #elif defined(__GNUC__) # define __PMIX_HAVE_ATTRIBUTE_UNUSED (GXX_ABOVE_3_4 || GCC_ABOVE_2_95) #else # define __PMIX_HAVE_ATTRIBUTE_UNUSED 0 #endif #if __PMIX_HAVE_ATTRIBUTE_UNUSED # define __pmix_attribute_unused __attribute__((__unused__)) #else # define __pmix_attribute_unused #endif #if PMIX_HAVE_ATTRIBUTE_UNUSED # define __pmix_attribute_unused__ __attribute__((__unused__)) #else # define __pmix_attribute_unused__ #endif #if PMIX_HAVE_ATTRIBUTE_WARN_UNUSED_RESULT # define __pmix_attribute_warn_unused_result__ __attribute__((__warn_unused_result__)) #else # define __pmix_attribute_warn_unused_result__ #endif #if PMIX_HAVE_ATTRIBUTE_DESTRUCTOR # define __pmix_attribute_destructor__ __attribute__((__destructor__)) #else # define __pmix_attribute_destructor__ #endif #if PMIX_HAVE_ATTRIBUTE_OPTNONE # define __pmix_attribute_optnone__ __attribute__((__optnone__)) #else # define __pmix_attribute_optnone__ #endif #if PMIX_HAVE_ATTRIBUTE_EXTENSION # define __pmix_attribute_extension__ __extension__ #else # define __pmix_attribute_extension__ #endif /* * Do we have ? */ #ifdef HAVE_STDINT_H # if !defined(__STDC_LIMIT_MACROS) && (defined(c_plusplus) || defined(__cplusplus)) /* When using a C++ compiler, the max / min value #defines for std types are only included if __STDC_LIMIT_MACROS is set before including stdint.h */ # define __STDC_LIMIT_MACROS # endif # include "src/include/pmix_config.h" # include #else # include "src/include/pmix_stdint.h" #endif /*********************************************************************** * * Code that is only for when building PMIx or utilities that are * using the internals of PMIx. It should not be included when * building MPI applications * **********************************************************************/ #if PMIX_BUILDING # ifndef HAVE_PTRDIFF_T typedef PMIX_PTRDIFF_TYPE ptrdiff_t; # endif /* * Maximum size of a filename path. */ # include # ifdef HAVE_SYS_PARAM_H # include # endif # if defined(PATH_MAX) # define PMIX_PATH_MAX (PATH_MAX + 1) # elif defined(_POSIX_PATH_MAX) # define PMIX_PATH_MAX (_POSIX_PATH_MAX + 1) # else # define PMIX_PATH_MAX 256 # endif # if defined(MAXHOSTNAMELEN) # define PMIX_MAXHOSTNAMELEN (MAXHOSTNAMELEN + 1) # elif defined(HOST_NAME_MAX) # define PMIX_MAXHOSTNAMELEN (HOST_NAME_MAX + 1) # else /* SUSv2 guarantees that "Host names are limited to 255 bytes". */ # define PMIX_MAXHOSTNAMELEN (255 + 1) # endif /* * Set the compile-time path-separator on this system and variable separator */ # define PMIX_PATH_SEP "/" # define PMIX_ENV_SEP ':' /* * printf functions for portability (only when building PMIx) */ # if !defined(HAVE_VASPRINTF) || !defined(HAVE_VSNPRINTF) # include # include # endif # if !defined(HAVE_ASPRINTF) || !defined(HAVE_SNPRINTF) || !defined(HAVE_VASPRINTF) \ || !defined(HAVE_VSNPRINTF) # include "src/util/pmix_printf.h" # endif # ifndef HAVE_ASPRINTF # define asprintf pmix_asprintf # endif # ifndef HAVE_SNPRINTF # define snprintf pmix_snprintf # endif # ifndef HAVE_VASPRINTF # define vasprintf pmix_vasprintf # endif # ifndef HAVE_VSNPRINTF # define vsnprintf pmix_vsnprintf # endif /* * Define __func__-preprocessor directive if the compiler does not * already define it. Define it to __FILE__ so that we at least have * a clue where the developer is trying to indicate where the error is * coming from (assuming that __func__ is typically used for * printf-style debugging). */ # if defined(HAVE_DECL___FUNC__) && !HAVE_DECL___FUNC__ # define __func__ __FILE__ # endif # define IOVBASE_TYPE void # include /** * If we generate our own bool type, we need a special way to cast the result * in such a way to keep the compilers silent. */ # define PMIX_INT_TO_BOOL(VALUE) (bool) (VALUE) # if !defined(HAVE_STRUCT_SOCKADDR_STORAGE) && defined(HAVE_STRUCT_SOCKADDR_IN) # define sockaddr_storage sockaddr # define ss_family sa_family # endif /* Compatibility structure so that we don't have to have as many #if checks in the code base */ # if !defined(HAVE_STRUCT_SOCKADDR_IN6) && defined(HAVE_STRUCT_SOCKADDR_IN) # define sockaddr_in6 sockaddr_in # define sin6_len sin_len # define sin6_family sin_family # define sin6_port sin_port # define sin6_addr sin_addr # endif # if !HAVE_DECL_AF_UNSPEC # define AF_UNSPEC 0 # endif # if !HAVE_DECL_PF_UNSPEC # define PF_UNSPEC 0 # endif # if !HAVE_DECL_AF_INET6 # define AF_INET6 AF_UNSPEC # endif # if !HAVE_DECL_PF_INET6 # define PF_INET6 PF_UNSPEC # endif # if defined(__APPLE__) && defined(HAVE_INTTYPES_H) /* Prior to Mac OS X 10.3, the length modifier "ll" wasn't supported, but "q" was for long long. This isn't ANSI C and causes a warning when using PRI?64 macros. We don't support versions prior to OS X 10.3, so we don't need such backward compatibility. Instead, redefine the macros to be "ll", which is ANSI C and doesn't cause a compiler warning. */ # include # if defined(__PRI_64_LENGTH_MODIFIER__) # undef __PRI_64_LENGTH_MODIFIER__ # define __PRI_64_LENGTH_MODIFIER__ "ll" # endif # if defined(__SCN_64_LENGTH_MODIFIER__) # undef __SCN_64_LENGTH_MODIFIER__ # define __SCN_64_LENGTH_MODIFIER__ "ll" # endif # endif # ifdef MCS_VXWORKS /* VXWorks puts some common functions in oddly named headers. Rather than update all the places the functions are used, which would be a maintenance disatster, just update here... */ # ifdef HAVE_IOLIB_H /* pipe(), ioctl() */ # include # endif # ifdef HAVE_SOCKLIB_H /* socket() */ # include # endif # ifdef HAVE_HOSTLIB_H /* gethostname() */ # include # endif # endif /* If we're in C++, then just undefine restrict and then define it to nothing. "restrict" is not part of the C++ language, and we don't have a corresponding AC_CXX_RESTRICT to figure out what the C++ compiler supports. */ # if defined(c_plusplus) || defined(__cplusplus) # undef restrict # define restrict # endif # if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)) # define __pmix_restrict __restrict # else # if __STDC_VERSION__ >= 199901L # define __pmix_restrict restrict # else # define __pmix_restrict # endif # endif #else /* For a similar reason to what is listed in pmix_config_top.h, we want to protect others from the autoconf/automake-generated PACKAGE_ macros in pmix_config.h. We can't put these undef's directly in pmix_config.h because they'll be turned into #defines' via autoconf. So put them here in case any one else includes PMIX's config.h files. */ # undef PACKAGE_BUGREPORT # undef PACKAGE_NAME # undef PACKAGE_STRING # undef PACKAGE_TARNAME # undef PACKAGE_VERSION # undef PACKAGE_URL # undef HAVE_CONFIG_H #endif /* PMIX_BUILDING */ #endif /* PMIX_CONFIG_BOTTOM_H */ pmix-6.1.1~rc2/src/include/pmix_types.h0000664000175000017500000001724215203536752020267 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_TYPES_H #define PMIX_TYPES_H #include "src/include/pmix_config.h" #include "pmix_common.h" #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #include #include #if PMIX_ENABLE_DEBUG # include "src/util/pmix_output.h" #endif #include /* * portable assignment of pointer to int */ typedef union { uint64_t lval; uint32_t ival; void *pval; struct { uint32_t uval; uint32_t lval; } sval; } pmix_ptr_t; /* * handle differences in iovec */ #if defined(__APPLE__) || defined(__WINDOWS__) typedef char *pmix_iov_base_ptr_t; # define PMIX_IOVBASE char #else # define PMIX_IOVBASE void typedef void *pmix_iov_base_ptr_t; #endif /* * handle differences in socklen_t */ #if defined(HAVE_SOCKLEN_T) typedef socklen_t pmix_socklen_t; #else typedef int pmix_socklen_t; #endif #define pmix_htons htons #define pmix_ntohs ntohs /* * Convert a 64 bit value to network byte order. */ static inline uint64_t pmix_hton64(uint64_t val) __pmix_attribute_const__; static inline uint64_t pmix_hton64(uint64_t val) { #ifdef HAVE_UNIX_BYTESWAP union { uint64_t ll; uint32_t l[2]; } w, r; /* platform already in network byte order? */ if (htonl(1) == 1L) return val; w.ll = val; r.l[0] = htonl(w.l[1]); r.l[1] = htonl(w.l[0]); return r.ll; #else return val; #endif } /* * Convert a 64 bit value from network to host byte order. */ static inline uint64_t pmix_ntoh64(uint64_t val) __pmix_attribute_const__; static inline uint64_t pmix_ntoh64(uint64_t val) { #ifdef HAVE_UNIX_BYTESWAP union { uint64_t ll; uint32_t l[2]; } w, r; /* platform already in network byte order? */ if (htonl(1) == 1L) return val; w.ll = val; r.l[0] = ntohl(w.l[1]); r.l[1] = ntohl(w.l[0]); return r.ll; #else return val; #endif } /* Convert size_t value from host to network byte order and back */ #if SIZEOF_SIZE_T == 4 # define pmix_htonsizet(x) htonl(x) # define pmix_ntohsizet(x) ntohl(x) #elif SIZEOF_SIZE_T == 8 # define pmix_htonsizet(x) pmix_hton64(x) # define pmix_ntohsizet(x) pmix_ntoh64(x) #endif /** * Convert between a local representation of pointer and a 64 bits value. */ static inline uint64_t pmix_ptr_ptol(void *ptr) __pmix_attribute_const__; static inline uint64_t pmix_ptr_ptol(void *ptr) { return (uint64_t)(uintptr_t) ptr; } static inline void *pmix_ptr_ltop(uint64_t value) __pmix_attribute_const__; static inline void *pmix_ptr_ltop(uint64_t value) { #if SIZEOF_VOID_P == 4 && PMIX_ENABLE_DEBUG if (value > ((1ULL << 32) - 1ULL)) { pmix_output(0, "Warning: truncating value in pmix_ptr_ltop"); } #endif return (void *) (uintptr_t) value; } #if defined(WORDS_BIGENDIAN) || !defined(HAVE_UNIX_BYTESWAP) static inline uint16_t pmix_swap_bytes2(uint16_t val) __pmix_attribute_const__; static inline uint16_t pmix_swap_bytes2(uint16_t val) { union { uint16_t bigval; uint8_t arrayval[2]; } w, r; w.bigval = val; r.arrayval[0] = w.arrayval[1]; r.arrayval[1] = w.arrayval[0]; return r.bigval; } static inline uint32_t pmix_swap_bytes4(uint32_t val) __pmix_attribute_const__; static inline uint32_t pmix_swap_bytes4(uint32_t val) { union { uint32_t bigval; uint8_t arrayval[4]; } w, r; w.bigval = val; r.arrayval[0] = w.arrayval[3]; r.arrayval[1] = w.arrayval[2]; r.arrayval[2] = w.arrayval[1]; r.arrayval[3] = w.arrayval[0]; return r.bigval; } static inline uint64_t pmix_swap_bytes8(uint64_t val) __pmix_attribute_const__; static inline uint64_t pmix_swap_bytes8(uint64_t val) { union { uint64_t bigval; uint8_t arrayval[8]; } w, r; w.bigval = val; r.arrayval[0] = w.arrayval[7]; r.arrayval[1] = w.arrayval[6]; r.arrayval[2] = w.arrayval[5]; r.arrayval[3] = w.arrayval[4]; r.arrayval[4] = w.arrayval[3]; r.arrayval[5] = w.arrayval[2]; r.arrayval[6] = w.arrayval[1]; r.arrayval[7] = w.arrayval[0]; return r.bigval; } #else # define pmix_swap_bytes2 htons # define pmix_swap_bytes4 htonl # define pmix_swap_bytes8 hton64 #endif /* WORDS_BIGENDIAN || !HAVE_UNIX_BYTESWAP */ #define PMIX_EV_TIMEOUT EV_TIMEOUT #define PMIX_EV_READ EV_READ #define PMIX_EV_WRITE EV_WRITE #define PMIX_EV_SIGNAL EV_SIGNAL /* Persistent event: won't get removed automatically when activated. */ #define PMIX_EV_PERSIST EV_PERSIST #define PMIX_EVLOOP_ONCE EVLOOP_ONCE /**< Block at most once. */ #define PMIX_EVLOOP_NONBLOCK EVLOOP_NONBLOCK /**< Do not block. */ #define PMIX_EVENT_SIGNAL(ev) pmix_event_get_signal(ev) typedef struct event_base pmix_event_base_t; typedef struct event pmix_event_t; #define pmix_event_base_create() event_base_new() #define pmix_event_base_free(b) event_base_free(b) /* thread support APIs */ #define pmix_event_use_threads() evthread_use_pthreads() #define pmix_event_free(x) event_free(x) #define pmix_event_get_signal(x) event_get_signal(x) /* Basic event APIs */ #define pmix_event_enable_debug_mode() event_enable_debug_mode() PMIX_EXPORT int pmix_event_assign(struct event *ev, pmix_event_base_t *evbase, int fd, short arg, event_callback_fn cbfn, void *cbd); #define pmix_event_set(b, x, fd, fg, cb, arg) \ pmix_event_assign((x), (b), (fd), (fg), (event_callback_fn)(cb), (arg)) #define pmix_event_add(ev, tv) event_add((ev), (tv)) #define pmix_event_del(ev) event_del((ev)) #define pmix_event_active(x, y, z) event_active((x), (y), (z)) #define pmix_event_base_loopexit(b) event_base_loopexit(b, NULL) PMIX_EXPORT pmix_event_t *pmix_event_new(pmix_event_base_t *b, int fd, short fg, event_callback_fn cbfn, void *cbd); #define pmix_event_loop(b, fg) event_base_loop((b), (fg)) #define pmix_event_evtimer_new(b, cb, arg) pmix_event_new((b), -1, 0, (cb), (arg)) #define pmix_event_evtimer_add(x, tv) pmix_event_add((x), (tv)) #define pmix_event_evtimer_set(b, x, cb, arg) \ pmix_event_assign((x), (b), -1, 0, (event_callback_fn)(cb), (arg)) #define pmix_event_evtimer_del(x) pmix_event_del((x)) #define pmix_event_signal_set(b, x, fd, cb, arg) \ pmix_event_assign((x), (b), (fd), EV_SIGNAL | EV_PERSIST, (event_callback_fn)(cb), (arg)) #endif /* PMIX_TYPES_H */ pmix-6.1.1~rc2/src/include/pmix_globals.h0000664000175000017500000010202615203536752020541 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2019 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_GLOBALS_H #define PMIX_GLOBALS_H #include "src/include/pmix_config.h" #include "src/include/pmix_types.h" #include #ifdef HAVE_SYS_TYPES_H # include #endif #include #include "pmix.h" #include "pmix_common.h" #include "pmix_tool.h" #include "src/class/pmix_hash_table.h" #include "src/class/pmix_hotel.h" #include "src/class/pmix_list.h" #include "src/event/pmix_event.h" #include "src/runtime/pmix_init_util.h" #include "src/threads/pmix_threads.h" #include "src/mca/bfrops/bfrops.h" #include "src/mca/gds/gds.h" #include "src/mca/psec/psec.h" #include "src/mca/ptl/ptl.h" #include "src/util/pmix_name_fns.h" BEGIN_C_DECLS /* some limits */ #define PMIX_MAX_CRED_SIZE 131072 // set max at 128kbytes #define PMIX_MAX_ERR_CONSTANT INT_MIN #define PMIX_TAINT_INT_LIMIT INT_MAX-2 // arbitrary limit to silence Coverity taint complaints #define PMIX_TAINT_UINT_LIMIT UINT_MAX-2 // arbitrary limit to silence Coverity taint complaints #define PMIX_TAINT_SIZE_LIMIT SIZE_MAX-2 // arbitrary limit to silence Coverity taint complaints /* internal-only attributes */ #define PMIX_BFROPS_MODULE \ "pmix.bfrops.mod" // (char*) name of bfrops plugin in-use by a given nspace #define PMIX_PNET_SETUP_APP \ "pmix.pnet.setapp" // (pmix_byte_object_t) blob containing info to be given to // pnet framework on remote nodes // define some bit handling macros #define PMIX_SET_BIT(a, f) \ (a) |= (f) #define PMIX_UNSET_BIT(a, f) \ (a) &= ~(f) #define PMIX_CHECK_BIT_IS_SET(a, f) \ ((a) & (f)) #define PMIX_CHECK_BIT_NOT_SET(a, f) \ !PMIX_CHECK_BIT_IS_SET(a, f) #define PMIX_INFO_OP_COMPLETE 0x80000000 #define PMIX_INFO_OP_COMPLETED(m) \ PMIX_SET_BIT((m)->flags, PMIX_INFO_OP_COMPLETE) #define PMIX_INFO_OP_IS_COMPLETE(m) \ PMIX_CHECK_BIT_IS_SET((m)->flags, PMIX_INFO_OP_COMPLETE) /* define an internal-only object for creating * lists of names */ typedef struct { pmix_list_item_t super; pmix_name_t *pname; } pmix_namelist_t; PMIX_CLASS_DECLARATION(pmix_namelist_t); /* define structs for holding entries in the * show-help matrix */ typedef struct { const char *topic; const char **content; } pmix_show_help_entry_t; typedef struct { const char *filename; pmix_show_help_entry_t *entries; } pmix_show_help_file_t; PMIX_EXPORT extern pmix_show_help_file_t pmix_show_help_data[]; /* define a struct for holding entries in the * dictionary of attributes */ typedef struct { uint32_t index; char *name; char *string; pmix_data_type_t type; char **description; } pmix_regattr_input_t; #define PMIX_REGATTR_INPUT_NEW(a, i, n, s, t, d) \ do { \ (a) = (pmix_regattr_input_t*)pmix_malloc(sizeof(pmix_regattr_input_t)); \ if (NULL != (a)) { \ memset((a), 0, sizeof(pmix_regattr_input_t)); \ (a)->index = (i); \ if (NULL != (n)) { \ (a)->name = strdup((n)); \ } \ if (NULL != (s)) { \ (a)->string = strdup((s)); \ } \ (a)->type = (t); \ if (NULL != (d)) { \ (a)->description = PMIx_Argv_copy((d)); \ } \ } \ } while(0) #define PMIX_REGATTR_INPUT_FREE(a) \ do { \ if (NULL != (a)) { \ if (NULL != (a)->name) { \ free((a)->name); \ } \ if (NULL != (a)->string) \ free((a)->string); \ } \ if (NULL != (a)->description) { \ free((a)->description); \ } \ } \ } while(0) /* define a struct for holding entries in the * dictionary of event strings */ typedef struct { uint32_t index; char *name; int32_t code; } pmix_event_string_t; /* define a struct for storing data in memory */ typedef struct { uint32_t index; pmix_value_t *value; } pmix_qual_t; #define PMIX_QUAL_NEW(d, k) \ do { \ (d) = (pmix_qual_t*)pmix_malloc(sizeof(pmix_qual_t)); \ if (NULL != (d)) { \ (d)->index = k; \ (d)->value = NULL; \ } \ } while(0) #define PMIX_QUAL_RELEASE(d) \ do { \ if (NULL != (d)->value) { \ PMIX_VALUE_RELEASE((d)->value); \ } \ } while(0) typedef struct { uint32_t index; uint32_t qualindex; pmix_value_t *value; } pmix_dstor_t; PMIX_EXPORT pmix_dstor_t * pmix_dstor_new_tma( uint32_t index, pmix_tma_t *tma ); PMIX_EXPORT void pmix_dstor_release_tma( pmix_dstor_t *d, pmix_tma_t *tma ); #define PMIX_DSTOR_NEW(d, k) \ do { \ (d) = pmix_dstor_new_tma((k), NULL); \ } while(0) #define PMIX_DSTOR_RELEASE(d) \ do { \ pmix_dstor_release_tma((d), NULL); \ } while(0) /* define a struct for passing topology objects */ typedef struct { pmix_object_t super; char *source; void *object; } pmix_topo_obj_t; PMIX_CLASS_DECLARATION(pmix_topo_obj_t); /* define a command type for communicating to the * pmix server */ typedef uint8_t pmix_cmd_t; /* define some commands */ #define PMIX_REQ_CMD 0 #define PMIX_ABORT_CMD 1 #define PMIX_COMMIT_CMD 2 #define PMIX_FENCENB_CMD 3 #define PMIX_GETNB_CMD 4 #define PMIX_FINALIZE_CMD 5 #define PMIX_PUBLISHNB_CMD 6 #define PMIX_LOOKUPNB_CMD 7 #define PMIX_UNPUBLISHNB_CMD 8 #define PMIX_SPAWNNB_CMD 9 #define PMIX_CONNECTNB_CMD 10 #define PMIX_DISCONNECTNB_CMD 11 #define PMIX_NOTIFY_CMD 12 #define PMIX_REGEVENTS_CMD 13 #define PMIX_DEREGEVENTS_CMD 14 #define PMIX_QUERY_CMD 15 #define PMIX_LOG_CMD 16 #define PMIX_ALLOC_CMD 17 #define PMIX_JOB_CONTROL_CMD 18 #define PMIX_MONITOR_CMD 19 #define PMIX_GET_CREDENTIAL_CMD 20 #define PMIX_VALIDATE_CRED_CMD 21 #define PMIX_IOF_PULL_CMD 22 #define PMIX_IOF_PUSH_CMD 23 #define PMIX_GROUP_CONSTRUCT_CMD 24 #define PMIX_GROUP_JOIN_CMD 25 #define PMIX_GROUP_INVITE_CMD 26 #define PMIX_GROUP_LEAVE_CMD 27 #define PMIX_GROUP_DESTRUCT_CMD 28 #define PMIX_IOF_DEREG_CMD 29 #define PMIX_FABRIC_REGISTER_CMD 30 #define PMIX_FABRIC_UPDATE_CMD 31 #define PMIX_COMPUTE_DEVICE_DISTANCES_CMD 32 #define PMIX_REFRESH_CACHE 33 #define PMIX_RESBLK_CMD 34 #define PMIX_SESSION_CTRL_CMD 35 #define PMIX_REQ_SYSINFO_CMD 36 #define PMIX_RESOLVE_PEERS_CMD 37 #define PMIX_RESOLVE_NODE_CMD 38 /* provide a "pretty-print" function for cmds */ const char *pmix_command_string(pmix_cmd_t cmd); /* provide a hook to init tool data */ PMIX_EXPORT extern pmix_status_t pmix_tool_init_info(void); /* define a set of flags to direct collection * of data during operations */ typedef enum { PMIX_COLLECT_INVALID = -1, PMIX_COLLECT_NO, PMIX_COLLECT_YES, PMIX_COLLECT_MAX } pmix_collect_t; /**** PEER STRUCTURES ****/ /* clients can only talk to their server, and servers are * assumed to all have the same personality. Thus, each * process only needs to track a single set of personality * modules. All interactions between a client and its local * server, or between servers, are done thru these modules */ typedef struct pmix_personality_t { pmix_bfrop_buffer_type_t type; pmix_bfrops_module_t *bfrops; pmix_psec_module_t *psec; pmix_gds_base_module_t *gds; } pmix_personality_t; /* define a set of structs for tracking post-termination cleanup */ typedef struct pmix_epilog_t { uid_t uid; gid_t gid; pmix_list_t cleanup_dirs; pmix_list_t cleanup_files; pmix_list_t ignores; } pmix_epilog_t; typedef struct { pmix_list_item_t super; char *path; } pmix_cleanup_file_t; PMIX_CLASS_DECLARATION(pmix_cleanup_file_t); typedef struct { pmix_list_item_t super; char *path; bool recurse; bool leave_topdir; } pmix_cleanup_dir_t; PMIX_CLASS_DECLARATION(pmix_cleanup_dir_t); /* define a struct to hold booleans controlling the * format/contents of the output */ typedef struct { bool set; bool xml; bool timestamp; bool tag; bool tag_detailed; bool tag_fullname; bool rank; char *file; char *directory; bool nocopy; bool merge; bool local_output; bool local_output_given; bool pattern; bool raw; } pmix_iof_flags_t; #define PMIX_IOF_FLAGS_STATIC_INIT \ { \ .set = false, \ .xml = false, \ .timestamp = false, \ .tag = false, \ .tag_detailed = false, \ .tag_fullname = false, \ .rank = false, \ .file = NULL, \ .directory = NULL, \ .nocopy = false, \ .merge = false, \ .local_output = false, \ .local_output_given = false, \ .pattern = false, \ .raw = false \ } /* objects used by servers for tracking active nspaces */ typedef struct { pmix_list_item_t super; char *nspace; struct { uint8_t major; uint8_t minor; uint8_t release; } version; pmix_rank_t nprocs; // num procs in this nspace size_t nlocalprocs; bool all_registered; // all local ranks have been defined bool version_stored; // the version string used by this nspace has been stored bool job_info_recvd; // job-level info has been received pmix_buffer_t *jobbkt; // packed version of jobinfo size_t ndelivered; // count of #local clients that have received the jobinfo size_t nfinalized; // count of #local clients that have finalized pmix_list_t ranks; // list of pmix_rank_info_t for connection support of my clients /* all members of an nspace are required to have the * same personality, but it can differ between nspaces. * Since servers may support clients from multiple nspaces, * track their respective compatibility modules here */ pmix_personality_t compat; pmix_epilog_t epilog; // things to do upon termination of all local clients // from this nspace pmix_list_t setup_data; // list of pmix_kval_t containing info structs having blobs // for setting up the local node for this nspace/application pmix_iof_flags_t iof_flags; // output formatting flags pmix_list_t sinks; // IOF write events for output to files or directories } pmix_namespace_t; PMIX_CLASS_DECLARATION(pmix_namespace_t); /* define a caddy for quickly creating a list of pmix_namespace_t * objects for local, dedicated purposes */ typedef struct { pmix_list_item_t super; pmix_namespace_t *ns; } pmix_nspace_caddy_t; PMIX_CLASS_DECLARATION(pmix_nspace_caddy_t); typedef struct { pmix_list_item_t super; pmix_namespace_t *ns; pmix_list_t envars; } pmix_nspace_env_cache_t; PMIX_CLASS_DECLARATION(pmix_nspace_env_cache_t); typedef struct { pmix_list_item_t super; pmix_envar_t envar; } pmix_envar_list_item_t; PMIX_CLASS_DECLARATION(pmix_envar_list_item_t); typedef struct pmix_rank_info_t { pmix_list_item_t super; int peerid; // peer object index into the local clients array on the server pmix_name_t pname; pid_t pid; uid_t realuid; uid_t uid; gid_t realgid; gid_t gid; bool modex_recvd; int proc_cnt; // #clones of this rank we know about void *server_object; // pointer to rank-specific object provided by server } pmix_rank_info_t; PMIX_CLASS_DECLARATION(pmix_rank_info_t); /* define a very simple caddy for dealing with pmix_info_t * and pmix_query_t objects when transferring portions of arrays */ typedef struct { pmix_list_item_t super; pmix_info_t *info; size_t ninfo; } pmix_info_caddy_t; PMIX_CLASS_DECLARATION(pmix_info_caddy_t); typedef struct { pmix_list_item_t super; pmix_info_t info; } pmix_infolist_t; PMIX_CLASS_DECLARATION(pmix_infolist_t); typedef struct { pmix_list_item_t super; pmix_query_t query; } pmix_querylist_t; PMIX_CLASS_DECLARATION(pmix_querylist_t); typedef struct { pmix_list_item_t super; pmix_proc_t proc; } pmix_proclist_t; PMIX_CLASS_DECLARATION(pmix_proclist_t); /* object for tracking peers - each peer can have multiple * connections. This can occur if the initial app executes * a fork/exec, and the child initiates its own connection * back to the PMIx server. Thus, the trackers should be "indexed" * by the socket, not the process nspace/rank */ typedef struct pmix_peer_t { pmix_object_t super; pmix_namespace_t *nptr; // point to the nspace object for this process pmix_rank_info_t *info; pmix_proc_type_t proc_type; pmix_listener_protocol_t protocol; int proc_cnt; int index; // index into the local clients array on the server int sd; bool finalized; // peer has called finalize pmix_event_t send_event; /**< registration with event thread for send events */ bool send_ev_active; pmix_event_t recv_event; /**< registration with event thread for recv events */ bool recv_ev_active; pmix_list_t send_queue; /**< list of messages to send */ pmix_ptl_send_t *send_msg; /**< current send in progress */ pmix_ptl_recv_t *recv_msg; /**< current recv in progress */ int commit_cnt; pmix_epilog_t epilog; /**< things to be performed upon termination of this peer */ uint32_t dyn_tags_start; // lower limit of valid tags for sendrecvs to this peer uint32_t dyn_tags_current; // current tag for sendrecvs to this peer uint32_t dyn_tags_end; // upper limit of valid tags for sendrecvs to this peer } pmix_peer_t; PMIX_CLASS_DECLARATION(pmix_peer_t); typedef struct { pmix_list_item_t super; pmix_peer_t *peer; } pmix_peerlist_t; PMIX_CLASS_DECLARATION(pmix_peerlist_t); typedef struct { pmix_object_t super; struct timeval tv; pmix_event_t ev; bool active; void *payload; } pmix_timer_t; PMIX_CLASS_DECLARATION(pmix_timer_t); /* tracker for IOF requests */ typedef struct { pmix_object_t super; pmix_event_t ev; pmix_lock_t lock; pmix_status_t status; pmix_peer_t *requestor; size_t local_id; size_t remote_id; pmix_proc_t *procs; size_t nprocs; pmix_iof_flags_t flags; pmix_iof_channel_t channels; pmix_info_t *directives; size_t ndirs; pmix_iof_cbfunc_t cbfunc; pmix_hdlr_reg_cbfunc_t regcbfunc; void *cbdata; } pmix_iof_req_t; PMIX_CLASS_DECLARATION(pmix_iof_req_t); /* caddy for query requests */ typedef struct { pmix_object_t super; pmix_event_t ev; pmix_lock_t lock; bool host_called; pmix_status_t status; pmix_query_t *queries; size_t nqueries; pmix_proc_t *targets; size_t ntargets; pmix_info_t *info; pmix_info_t *dirs; size_t ninfo; size_t ndirs; pmix_list_t results; size_t nreplies; size_t nrequests; pmix_byte_object_t bo; pmix_info_cbfunc_t cbfunc; pmix_value_cbfunc_t valcbfunc; pmix_release_cbfunc_t relcbfunc; pmix_credential_cbfunc_t credcbfunc; pmix_validation_cbfunc_t validcbfunc; void *cbdata; } pmix_query_caddy_t; PMIX_CLASS_DECLARATION(pmix_query_caddy_t); typedef struct { pmix_list_item_t super; char *grpid; size_t ctxid; pmix_proc_t *members; size_t nmbrs; } pmix_group_t; PMIX_CLASS_DECLARATION(pmix_group_t); typedef struct { pmix_list_item_t super; pmix_proc_t proc; pmix_byte_object_t blob; // packed blob of info provided by this proc } pmix_grpinfo_t; PMIX_CLASS_DECLARATION(pmix_grpinfo_t); /* define a tracker for collective operations * - instanced in pmix_server_ops.c */ typedef struct { pmix_list_item_t super; pmix_event_t ev; bool event_active; bool host_called; // tracker has been passed up to host bool local; // operation is strictly local char *id; // string identifier for the collective pmix_cmd_t type; pmix_proc_t pname; bool hybrid; // true if participating procs are from more than one nspace pmix_proc_t *pcs; // copy of the original array of participants size_t npcs; // number of procs in the array pmix_list_t nslist; // unique nspace list of participants pmix_lock_t lock; // flag for waiting for completion bool def_complete; // all local procs have been registered and the trk definition is complete pmix_list_t local_cbs; // list of pmix_server_caddy_t for sending result to the local participants // Note: there may be multiple entries for a given proc if that proc // has fork/exec'd clones that are also participating uint32_t nlocal; // number of local participants uint32_t local_cnt; // number of local participants who have contributed pmix_info_t *info; // array of info structs size_t ninfo; // number of info structs in array pmix_list_t grpinfo; // list of group info to be distributed int grpop; // the group operation being tracked pmix_collect_t collect_type; // whether or not data is to be returned at completion pmix_modex_cbfunc_t modexcbfunc; pmix_op_cbfunc_t op_cbfunc; pmix_info_cbfunc_t info_cbfunc; void *cbdata; } pmix_server_trkr_t; PMIX_CLASS_DECLARATION(pmix_server_trkr_t); /* define an object for moving a send * request into the server's event base and * dealing with some request timeouts * - instanced in pmix_server_ops.c */ typedef struct { pmix_list_item_t super; pmix_event_t ev; bool event_active; pmix_server_trkr_t *trk; pmix_ptl_hdr_t hdr; pmix_peer_t *peer; pmix_info_t *info; size_t ninfo; pmix_query_t *query; } pmix_server_caddy_t; PMIX_CLASS_DECLARATION(pmix_server_caddy_t); /**** THREAD-RELATED ****/ /* define a caddy for thread-shifting operations */ typedef struct { pmix_object_t super; pmix_event_t ev; pmix_lock_t lock; pmix_status_t status; pmix_status_t *codes; size_t ncodes; uint32_t sessionid; pmix_name_t pname; pmix_proc_t *proc; pmix_peer_t *peer; const char *data; size_t ndata; const char *key; bool infocopy; pmix_info_t *info; size_t ninfo; bool dircopy; pmix_info_t *directives; size_t ndirs; pmix_pdata_t *pdata; size_t npdata; pmix_byte_object_t *bo; pmix_device_distance_t *dist; size_t ndist; pmix_data_range_t range; pmix_notification_fn_t evhdlr; pmix_iof_req_t *iofreq; pmix_kval_t *kv; pmix_value_t *vptr; pmix_server_caddy_t *cd; pmix_server_trkr_t *tracker; bool enviro; union { pmix_release_cbfunc_t relfn; pmix_hdlr_reg_cbfunc_t hdlrregcbfn; pmix_op_cbfunc_t opcbfn; pmix_modex_cbfunc_t modexcbfunc; pmix_info_cbfunc_t infocbfunc; } cbfunc; void *cbdata; void *relcbdata; size_t ref; } pmix_shift_caddy_t; PMIX_CLASS_DECLARATION(pmix_shift_caddy_t); typedef struct { pmix_object_t super; pmix_proc_t p; bool pntrval; bool stval; bool optional; bool immediate; bool add_immediate; bool refresh_cache; pmix_scope_t scope; bool sessioninfo; bool sessiondirective; uint32_t sessionid; bool nodeinfo; bool nodedirective; char *hostname; uint32_t nodeid; bool appinfo; bool appdirective; uint32_t appnum; } pmix_get_logic_t; PMIX_CLASS_DECLARATION(pmix_get_logic_t); /* struct for tracking ops */ typedef struct { pmix_list_item_t super; pmix_event_t ev; pmix_lock_t lock; bool checked; int status; pmix_status_t pstatus; pmix_scope_t scope; pmix_buffer_t data; union { pmix_ptl_cbfunc_t ptlfn; pmix_op_cbfunc_t opfn; pmix_value_cbfunc_t valuefn; pmix_lookup_cbfunc_t lookupfn; pmix_spawn_cbfunc_t spawnfn; pmix_hdlr_reg_cbfunc_t hdlrregfn; pmix_info_cbfunc_t infofn; pmix_device_dist_cbfunc_t distfn; } cbfunc; size_t errhandler_ref; void *cbdata; pmix_name_t pname; char *key; pmix_value_t *value; pmix_proc_t *proc; pmix_proc_t *procs; size_t nprocs; pmix_info_t *info; size_t ninfo; pmix_info_t *directives; size_t ndirs; pmix_device_distance_t *dist; pmix_byte_object_t *bo; bool infocopy; size_t nvals; pmix_list_t kvs; bool copy; pmix_get_logic_t *lg; bool timer_running; pmix_fabric_t *fabric; pmix_topology_t *topo; } pmix_cb_t; PMIX_CLASS_DECLARATION(pmix_cb_t); #define PMIX_THREADSHIFT(r, c) \ do { \ pmix_event_assign(&((r)->ev), pmix_globals.evbase, -1, EV_WRITE, (c), (r)); \ PMIX_POST_OBJECT((r)); \ pmix_event_active(&((r)->ev), EV_WRITE, 1); \ } while (0) #define PMIX_THREADSHIFT_DELAY(r, c, t) \ do { \ struct timeval _tv = {0, 0}; \ pmix_event_evtimer_set(pmix_globals.evbase, &(r)->ev, (c), (r)); \ _tv.tv_sec = (int) (t); \ _tv.tv_usec = ((t) -_tv.tv_sec) * 1000000.0; \ PMIX_POST_OBJECT((r)); \ pmix_event_evtimer_add(&(r)->ev, &_tv); \ } while (0) typedef struct { pmix_object_t super; pmix_event_t ev; pmix_lock_t lock; /* timestamp receipt of the notification so we * can evict the oldest one if we get overwhelmed */ time_t ts; /* what room of the hotel they are in */ int room; pmix_status_t status; pmix_proc_t source; pmix_data_range_t range; bool staylocal; // do not pass up to host environment /* For notification, we use the targets field to track * any custom range of procs that are to receive the * event. */ pmix_proc_t *targets; size_t ntargets; size_t nleft; // number of targets left to be notified /* When generating a notification, the originator can * specify the range of procs affected by this event. * For example, when creating a JOB_TERMINATED event, * the RM can specify the nspace of the job that has * ended, thus allowing users to provide a different * callback object based on the nspace being monitored. * We use the "affected" field to track these values * when processing the event chain. */ pmix_proc_t *affected; size_t naffected; /* track if the event generator stipulates that default * event handlers are/are not to be given the event */ bool nondefault; /* carry along any other provided info so the individual * handlers can look at it */ pmix_info_t *info; size_t ninfo; /* allow for a buffer to be carried across internal processing */ pmix_buffer_t *buf; /* the final callback to be executed upon completion of the event */ pmix_op_cbfunc_t cbfunc; void *cbdata; } pmix_notify_caddy_t; PMIX_CLASS_DECLARATION(pmix_notify_caddy_t); typedef struct { pmix_object_t super; /** Points to key <--> index translation table. */ pmix_pointer_array_t *table; /** Stores the next ID. */ uint32_t next_id; } pmix_keyindex_t; PMIX_CLASS_DECLARATION(pmix_keyindex_t); #define PMIX_KEYINDEX_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \ .table = NULL, \ .next_id = PMIX_INDEX_BOUNDARY \ } /**** GLOBAL STORAGE ****/ /* define a global construct that includes values that must be shared * between various parts of the code library. This structure is * instanced and initialized in runtime/pmix_init.c */ typedef struct { // control atomics bool init_called; atomic_bool initialized; atomic_bool util_initialized; atomic_bool connected; atomic_bool progress_thread_stopped; // proc info pmix_proc_t myid; pmix_value_t myidval; pmix_value_t myrankval; pmix_peer_t *mypeer; // my own peer object uid_t realuid; // real uid uid_t uid; // my effective uid gid_t realgid; // real gid gid_t gid; // my effective gid char *hostname; // my hostname char **aliases; // aliases for my hostname uint32_t appnum; // my appnum pid_t pid; // my local pid uint32_t nodeid; // my nodeid, if given uint32_t sessionid; // my sessionid, if given int pindex; pmix_event_base_t *evbase; pmix_event_base_t *evauxbase; int debug_output; pmix_events_t events; // my event handler registrations. bool commits_pending; struct timeval event_window; pmix_list_t cached_events; // events waiting in the window prior to processing pmix_pointer_array_t iof_requests; // array of pmix_iof_req_t IOF requests int max_events; // size of the notifications hotel int event_eviction_time; // max time to cache notifications pmix_hotel_t notifications; // hotel of pending notifications /* IOF controls */ bool pushstdin; pmix_list_t stdin_targets; // list of pmix_namelist_t bool tag_output; bool xml_output; bool timestamp_output; size_t output_limit; pmix_list_t nspaces; pmix_topology_t topology; pmix_cpuset_t cpuset; bool external_topology; bool external_progress; pmix_iof_flags_t iof_flags; pmix_keyindex_t keyindex; } pmix_globals_t; /* provide access to a function to cleanup epilogs */ PMIX_EXPORT void pmix_execute_epilog(pmix_epilog_t *ep); PMIX_EXPORT pmix_status_t pmix_notify_event_cache(pmix_notify_caddy_t *cd); PMIX_EXPORT extern pmix_globals_t pmix_globals; PMIX_EXPORT extern const char* PMIX_PROXY_VERSION; PMIX_EXPORT extern const char* PMIX_PROXY_BUGREPORT; PMIX_EXPORT void pmix_log_local_op(int sd, short args, void *cbdata_); static inline bool pmix_check_node_info(const char *key) { char *keys[] = { PMIX_HOSTNAME, PMIX_HOSTNAME_ALIASES, PMIX_NODEID, PMIX_AVAIL_PHYS_MEMORY, PMIX_LOCAL_PEERS, PMIX_LOCAL_PROCS, PMIX_LOCAL_CPUSETS, PMIX_LOCAL_SIZE, PMIX_NODE_SIZE, PMIX_LOCALLDR, PMIX_NODE_OVERSUBSCRIBED, PMIX_FABRIC_DEVICES, PMIX_FABRIC_COORDINATES, PMIX_FABRIC_DEVICE, PMIX_FABRIC_DEVICE_INDEX, PMIX_FABRIC_DEVICE_NAME, PMIX_FABRIC_DEVICE_VENDOR, PMIX_FABRIC_DEVICE_BUS_TYPE, PMIX_FABRIC_DEVICE_VENDORID, PMIX_FABRIC_DEVICE_DRIVER, PMIX_FABRIC_DEVICE_FIRMWARE, PMIX_FABRIC_DEVICE_ADDRESS, PMIX_FABRIC_DEVICE_MTU, PMIX_FABRIC_DEVICE_COORDINATES, PMIX_FABRIC_DEVICE_SPEED, PMIX_FABRIC_DEVICE_STATE, PMIX_FABRIC_DEVICE_TYPE, PMIX_FABRIC_DEVICE_PCI_DEVID, NULL }; size_t n; for (n = 0; NULL != keys[n]; n++) { if (0 == strncmp(key, keys[n], PMIX_MAX_KEYLEN)) { return true; } } return false; } static inline bool pmix_check_app_info(const char *key) { char *keys[] = { PMIX_APP_SIZE, PMIX_APPLDR, PMIX_APP_ARGV, PMIX_WDIR, PMIX_PSET_NAME, PMIX_PSET_MEMBERS, PMIX_APP_MAP_TYPE, PMIX_APP_MAP_REGEX, NULL }; size_t n; for (n = 0; NULL != keys[n]; n++) { if (0 == strncmp(key, keys[n], PMIX_MAX_KEYLEN)) { return true; } } return false; } static inline bool pmix_check_session_info(const char *key) { char *keys[] = { PMIX_SESSION_ID, PMIX_CLUSTER_ID, PMIX_UNIV_SIZE, PMIX_TMPDIR, PMIX_TDIR_RMCLEAN, PMIX_HOSTNAME_KEEP_FQDN, PMIX_RM_NAME, PMIX_RM_VERSION, NULL }; size_t n; for (n = 0; NULL != keys[n]; n++) { if (0 == strncmp(key, keys[n], PMIX_MAX_KEYLEN)) { return true; } } return false; } static inline bool pmix_check_special_key(const char *key) { char *keys[] = { PMIX_GROUP_CONTEXT_ID, PMIX_GROUP_LOCAL_CID, NULL }; size_t n; for (n = 0; NULL != keys[n]; n++) { if (0 == strncmp(key, keys[n], PMIX_MAX_KEYLEN)) { return true; } } return false; } static inline bool pmix_check_local(const char *hostname) { size_t n; // first do simple check if (0 == strcmp(pmix_globals.hostname, hostname)) { return true; } // now check aliases if (NULL != pmix_globals.aliases) { for (n=0; NULL != pmix_globals.aliases[n]; n++) { if (0 == strcmp(pmix_globals.aliases[n], hostname)) { return true; } } } return false; } #if PMIX_PICKY_COMPILERS #define PMIX_HIDE_UNUSED_PARAMS(...) \ do { \ int __x = 3; \ pmix_hide_unused_params(__x, __VA_ARGS__); \ } while(0) PMIX_EXPORT void pmix_hide_unused_params(int x, ...); #else #define PMIX_HIDE_UNUSED_PARAMS(...) #endif #define PMIX_TRACE_KEY_ACTUAL(s, k, v) \ do { \ if (0 == strcmp(s, k)) { \ char *_v = PMIx_Value_string(v); \ pmix_output(0, "[%s:%s:%d] %s\n%s\n", \ __FILE__, __func__, __LINE__, \ PMIx_Get_attribute_name(k), _v); \ free(_v); \ } \ } while(0) #define PMIX_TRACE_KEY(c, s, k, v) \ do { \ if (0 == strcasecmp(c, "SERVER") && \ PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { \ PMIX_TRACE_KEY_ACTUAL(s, k, v); \ } else if (0 == strcasecmp(c, "CLIENT") && \ !PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) { \ PMIX_TRACE_KEY_ACTUAL(s, k, v); \ } \ } while (0) END_C_DECLS #endif /* PMIX_GLOBALS_H */ pmix-6.1.1~rc2/src/class/0000775000175000017500000000000015203536752015371 5ustar alastairalastairpmix-6.1.1~rc2/src/class/pmix_hotel.h0000664000175000017500000003246215203536752017721 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2012-2016 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012 Los Alamos National Security, LLC. All rights reserved * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2020 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file * * This file provides a "hotel" class: * * - A hotel has a fixed number of rooms (i.e., storage slots) * - An arbitrary data pointer can check into an empty room at any time * - The occupant of a room can check out at any time * - Optionally, the occupant of a room can be forcibly evicted at a * given time (i.e., when an pmix timer event expires). * - The hotel has finite occupancy; if you try to checkin a new * occupant and the hotel is already full, it will gracefully fail * to checkin. * * One use case for this class is for ACK-based network retransmission * schemes (NACK-based retransmission schemes probably can use * pmix_ring_buffer). * * For ACK-based retransmission schemes, a hotel might be used * something like this: * * - when a message is sent, check it in to a hotel with a timer * - if an ACK is received, check it out of the hotel (which also cancels * the timer) * - if an ACK isn't received in time, the timer will expire and the * upper layer will get a callback with the message * - if an ACK is received late (i.e., after its timer has expired), * then checkout will gracefully fail * * Note that this class intentionally provides pretty minimal * functionality. It is intended to be used in performance-critical * code paths -- extra functionality would simply add latency. * * There is an pmix_hotel_init() function to create a hotel, but no * corresponding finalize; the destructor will handle all finalization * issues. Note that when a hotel is destroyed, it will delete all * pending events from the event base (i.e., all pending eviction * callbacks); no further eviction callbacks will be invoked. */ #ifndef PMIX_HOTEL_H #define PMIX_HOTEL_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include "src/class/pmix_object.h" #include "src/include/pmix_prefetch.h" #include "src/include/pmix_types.h" #include #include "src/util/pmix_error.h" #include "src/util/pmix_output.h" BEGIN_C_DECLS struct pmix_hotel_t; /* User-supplied function to be invoked when an occupant is evicted. */ typedef void (*pmix_hotel_eviction_callback_fn_t)(struct pmix_hotel_t *hotel, int room_num, void *occupant); /* Note that this is an internal data structure; it is not part of the public pmix_hotel interface. Public consumers of pmix_hotel shouldn't need to use this struct at all (we only have it here in this .h file because some functions are inlined for speed, and need to get to the internals of this struct). The room struct should be as small as possible to be cache friendly. Specifically: it would be great if multiple rooms could fit in a single cache line because we'll always allocate a contiguous set of rooms in an array. */ typedef struct { void *occupant; pmix_event_t eviction_timer_event; } pmix_hotel_room_t; /* Note that this is an internal data structure; it is not part of the public pmix_hotel interface. Public consumers of pmix_hotel shouldn't need to use this struct at all (we only have it here in this .h file because some functions are inlined for speed, and need to get to the internals of this struct). Use a unique struct for holding the arguments for eviction callbacks. We *could* make the to-be-evicted pmix_hotel_room_t instance as the argument, but we don't, for 2 reasons: 1. We want as many pmix_hotel_room_t's to fit in a cache line as possible (i.e., to be as cache-friendly as possible). The common/fast code path only needs to access the data in the pmix_hotel_room_t (and not the callback argument data). 2. Evictions will be uncommon, so we don't mind penalizing them a bit by making the data be in a separate cache line. */ typedef struct { struct pmix_hotel_t *hotel; int room_num; } pmix_hotel_room_eviction_callback_arg_t; typedef struct pmix_hotel_t { /* make this an object */ pmix_object_t super; /* Max number of rooms in the hotel */ int num_rooms; /* event base to be used for eviction timeout */ pmix_event_base_t *evbase; struct timeval eviction_timeout; pmix_hotel_eviction_callback_fn_t evict_callback_fn; /* All rooms in this hotel */ pmix_hotel_room_t *rooms; /* Separate array for all the eviction callback arguments (see rationale above for why this is a separate array) */ pmix_hotel_room_eviction_callback_arg_t *eviction_args; /* All currently unoccupied rooms in this hotel (not necessarily in any particular order) */ int *unoccupied_rooms; int last_unoccupied_room; } pmix_hotel_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_hotel_t); #define PMIX_HOTEL_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \ .num_rooms = 0, \ .evbase = NULL, \ .eviction_timeout = {0, 0}, \ .evict_callback_fn = NULL, \ .rooms = NULL, \ .eviction_args = NULL, \ .unoccupied_rooms = NULL, \ .last_unoccupied_room = 0 \ } /** * Initialize the hotel. * * @param hotel Pointer to a hotel (IN) * @param num_rooms The total number of rooms in the hotel (IN) * @param evbase Pointer to event base used for eviction timeout * @param eviction_timeout Max length of a stay at the hotel before * the eviction callback is invoked (in seconds) * @param evict_callback_fn Callback function invoked if an occupant * does not check out before the eviction_timeout. * * NOTE: If the callback function is NULL, then no eviction timer * will be set - occupants will remain checked into the hotel until * explicitly checked out. * * Also note: the eviction_callback_fn should absolutely not call any * of the hotel checkout functions. Specifically: the occupant has * already been ("forcibly") checked out *before* the * eviction_callback_fn is invoked. * * @return PMIX_SUCCESS if all initializations were successful. Otherwise, * the error indicate what went wrong in the function. */ PMIX_EXPORT pmix_status_t pmix_hotel_init(pmix_hotel_t *hotel, int num_rooms, pmix_event_base_t *evbase, uint32_t eviction_timeout, pmix_hotel_eviction_callback_fn_t evict_callback_fn); /** * Check in an occupant to the hotel. * * @param hotel Pointer to hotel (IN) * @param occupant Occupant to check in (opaque to the hotel) (IN) * @param room The room number that identifies this occupant in the * hotel (OUT). * * If there is room in the hotel, the occupant is checked in and the * timer for that occupant is started. The occupant's room is * returned in the "room" param. * * Note that once a room's checkout_expire timer expires, the occupant * is forcibly checked out, and then the eviction callback is invoked. * * @return PMIX_SUCCESS if the occupant is successfully checked in, * and the room parameter will contain a valid value. * @return PMIX_ERR_TEMP_OUT_OF_RESOURCE is the hotel is full. Try * again later. */ static inline pmix_status_t pmix_hotel_checkin(pmix_hotel_t *hotel, void *occupant, int *room_num) { pmix_hotel_room_t *room; /* Do we have any rooms available? */ if (PMIX_UNLIKELY(hotel->last_unoccupied_room < 0)) { *room_num = -1; return PMIX_ERR_OUT_OF_RESOURCE; } /* Put this occupant into the first empty room that we have */ *room_num = hotel->unoccupied_rooms[hotel->last_unoccupied_room--]; room = &(hotel->rooms[*room_num]); room->occupant = occupant; /* Assign the event and make it pending */ if (NULL != hotel->evbase) { pmix_event_add(&(room->eviction_timer_event), &(hotel->eviction_timeout)); } return PMIX_SUCCESS; } /** * Same as pmix_hotel_checkin(), but slightly optimized for when the * caller *knows* that there is a room available. */ static inline void pmix_hotel_checkin_with_res(pmix_hotel_t *hotel, void *occupant, int *room_num) { pmix_hotel_room_t *room; /* Put this occupant into the first empty room that we have */ *room_num = hotel->unoccupied_rooms[hotel->last_unoccupied_room--]; room = &(hotel->rooms[*room_num]); assert(room->occupant == NULL); room->occupant = occupant; /* Assign the event and make it pending */ if (NULL != hotel->evbase) { pmix_event_add(&(room->eviction_timer_event), &(hotel->eviction_timeout)); } } /** * Check the specified occupant out of the hotel. * * @param hotel Pointer to hotel (IN) * @param room Room number to checkout (IN) * * If there is an occupant in the room, their timer is canceled and * they are checked out. * * Nothing is returned (as a minor optimization). */ static inline void pmix_hotel_checkout(pmix_hotel_t *hotel, int room_num) { pmix_hotel_room_t *room; /* Bozo check */ assert(room_num < hotel->num_rooms); if (0 > room_num) { /* occupant wasn't checked in */ return; } /* If there's an occupant in the room, check them out */ room = &(hotel->rooms[room_num]); if (PMIX_LIKELY(NULL != room->occupant)) { /* Do not change this logic without also changing the same logic in pmix_hotel_checkout_and_return_occupant() and pmix_hotel.c:local_eviction_callback(). */ room->occupant = NULL; if (NULL != hotel->evbase) { pmix_event_del(&(room->eviction_timer_event)); } hotel->last_unoccupied_room++; assert(hotel->last_unoccupied_room < hotel->num_rooms); hotel->unoccupied_rooms[hotel->last_unoccupied_room] = room_num; } /* Don't bother returning whether we actually checked someone out or not (because this is in the critical performance path) -- assume the upper layer knows what it's doing. */ } /** * Check the specified occupant out of the hotel and return the occupant. * * @param hotel Pointer to hotel (IN) * @param room Room number to checkout (IN) * @param void * occupant (OUT) * If there is an occupant in the room, their timer is canceled and * they are checked out. * * Use this checkout and when caller needs the occupant */ static inline void pmix_hotel_checkout_and_return_occupant(pmix_hotel_t *hotel, int room_num, void **occupant) { pmix_hotel_room_t *room; /* Bozo check */ assert(room_num < hotel->num_rooms); if (0 > room_num) { /* occupant wasn't checked in */ *occupant = NULL; return; } /* If there's an occupant in the room, check them out */ room = &(hotel->rooms[room_num]); if (PMIX_LIKELY(NULL != room->occupant)) { pmix_output(10, "checking out occupant %p from room num %d", room->occupant, room_num); /* Do not change this logic without also changing the same logic in pmix_hotel_checkout() and pmix_hotel.c:local_eviction_callback(). */ *occupant = room->occupant; room->occupant = NULL; if (NULL != hotel->evbase) { pmix_event_del(&(room->eviction_timer_event)); } hotel->last_unoccupied_room++; assert(hotel->last_unoccupied_room < hotel->num_rooms); hotel->unoccupied_rooms[hotel->last_unoccupied_room] = room_num; } else { *occupant = NULL; } } /** * Returns true if the hotel is empty (no occupant) * @param hotel Pointer to hotel (IN) * @return bool true if empty false if there is a occupant(s) * */ static inline bool pmix_hotel_is_empty(pmix_hotel_t *hotel) { if (hotel->last_unoccupied_room == hotel->num_rooms - 1) return true; else return false; } /** * Access the occupant of a room, but leave them checked into their room. * * @param hotel Pointer to hotel (IN) * @param room Room number to checkout (IN) * @param void * occupant (OUT) * * This accessor function is typically used to cycle across the occupants * to check for someone already present that matches a description. */ static inline void pmix_hotel_knock(pmix_hotel_t *hotel, int room_num, void **occupant) { pmix_hotel_room_t *room; /* Bozo check */ assert(room_num < hotel->num_rooms); *occupant = NULL; if (0 > room_num) { /* occupant wasn't checked in */ return; } /* If there's an occupant in the room, have them come to the door */ room = &(hotel->rooms[room_num]); if (PMIX_LIKELY(NULL != room->occupant)) { pmix_output(10, "occupant %p in room num %d responded to knock", room->occupant, room_num); *occupant = room->occupant; } } END_C_DECLS #endif /* PMIX_HOTEL_H */ pmix-6.1.1~rc2/src/class/pmix_value_array.h0000664000175000017500000002226715203536752021122 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_VALUE_ARRAY_H #define PMIX_VALUE_ARRAY_H #include "src/include/pmix_config.h" #include #ifdef HAVE_STRINGS_H # include #endif /* HAVE_STRINGS_H */ #include "src/class/pmix_object.h" #if PMIX_ENABLE_DEBUG # include "src/util/pmix_output.h" #endif #include "pmix_common.h" BEGIN_C_DECLS /* * @file Array of elements maintained by value. */ struct pmix_value_array_t { pmix_object_t super; unsigned char *array_items; size_t array_item_sizeof; size_t array_size; size_t array_alloc_size; }; typedef struct pmix_value_array_t pmix_value_array_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_value_array_t); #define PMIX_VALUE_ARRAY_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \ .array_items = NULL, \ .array_item_sizeof = 0, \ .array_size = 0, \ .array_alloc_size = 0 \ } /** * Initialize the array to hold items by value. This routine must * be called prior to using the array. * * @param array The array to initialize (IN). * @param item_size The sizeof each array element (IN). * @return PMIX error code * * Note that there is no corresponding "finalize" function -- use * OBJ_DESTRUCT (for stack arrays) or OBJ_RELEASE (for heap arrays) to * delete it. */ static inline int pmix_value_array_init(pmix_value_array_t *array, size_t item_sizeof) { array->array_item_sizeof = item_sizeof; array->array_alloc_size = 1; array->array_size = 0; array->array_items = (unsigned char *) realloc(array->array_items, item_sizeof * array->array_alloc_size); return (NULL != array->array_items) ? PMIX_SUCCESS : PMIX_ERR_OUT_OF_RESOURCE; } /** * Reserve space in the array for new elements, but do not change the size. * * @param array The input array (IN). * @param size The anticipated size of the array (IN). * @return PMIX error code. */ static inline int pmix_value_array_reserve(pmix_value_array_t *array, size_t size) { if (size > array->array_alloc_size) { array->array_items = (unsigned char *) realloc(array->array_items, array->array_item_sizeof * size); if (NULL == array->array_items) { array->array_size = 0; array->array_alloc_size = 0; return PMIX_ERR_OUT_OF_RESOURCE; } array->array_alloc_size = size; } return PMIX_SUCCESS; } /** * Retrieves the number of elements in the array. * * @param array The input array (IN). * @return The number of elements currently in use. */ static inline size_t pmix_value_array_get_size(pmix_value_array_t *array) { return array->array_size; } /** * Set the number of elements in the array. * * @param array The input array (IN). * @param size The new array size. * * @return PMIX error code. * * Note that resizing the array to a smaller size may not change * the underlying memory allocated by the array. However, setting * the size larger than the current allocation will grow it. In either * case, if the routine is successful, pmix_value_array_get_size() will * return the new size. */ PMIX_EXPORT int pmix_value_array_set_size(pmix_value_array_t *array, size_t size); /** * Macro to retrieve an item from the array by value. * * @param array The input array (IN). * @param item_type The C datatype of the array item (IN). * @param item_index The array index (IN). * * @returns item The requested item. * * Note that this does not change the size of the array - this macro is * strictly for performance - the user assumes the responsibility of * ensuring the array index is valid (0 <= item index < array size). */ #define PMIX_VALUE_ARRAY_GET_ITEM(array, item_type, item_index) \ ((item_type *) ((array)->array_items))[item_index] /** * Retrieve an item from the array by reference. * * @param array The input array (IN). * @param item_index The array index (IN). * * @return ptr Pointer to the requested item. * * Note that if the specified item_index is larger than the current * array size, the array is grown to satisfy the request. */ static inline void *pmix_value_array_get_item(pmix_value_array_t *array, size_t item_index) { if (item_index >= array->array_size && pmix_value_array_set_size(array, item_index + 1) != PMIX_SUCCESS) return NULL; return array->array_items + (item_index * array->array_item_sizeof); } /** * Macro to set an array element by value. * * @param array The input array (IN). * @param item_type The C datatype of the array item (IN). * @param item_index The array index (IN). * @param item_value The new value for the specified index (IN). * * Note that this does not change the size of the array - this macro is * strictly for performance - the user assumes the responsibility of * ensuring the array index is valid (0 <= item index < array size). * * It is safe to free the item after returning from this call; it is * copied into the array by value. */ #define PMIX_VALUE_ARRAY_SET_ITEM(array, item_type, item_index, item_value) \ (((item_type *) ((array)->array_items))[item_index] = item_value) /** * Set an array element by value. * * @param array The input array (IN). * @param item_index The array index (IN). * @param item_value A pointer to the item, which is copied into * the array. * * @return PMIX error code. * * It is safe to free the item after returning from this call; it is * copied into the array by value. */ static inline int pmix_value_array_set_item(pmix_value_array_t *array, size_t item_index, const void *item) { int rc; if (item_index >= array->array_size && (rc = pmix_value_array_set_size(array, item_index + 1)) != PMIX_SUCCESS) return rc; memcpy(array->array_items + (item_index * array->array_item_sizeof), item, array->array_item_sizeof); return PMIX_SUCCESS; } /** * Appends an item to the end of the array. * * @param array The input array (IN). * @param item A pointer to the item to append, which is copied * into the array. * * @return PMIX error code * * This will grow the array if it is not large enough to contain the * item. It is safe to free the item after returning from this call; * it is copied by value into the array. */ static inline int pmix_value_array_append_item(pmix_value_array_t *array, const void *item) { return pmix_value_array_set_item(array, array->array_size, item); } /** * Remove a specific item from the array. * * @param array The input array (IN). * @param item_index The index to remove, which must be less than * the current array size (IN). * * @return PMIX error code. * * All elements following this index are shifted down. */ static inline int pmix_value_array_remove_item(pmix_value_array_t *array, size_t item_index) { #if PMIX_ENABLE_DEBUG if (item_index >= array->array_size) { pmix_output(0, "pmix_value_array_remove_item: invalid index %lu\n", (unsigned long) item_index); return PMIX_ERR_BAD_PARAM; } #endif memmove(array->array_items + (array->array_item_sizeof * item_index), array->array_items + (array->array_item_sizeof * (item_index + 1)), array->array_item_sizeof * (array->array_size - item_index - 1)); array->array_size--; return PMIX_SUCCESS; } /** * Get the base pointer of the underlying array. * * @param array The input array (IN). * @param array_type The C datatype of the array (IN). * * @returns ptr Pointer to the actual array. * * This function is helpful when you need to iterate through an * entire array; simply get the base value of the array and use native * C to iterate through it manually. This can have better performance * than looping over PMIX_VALUE_ARRAY_GET_ITEM() and * PMIX_VALUE_ARRAY_SET_ITEM() because it will [potentially] reduce the * number of pointer dereferences. */ #define PMIX_VALUE_ARRAY_GET_BASE(array, item_type) ((item_type *) ((array)->array_items)) END_C_DECLS #endif pmix-6.1.1~rc2/src/class/pmix_object.c0000664000175000017500000001342315203536752020043 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2007 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * Implementation of pmix_object_t, the base pmix foundation class */ #include "src/include/pmix_config.h" /* Symbol transforms */ #include #include #include "src/class/pmix_object.h" /* * Instantiation of class descriptor for the base class. This is * special, since be mark it as already initialized, with no parent * and no constructor or destructor. */ PMIX_EXPORT pmix_class_t pmix_object_t_class = { "pmix_object_t", /* name */ NULL, /* parent class */ NULL, /* constructor */ NULL, /* destructor */ 1, /* initialized -- this class is preinitialized */ 0, /* class hierarchy depth */ NULL, /* array of constructors */ NULL, /* array of destructors */ sizeof(pmix_object_t) /* size of the pmix object */ }; int pmix_class_init_epoch = 1; /* * Local variables */ static pthread_mutex_t class_mutex = PTHREAD_MUTEX_INITIALIZER; static void **classes = NULL; static int num_classes = 0; static int max_classes = 0; static const int increment = 10; /* * Local functions */ static void save_class(pmix_class_t *cls); static void expand_array(void); /* * Lazy initialization of class descriptor. */ void pmix_class_initialize(pmix_class_t *cls) { pmix_class_t *c; pmix_construct_t *cls_construct_array; pmix_destruct_t *cls_destruct_array; int cls_construct_array_count; int cls_destruct_array_count; int i; assert(cls); pthread_mutex_lock(&class_mutex); /* If another thread initializing this same class came in at roughly the same time, it may have gotten the lock and initialized. So check again. */ if (pmix_class_init_epoch == cls->cls_initialized) { pthread_mutex_unlock(&class_mutex); return; } /* * First calculate depth of class hierarchy * And the number of constructors and destructors */ cls->cls_depth = 0; cls_construct_array_count = 0; cls_destruct_array_count = 0; for (c = cls; c; c = c->cls_parent) { if (NULL != c->cls_construct) { cls_construct_array_count++; } if (NULL != c->cls_destruct) { cls_destruct_array_count++; } cls->cls_depth++; } /* * Allocate arrays for hierarchy of constructors and destructors * plus for each a NULL-sentinel */ cls->cls_construct_array = (void (**)(pmix_object_t *)) malloc( (cls_construct_array_count + cls_destruct_array_count + 2) * sizeof(pmix_construct_t)); if (NULL == cls->cls_construct_array) { perror("Out of memory"); exit(-1); } cls->cls_destruct_array = cls->cls_construct_array + cls_construct_array_count + 1; /* * The constructor array is reversed, so start at the end */ cls_construct_array = cls->cls_construct_array + cls_construct_array_count; cls_destruct_array = cls->cls_destruct_array; c = cls; *cls_construct_array = NULL; /* end marker for the constructors */ for (i = 0; i < cls->cls_depth; i++) { if (NULL != c->cls_construct) { --cls_construct_array; *cls_construct_array = c->cls_construct; } if (NULL != c->cls_destruct) { *cls_destruct_array = c->cls_destruct; cls_destruct_array++; } c = c->cls_parent; } *cls_destruct_array = NULL; /* end marker for the destructors */ cls->cls_initialized = pmix_class_init_epoch; save_class(cls); /* All done */ pthread_mutex_unlock(&class_mutex); } /* * Note that this is finalize for *all* classes. */ int pmix_class_finalize(void) { int i; if (INT_MAX == pmix_class_init_epoch) { pmix_class_init_epoch = 1; } else { pmix_class_init_epoch++; } if (NULL != classes) { for (i = 0; i < num_classes; ++i) { if (NULL != classes[i]) { free(classes[i]); } } free(classes); classes = NULL; num_classes = 0; max_classes = 0; } return 0; } static void save_class(pmix_class_t *cls) { if (num_classes >= max_classes) { expand_array(); } classes[num_classes] = cls->cls_construct_array; ++num_classes; } static void expand_array(void) { int i; max_classes += increment; if (NULL == classes) { classes = (void **) calloc(max_classes, sizeof(void *)); } else { classes = (void **) realloc(classes, sizeof(void *) * max_classes); } if (NULL == classes) { perror("class malloc failed"); exit(-1); } for (i = num_classes; i < max_classes; ++i) { classes[i] = NULL; } } pmix-6.1.1~rc2/src/class/pmix_pointer_array.c0000664000175000017500000003700415203536752021454 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2017 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2017-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "pmix_config.h" #include "pmix_common.h" #include #include #include #include "src/class/pmix_pointer_array.h" #include "src/util/pmix_output.h" static void pmix_pointer_array_construct(pmix_pointer_array_t *); static void pmix_pointer_array_destruct(pmix_pointer_array_t *); static bool grow_table(pmix_pointer_array_t *table, int at_least); PMIX_CLASS_INSTANCE(pmix_pointer_array_t, pmix_object_t, pmix_pointer_array_construct, pmix_pointer_array_destruct); /* * pmix_pointer_array constructor */ static void pmix_pointer_array_construct(pmix_pointer_array_t *array) { array->lowest_free = 0; array->number_free = 0; array->size = 0; array->max_size = INT_MAX; array->block_size = 8; array->free_bits = NULL; array->addr = NULL; } /* * pmix_pointer_array destructor */ static void pmix_pointer_array_destruct(pmix_pointer_array_t *array) { pmix_tma_t *const tma = pmix_obj_get_tma(&array->super); /* free table */ if (NULL != array->free_bits) { pmix_tma_free(tma, array->free_bits); array->free_bits = NULL; } if (NULL != array->addr) { pmix_tma_free(tma, array->addr); array->addr = NULL; } array->size = 0; } #define TYPE_ELEM_COUNT(TYPE, CAP) (((CAP) + 8 * sizeof(TYPE) - 1) / (8 * sizeof(TYPE))) /** * Translate an index position into the free bits array into 2 values, the * index of the element and the index of the bit position. */ #define GET_BIT_POS(IDX, BIDX, PIDX) \ do { \ uint32_t __idx = (uint32_t)(IDX); \ (BIDX) = (__idx / (8 * sizeof(uint64_t))); \ (PIDX) = (__idx % (8 * sizeof(uint64_t))); \ } while (0) /** * A classical find first zero bit (ffs) on a large array. It checks starting * from the indicated position until it finds a zero bit. If SET is true, * the bit is set. The position of the bit is returned in store. * * According to Section 6.4.4.1 of the C standard we don't need to prepend a type * indicator to constants (the type is inferred by the compiler according to * the number of bits necessary to represent it). */ #define FIND_FIRST_ZERO(START_IDX, STORE) \ do { \ uint32_t __b_idx, __b_pos; \ if (0 == table->number_free) { \ (STORE) = table->size; \ break; \ } \ GET_BIT_POS((START_IDX), __b_idx, __b_pos); \ for (; table->free_bits[__b_idx] == 0xFFFFFFFFFFFFFFFFu; __b_idx++) \ ; \ assert(__b_idx < (uint32_t) table->size); \ uint64_t __check_value = table->free_bits[__b_idx]; \ __b_pos = 0; \ \ if (0x00000000FFFFFFFFu == (__check_value & 0x00000000FFFFFFFFu)) { \ __check_value >>= 32; \ __b_pos += 32; \ } \ if (0x000000000000FFFFu == (__check_value & 0x000000000000FFFFu)) { \ __check_value >>= 16; \ __b_pos += 16; \ } \ if (0x00000000000000FFu == (__check_value & 0x00000000000000FFu)) { \ __check_value >>= 8; \ __b_pos += 8; \ } \ if (0x000000000000000Fu == (__check_value & 0x000000000000000Fu)) { \ __check_value >>= 4; \ __b_pos += 4; \ } \ if (0x0000000000000003u == (__check_value & 0x0000000000000003u)) { \ __check_value >>= 2; \ __b_pos += 2; \ } \ if (0x0000000000000001u == (__check_value & 0x0000000000000001u)) { \ __b_pos += 1; \ } \ (STORE) = (__b_idx * 8 * sizeof(uint64_t)) + __b_pos; \ } while (0) /** * Set the IDX bit in the free_bits array. The bit should be previously unset. */ #define SET_BIT(IDX) \ do { \ uint32_t __b_idx, __b_pos; \ GET_BIT_POS((IDX), __b_idx, __b_pos); \ assert(0 == (table->free_bits[__b_idx] & (((uint64_t) 1) << __b_pos))); \ table->free_bits[__b_idx] |= (((uint64_t) 1) << __b_pos); \ } while (0) /** * Unset the IDX bit in the free_bits array. The bit should be previously set. */ #define UNSET_BIT(IDX) \ do { \ uint32_t __b_idx, __b_pos; \ GET_BIT_POS((IDX), __b_idx, __b_pos); \ assert((table->free_bits[__b_idx] & (((uint64_t) 1) << __b_pos))); \ table->free_bits[__b_idx] ^= (((uint64_t) 1) << __b_pos); \ } while (0) #if 0 /** * Validate the pointer array by making sure that the elements and * the free bits array are in sync. It also check that the number * of remaining free element is consistent. */ static void pmix_pointer_array_validate(pmix_pointer_array_t *array) { int i, cnt = 0; uint32_t b_idx, p_idx; for( i = 0; i < array->size; i++ ) { GET_BIT_POS(i, b_idx, p_idx); if( NULL == array->addr[i] ) { cnt++; assert( 0 == (array->free_bits[b_idx] & (((uint64_t)1) << p_idx)) ); } else { assert( 0 != (array->free_bits[b_idx] & (((uint64_t)1) << p_idx)) ); } } assert(cnt == array->number_free); } #endif /** * initialize an array object */ int pmix_pointer_array_init(pmix_pointer_array_t *array, int initial_allocation, int max_size, int block_size) { size_t num_bytes; /* check for errors */ if (NULL == array || max_size < block_size) { return PMIX_ERR_BAD_PARAM; } pmix_tma_t *const tma = pmix_obj_get_tma(&array->super); array->max_size = max_size; array->block_size = (0 == block_size ? 8 : block_size); array->lowest_free = 0; num_bytes = (0 < initial_allocation ? initial_allocation : block_size); /* Allocate and set the array to NULL */ array->addr = (void **) pmix_tma_calloc(tma, num_bytes, sizeof(void *)); if (NULL == array->addr) { /* out of memory */ return PMIX_ERR_OUT_OF_RESOURCE; } array->free_bits = (uint64_t *) pmix_tma_calloc(tma, TYPE_ELEM_COUNT(uint64_t, num_bytes), sizeof(uint64_t)); if (NULL == array->free_bits) { /* out of memory */ pmix_tma_free(tma, array->addr); array->addr = NULL; return PMIX_ERR_OUT_OF_RESOURCE; } array->number_free = num_bytes; array->size = num_bytes; return PMIX_SUCCESS; } /** * add a pointer to dynamic pointer table * * @param table Pointer to pmix_pointer_array_t object (IN) * @param ptr Pointer to be added to table (IN) * * @return Array index where ptr is inserted or PMIX_ERROR if it fails */ int pmix_pointer_array_add(pmix_pointer_array_t *table, void *ptr) { int index = table->size + 1; if (table->number_free == 0) { /* need to grow table */ if (!grow_table(table, index)) { return PMIX_ERR_OUT_OF_RESOURCE; } } assert((table->addr != NULL) && (table->size > 0)); assert((table->lowest_free >= 0) && (table->lowest_free < table->size)); assert((table->number_free > 0) && (table->number_free <= table->size)); /* * add pointer to table, and return the index */ index = table->lowest_free; assert(NULL == table->addr[index]); table->addr[index] = ptr; table->number_free--; SET_BIT(index); if (table->number_free > 0) { FIND_FIRST_ZERO(index, table->lowest_free); } else { table->lowest_free = table->size; } #if 0 pmix_pointer_array_validate(table); #endif return index; } /** * Set the value of the dynamic array at a specified location. * * * @param table Pointer to pmix_pointer_array_t object (IN) * @param ptr Pointer to be added to table (IN) * * @return Error code * * Assumption: NULL element is free element. */ int pmix_pointer_array_set_item(pmix_pointer_array_t *table, int index, void *value) { assert(table != NULL); if (PMIX_UNLIKELY(0 > index)) { return PMIX_ERROR; } /* expand table if required to set a specific index */ if (table->size <= index) { if (!grow_table(table, index)) { return PMIX_ERROR; } } assert(table->size > index); /* mark element as free, if NULL element */ if (NULL == value) { if (NULL != table->addr[index]) { if (index < table->lowest_free) { table->lowest_free = index; } table->number_free++; UNSET_BIT(index); } } else { if (NULL == table->addr[index]) { table->number_free--; SET_BIT(index); /* Reset lowest_free if required */ if (index == table->lowest_free) { FIND_FIRST_ZERO(index, table->lowest_free); } } else { assert(index != table->lowest_free); } } table->addr[index] = value; #if 0 pmix_pointer_array_validate(table); pmix_output(0,"pmix_pointer_array_set_item: OUT: " " table %p (size %ld, lowest free %ld, number free %ld)" " addr[%d] = %p\n", table, table->size, table->lowest_free, table->number_free, index, table->addr[index]); #endif return PMIX_SUCCESS; } /** * Test whether a certain element is already in use. If not yet * in use, reserve it. * * @param array Pointer to array (IN) * @param index Index of element to be tested (IN) * @param value New value to be set at element index (IN) * * @return true/false True if element could be reserved * False if element could not be reserved (e.g.in use). * * In contrary to array_set, this function does not allow to overwrite * a value, unless the previous value is NULL ( equiv. to free ). */ bool pmix_pointer_array_test_and_set_item(pmix_pointer_array_t *table, int index, void *value) { assert(table != NULL); assert(index >= 0); #if 0 pmix_output(0,"pmix_pointer_array_test_and_set_item: IN: " " table %p (size %ld, lowest free %ld, number free %ld)" " addr[%d] = %p\n", table, table->size, table->lowest_free, table->number_free, index, table->addr[index]); #endif /* expand table if required to set a specific index */ if (index < table->size && table->addr[index] != NULL) { /* This element is already in use */ return false; } /* Do we need to grow the table? */ if (table->size <= index) { if (!grow_table(table, index)) { return false; } } /* * allow a specific index to be changed. */ assert(NULL == table->addr[index]); table->addr[index] = value; table->number_free--; SET_BIT(index); /* Reset lowest_free if required */ if (table->number_free > 0) { if (index == table->lowest_free) { FIND_FIRST_ZERO(index, table->lowest_free); } } else { table->lowest_free = table->size; } #if 0 pmix_pointer_array_validate(table); pmix_output(0,"pmix_pointer_array_test_and_set_item: OUT: " " table %p (size %ld, lowest free %ld, number free %ld)" " addr[%d] = %p\n", table, table->size, table->lowest_free, table->number_free, index, table->addr[index]); #endif return true; } int pmix_pointer_array_set_size(pmix_pointer_array_t *array, int new_size) { if (new_size > array->size) { if (!grow_table(array, new_size)) { return PMIX_ERROR; } } return PMIX_SUCCESS; } static bool grow_table(pmix_pointer_array_t *table, int at_least) { pmix_tma_t *const tma = pmix_obj_get_tma(&table->super); int i, new_size, new_size_int; void *p; new_size = table->block_size * ((at_least + 1 + table->block_size - 1) / table->block_size); if (new_size >= table->max_size) { new_size = table->max_size; if (at_least >= table->max_size) { return false; } } p = (void **) pmix_tma_realloc(tma, table->addr, new_size * sizeof(void *)); if (NULL == p) { return false; } table->number_free += (new_size - table->size); table->addr = (void **) p; for (i = table->size; i < new_size; ++i) { table->addr[i] = NULL; } new_size_int = TYPE_ELEM_COUNT(uint64_t, new_size); if ((int) (TYPE_ELEM_COUNT(uint64_t, table->size)) != new_size_int) { p = (uint64_t *) pmix_tma_realloc(tma, table->free_bits, new_size_int * sizeof(uint64_t)); if (NULL == p) { return false; } table->free_bits = (uint64_t *) p; for (i = TYPE_ELEM_COUNT(uint64_t, table->size); i < new_size_int; i++) { table->free_bits[i] = 0; } } table->size = new_size; #if 0 pmix_output(0, "grow_table %p to %d (max_size %d, block %d, number_free %d)\n", (void*)table, table->size, table->max_size, table->block_size, table->number_free); #endif return true; } pmix-6.1.1~rc2/src/class/pmix_bitmap.h0000664000175000017500000001754515203536752020067 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2014 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010-2012 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ /** @file * * A bitmap implementation. The bits start off with 0, so this bitmap * has bits numbered as bit 0, bit 1, bit 2 and so on. This bitmap * has auto-expansion capabilities, that is once the size is set * during init, it can be automatically expanded by setting the bit * beyond the current size. But note, this is allowed just when the * bit is set -- so the valid functions are set_bit and * find_and_set_bit. Other functions like clear, if passed a bit * outside the initialized range will result in an error. * * To allow these bitmaps to track fortran handles (which MPI defines * to be Fortran INTEGER), we offer a pmix_bitmap_set_max_size, so that * the upper layer can ask to never have more than * OMPI_FORTRAN_HANDLE_MAX, which is min(INT_MAX, fortran INTEGER max). */ #ifndef PMIX_BITMAP_H #define PMIX_BITMAP_H #include "src/include/pmix_config.h" #include #include "src/class/pmix_object.h" BEGIN_C_DECLS struct pmix_bitmap_t { pmix_object_t super; /**< Subclass of pmix_object_t */ uint64_t *bitmap; /**< The actual bitmap array of characters */ int array_size; /**< The actual array size that maintains the bitmap */ int max_size; /**< The maximum size that this bitmap may grow (optional) */ }; typedef struct pmix_bitmap_t pmix_bitmap_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_bitmap_t); /** * Set the maximum size of the bitmap. * May be reset any time, but HAS TO BE SET BEFORE pmix_bitmap_init! * * @param bitmap The input bitmap (IN) * @param max_size The maximum size of the bitmap in terms of bits (IN) * @return PMIX error code or success * */ PMIX_EXPORT int pmix_bitmap_set_max_size(pmix_bitmap_t *bm, int max_size); /** * Initializes the bitmap and sets its size. This must be called * before the bitmap can be actually used * * @param bitmap The input bitmap (IN) * @param size The initial size of the bitmap in terms of bits (IN) * @return PMIX error code or success * */ PMIX_EXPORT int pmix_bitmap_init(pmix_bitmap_t *bm, int size); /** * Set a bit of the bitmap. If the bit asked for is beyond the current * size of the bitmap, then the bitmap is extended to accommodate the * bit * * @param bitmap The input bitmap (IN) * @param bit The bit which is to be set (IN) * @return PMIX error code or success * */ PMIX_EXPORT int pmix_bitmap_set_bit(pmix_bitmap_t *bm, int bit); /** * Clear/unset a bit of the bitmap. If the bit is beyond the current * size of the bitmap, an error is returned * * @param bitmap The input bitmap (IN) * @param bit The bit which is to be cleared (IN) * @return PMIX error code if the bit is out of range, else success * */ PMIX_EXPORT int pmix_bitmap_clear_bit(pmix_bitmap_t *bm, int bit); /** * Find out if a bit is set in the bitmap * * @param bitmap The input bitmap (IN) * @param bit The bit which is to be checked (IN) * @return true if the bit is set * false if the bit is not set OR the index * is outside the bounds of the provided * bitmap * */ PMIX_EXPORT bool pmix_bitmap_is_set_bit(pmix_bitmap_t *bm, int bit); /** * Find the first clear bit in the bitmap and set it * * @param bitmap The input bitmap (IN) * @param position Position of the first clear bit (OUT) * @return err PMIX_SUCCESS on success */ PMIX_EXPORT int pmix_bitmap_find_and_set_first_unset_bit(pmix_bitmap_t *bm, int *position); /** * Clear all bits in the bitmap * * @param bitmap The input bitmap (IN) * @return PMIX error code if bm is NULL * */ PMIX_EXPORT int pmix_bitmap_clear_all_bits(pmix_bitmap_t *bm); /** * Set all bits in the bitmap * @param bitmap The input bitmap (IN) * @return PMIX error code if bm is NULL * */ PMIX_EXPORT int pmix_bitmap_set_all_bits(pmix_bitmap_t *bm); /** * Gives the current size (number of bits) in the bitmap. This is the * legal (accessible) number of bits * * @param bitmap The input bitmap (IN) * @return PMIX error code if bm is NULL * */ static inline int pmix_bitmap_size(pmix_bitmap_t *bm) { return (NULL == bm) ? 0 : (bm->array_size * ((int) (sizeof(*bm->bitmap) * 8))); } /** * Copy a bitmap * * @param dest Pointer to the destination bitmap * @param src Pointer to the source bitmap * @ return PMIX error code if something goes wrong */ static inline void pmix_bitmap_copy(pmix_bitmap_t *dest, pmix_bitmap_t *src) { if (dest->array_size < src->array_size) { if (NULL != dest->bitmap) free(dest->bitmap); dest->max_size = src->max_size; dest->bitmap = (uint64_t *) malloc(src->array_size * sizeof(uint64_t)); } memcpy(dest->bitmap, src->bitmap, src->array_size * sizeof(uint64_t)); dest->array_size = src->array_size; } /** * Bitwise AND operator (inplace) * * @param dest Pointer to the bitmap that should be modified * @param right Point to the other bitmap in the operation * @return PMIX error code if the length of the two bitmaps is not equal or one is NULL. */ PMIX_EXPORT int pmix_bitmap_bitwise_and_inplace(pmix_bitmap_t *dest, pmix_bitmap_t *right); /** * Bitwise OR operator (inplace) * * @param dest Pointer to the bitmap that should be modified * @param right Point to the other bitmap in the operation * @return PMIX error code if the length of the two bitmaps is not equal or one is NULL. */ PMIX_EXPORT int pmix_bitmap_bitwise_or_inplace(pmix_bitmap_t *dest, pmix_bitmap_t *right); /** * Bitwise XOR operator (inplace) * * @param dest Pointer to the bitmap that should be modified * @param right Point to the other bitmap in the operation * @return PMIX error code if the length of the two bitmaps is not equal or one is NULL. */ PMIX_EXPORT int pmix_bitmap_bitwise_xor_inplace(pmix_bitmap_t *dest, pmix_bitmap_t *right); /** * If the bitmaps are different * * @param left Pointer to a bitmap * @param right Pointer to another bitmap * @return true if different, false if the same */ PMIX_EXPORT bool pmix_bitmap_are_different(pmix_bitmap_t *left, pmix_bitmap_t *right); /** * Get a string representation of the bitmap. * Useful for debugging. * * @param bitmap Point to the bitmap to represent * @return Pointer to the string (caller must free if not NULL) */ PMIX_EXPORT char *pmix_bitmap_get_string(pmix_bitmap_t *bitmap); /** * Return the number of 'unset' bits, up to the specified length * * @param bitmap Pointer to the bitmap * @param len Number of bits to check * @return Integer */ PMIX_EXPORT int pmix_bitmap_num_unset_bits(pmix_bitmap_t *bm, int len); /** * Return the number of 'set' bits, up to the specified length * * @param bitmap Pointer to the bitmap * @param len Number of bits to check * @return Integer */ PMIX_EXPORT int pmix_bitmap_num_set_bits(pmix_bitmap_t *bm, int len); /** * Check a bitmap to see if any bit is set */ PMIX_EXPORT bool pmix_bitmap_is_clear(pmix_bitmap_t *bm); END_C_DECLS #endif pmix-6.1.1~rc2/src/class/pmix_ring_buffer.c0000664000175000017500000000773015203536752021071 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #include "pmix_common.h" #include "src/class/pmix_ring_buffer.h" #include "src/util/pmix_output.h" static void pmix_ring_buffer_construct(pmix_ring_buffer_t *); static void pmix_ring_buffer_destruct(pmix_ring_buffer_t *); PMIX_CLASS_INSTANCE(pmix_ring_buffer_t, pmix_object_t, pmix_ring_buffer_construct, pmix_ring_buffer_destruct); /* * pmix_ring_buffer constructor */ static void pmix_ring_buffer_construct(pmix_ring_buffer_t *ring) { ring->head = 0; ring->tail = -1; ring->size = 0; ring->addr = NULL; } /* * pmix_ring_buffer destructor */ static void pmix_ring_buffer_destruct(pmix_ring_buffer_t *ring) { if (NULL != ring->addr) { free(ring->addr); ring->addr = NULL; } ring->size = 0; } /** * initialize a ring object */ int pmix_ring_buffer_init(pmix_ring_buffer_t *ring, int size) { /* check for errors */ if (NULL == ring) { return PMIX_ERR_BAD_PARAM; } /* Allocate and set the ring to NULL */ ring->addr = (char **) calloc(size * sizeof(char *), 1); if (NULL == ring->addr) { /* out of memory */ return PMIX_ERR_OUT_OF_RESOURCE; } ring->size = size; return PMIX_SUCCESS; } void *pmix_ring_buffer_push(pmix_ring_buffer_t *ring, void *ptr) { char *p = NULL; if (NULL != ring->addr[ring->head]) { p = (char *) ring->addr[ring->head]; if (ring->tail == ring->size - 1) { ring->tail = 0; } else { ring->tail = ring->head + 1; } } ring->addr[ring->head] = (char *) ptr; if (ring->tail < 0) { ring->tail = ring->head; } if (ring->head == ring->size - 1) { ring->head = 0; } else { ring->head++; } return (void *) p; } void *pmix_ring_buffer_pop(pmix_ring_buffer_t *ring) { char *p = NULL; if (-1 == ring->tail) { /* nothing has been put on the ring yet */ p = NULL; } else { p = (char *) ring->addr[ring->tail]; ring->addr[ring->tail] = NULL; if (ring->tail == ring->size - 1) { ring->tail = 0; } else { ring->tail++; } /* see if the ring is empty */ if (ring->tail == ring->head) { ring->tail = -1; } } return (void *) p; } void *pmix_ring_buffer_poke(pmix_ring_buffer_t *ring, int i) { char *p = NULL; int offset; if (ring->size <= i || -1 == ring->tail) { p = NULL; } else if (i < 0) { /* return the value at the head of the ring */ if (ring->head == 0) { p = ring->addr[ring->size - 1]; } else { p = ring->addr[ring->head - 1]; } } else { /* calculate the offset of the tail in the ring */ offset = ring->tail + i; /* correct for wrap-around */ if (ring->size <= offset) { offset -= ring->size; } p = ring->addr[offset]; } return (void *) p; } pmix-6.1.1~rc2/src/class/pmix_list.h0000664000175000017500000007502215203536752017560 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Voltaire All rights reserved. * Copyright (c) 2013 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * * The pmix_list_t interface is used to provide a generic * doubly-linked list container for PMIx. It was inspired by (but * is slightly different than) the Standard Template Library (STL) * std::list class. One notable difference from std::list is that * when an pmix_list_t is destroyed, all of the pmix_list_item_t * objects that it contains are orphaned -- they are \em not * destroyed. * * The general idea is that pmix_list_item_t objects can be put on an * pmix_list_t. Hence, you create a new type that derives from * pmix_list_item_t; this new type can then be used with pmix_list_t * containers. * * NOTE: pmix_list_item_t instances can only be on \em one list at a * time. Specifically, if you add an pmix_list_item_t to one list, * and then add it to another list (without first removing it from the * first list), you will effectively be hosing the first list. You * have been warned. * * If PMIX_ENABLE_DEBUG is true, a bunch of checks occur, including * some spot checks for a debugging reference count in an attempt to * ensure that an pmix_list_item_t is only one *one* list at a time. * Given the highly concurrent nature of this class, these spot checks * cannot guarantee that an item is only one list at a time. * Specifically, since it is a desirable attribute of this class to * not use locks for normal operations, it is possible that two * threads may [erroneously] modify an pmix_list_item_t concurrently. * * The only way to guarantee that a debugging reference count is valid * for the duration of an operation is to lock the item_t during the * operation. But this fundamentally changes the desirable attribute * of this class (i.e., no locks). So all we can do is spot-check the * reference count in a bunch of places and check that it is still the * value that we think it should be. But this doesn't mean that you * can run into "unlucky" cases where two threads are concurrently * modifying an item_t, but all the spot checks still return the * "right" values. All we can do is hope that we have enough spot * checks to statistically drive down the possibility of the unlucky * cases happening. */ #ifndef PMIX_LIST_H #define PMIX_LIST_H #include "src/include/pmix_config.h" #include #include #if HAVE_STDBOOL_H # include #endif #include "pmix_common.h" #include "src/class/pmix_object.h" BEGIN_C_DECLS /** * \internal * * The class for the list container. */ PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_list_t); /** * \internal * * Base class for items that are put in list (pmix_list_t) containers. */ PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_list_item_t); /** * \internal * * Struct of an pmix_list_item_t */ struct pmix_list_item_t { pmix_object_t super; /**< Generic parent class for all PMIx objects */ volatile struct pmix_list_item_t *pmix_list_next; /**< Pointer to next list item */ volatile struct pmix_list_item_t *pmix_list_prev; /**< Pointer to previous list item */ int32_t item_free; #if PMIX_ENABLE_DEBUG /** Atomic reference count for debugging */ int32_t pmix_list_item_refcount; /** The list this item belong to */ volatile struct pmix_list_t *pmix_list_item_belong_to; #endif }; /** * Base type for items that are put in a list (pmix_list_t) containers. */ typedef struct pmix_list_item_t pmix_list_item_t; /* static initializer for pmix_list_t */ #define PMIX_LIST_ITEM_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \ .pmix_list_next = NULL, \ .pmix_list_prev = NULL, \ .item_free = 0 \ } /** * Get the next item in a list. * * @param item A list item. * * @returns The next item in the list */ #define pmix_list_get_next(item) \ ((item) ? ((pmix_list_item_t *) ((pmix_list_item_t *) (item))->pmix_list_next) : NULL) /** * Get the next item in a list. * * @param item A list item. * * @returns The next item in the list */ #define pmix_list_get_prev(item) \ ((item) ? ((pmix_list_item_t *) ((pmix_list_item_t *) (item))->pmix_list_prev) : NULL) /** * \internal * * Struct of an pmix_list_t */ struct pmix_list_t { pmix_object_t super; /**< Generic parent class for all PMIx objects */ pmix_list_item_t pmix_list_sentinel; /**< Head and tail item of the list */ volatile size_t pmix_list_length; /**< Quick reference to the number of items in the list */ }; /** * List container type. */ typedef struct pmix_list_t pmix_list_t; /* static initializer for pmix_list_t */ #define PMIX_LIST_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \ .pmix_list_sentinel = PMIX_LIST_ITEM_STATIC_INIT, \ .pmix_list_length = 0 \ } /** Cleanly destruct a list * * The pmix_list_t destructor doesn't release the items on the * list - so provide two convenience macros that do so and then * destruct/release the list object itself * * @param[in] list List to destruct or release */ #define PMIX_LIST_DESTRUCT(list) \ do { \ pmix_list_item_t *it; \ while (NULL != (it = pmix_list_remove_first(list))) { \ PMIX_RELEASE(it); \ } \ PMIX_DESTRUCT(list); \ } while (0) #define PMIX_LIST_RELEASE(list) \ do { \ pmix_list_item_t *it; \ while (NULL != (it = pmix_list_remove_first(list))) { \ PMIX_RELEASE(it); \ } \ PMIX_RELEASE(list); \ } while (0) /** * Loop over a list. * * @param[in] item Storage for each item * @param[in] list List to iterate over * @param[in] type Type of each list item * * This macro provides a simple way to loop over the items in an pmix_list_t. It * is not safe to call pmix_list_remove_item from within the loop. * * Example Usage: * * class_foo_t *foo; * pmix_list_foreach(foo, list, class_foo_t) { * do something; * } */ #define PMIX_LIST_FOREACH(item, list, type) \ for (item = (type *) (list)->pmix_list_sentinel.pmix_list_next; \ item != (type *) &(list)->pmix_list_sentinel; \ item = (type *) ((pmix_list_item_t *) (item))->pmix_list_next) #define PMIX_LIST_FOREACH_DECL(item, list, type) \ for (type *item = (type *) (list)->pmix_list_sentinel.pmix_list_next; \ item != (type *) &(list)->pmix_list_sentinel; \ item = (type *) ((pmix_list_item_t *) (item))->pmix_list_next) /** * Loop over a list in reverse. * * @param[in] item Storage for each item * @param[in] list List to iterate over * @param[in] type Type of each list item * * This macro provides a simple way to loop over the items in an pmix_list_t. It * is not safe to call pmix_list_remove_item from within the loop. * * Example Usage: * * class_foo_t *foo; * pmix_list_foreach(foo, list, class_foo_t) { * do something; * } */ #define PMIX_LIST_FOREACH_REV(item, list, type) \ for (item = (type *) (list)->pmix_list_sentinel.pmix_list_prev; \ item != (type *) &(list)->pmix_list_sentinel; \ item = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev) /** * Loop over a list in a *safe* way * * @param[in] item Storage for each item * @param[in] next Storage for next item * @param[in] list List to iterate over * @param[in] type Type of each list item * * This macro provides a simple way to loop over the items in an pmix_list_t. It * is safe to call pmix_list_remove_item(list, item) from within the loop. * * Example Usage: * * class_foo_t *foo, *next; * pmix_list_foreach_safe(foo, next, list, class_foo_t) { * do something; * pmix_list_remove_item (list, (pmix_list_item_t *) foo); * } */ #define PMIX_LIST_FOREACH_SAFE(item, next, list, type) \ for (item = (type *) (list)->pmix_list_sentinel.pmix_list_next, \ next = (type *) ((pmix_list_item_t *) (item))->pmix_list_next; \ item != (type *) &(list)->pmix_list_sentinel; \ item = next, next = (type *) ((pmix_list_item_t *) (item))->pmix_list_next) /** * Loop over a list in a *safe* way * * @param[in] item Storage for each item * @param[in] next Storage for next item * @param[in] list List to iterate over * @param[in] type Type of each list item * * This macro provides a simple way to loop over the items in an pmix_list_t. If * is safe to call pmix_list_remove_item(list, item) from within the loop. * * Example Usage: * * class_foo_t *foo, *next; * pmix_list_foreach_safe(foo, next, list, class_foo_t) { * do something; * pmix_list_remove_item (list, (pmix_list_item_t *) foo); * } */ #define PMIX_LIST_FOREACH_SAFE_REV(item, prev, list, type) \ for (item = (type *) (list)->pmix_list_sentinel.pmix_list_prev, \ prev = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev; \ item != (type *) &(list)->pmix_list_sentinel; \ item = prev, prev = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev) /** * Check for empty list * * @param list The list container * * @returns true if list's size is 0, false otherwise * * This is an O(1) operation. * * This is an inlined function in compilers that support inlining, * so it's usually a cheap operation. */ static inline bool pmix_list_is_empty(pmix_list_t *list) { return (list->pmix_list_sentinel.pmix_list_next == &(list->pmix_list_sentinel) ? true : false); } /** * Return the first item on the list (does not remove it). * * @param list The list container * * @returns A pointer to the first item on the list * * This is an O(1) operation to return the first item on the list. It * should be compared against the returned value from * pmix_list_get_end() to ensure that the list is not empty. * * This is an inlined function in compilers that support inlining, so * it's usually a cheap operation. */ static inline pmix_list_item_t *pmix_list_get_first(pmix_list_t *list) { pmix_list_item_t *item = (pmix_list_item_t *) list->pmix_list_sentinel.pmix_list_next; #if PMIX_ENABLE_DEBUG /* Spot check: ensure that the first item is only on one list */ assert(1 == item->pmix_list_item_refcount); assert(list == item->pmix_list_item_belong_to); #endif return item; } /** * Return the last item on the list (does not remove it). * * @param list The list container * * @returns A pointer to the last item on the list * * This is an O(1) operation to return the last item on the list. It * should be compared against the returned value from * pmix_list_get_begin() to ensure that the list is not empty. * * This is an inlined function in compilers that support inlining, so * it's usually a cheap operation. */ static inline pmix_list_item_t *pmix_list_get_last(pmix_list_t *list) { pmix_list_item_t *item = (pmix_list_item_t *) list->pmix_list_sentinel.pmix_list_prev; #if PMIX_ENABLE_DEBUG /* Spot check: ensure that the last item is only on one list */ assert(1 == item->pmix_list_item_refcount); assert(list == item->pmix_list_item_belong_to); #endif return item; } /** * Return the beginning of the list; an invalid list entry suitable * for comparison only. * * @param list The list container * * @returns A pointer to the beginning of the list. * * This is an O(1) operation to return the beginning of the list. * Similar to the STL, this is a special invalid list item -- it * should \em not be used for storage. It is only suitable for * comparison to other items in the list to see if they are valid or * not; it's usually used when iterating through the items in a list. * * This is an inlined function in compilers that support inlining, so * it's usually a cheap operation. */ static inline pmix_list_item_t *pmix_list_get_begin(pmix_list_t *list) { return &(list->pmix_list_sentinel); } /** * Return the end of the list; an invalid list entry suitable for * comparison only. * * @param list The list container * * @returns A pointer to the end of the list. * * This is an O(1) operation to return the end of the list. * Similar to the STL, this is a special invalid list item -- it * should \em not be used for storage. It is only suitable for * comparison to other items in the list to see if they are valid or * not; it's usually used when iterating through the items in a list. * * This is an inlined function in compilers that support inlining, so * it's usually a cheap operation. */ static inline pmix_list_item_t *pmix_list_get_end(pmix_list_t *list) { return &(list->pmix_list_sentinel); } /** * Return the number of items in a list * * @param list The list container * * @returns The size of the list (size_t) * * This is an O(1) lookup to return the size of the list. * * This is an inlined function in compilers that support inlining, so * it's usually a cheap operation. * * \warning The size of the list is cached as part of the list. In * the future, calling \c pmix_list_splice or \c pmix_list_join may * result in this function recomputing the list size, which would be * an O(N) operation. If \c pmix_list_splice or \c pmix_list_join is * never called on the specified list, this function will always be * O(1). */ static inline size_t pmix_list_get_size(pmix_list_t *list) { #if PMIX_ENABLE_DEBUG && 0 /* not sure if we really want this running in devel, as it does * slow things down. Wanted for development of splice / join to * make sure length was reset properly */ size_t check_len = 0; pmix_list_item_t *item; for (item = pmix_list_get_first(list); item != pmix_list_get_end(list); item = pmix_list_get_next(item)) { check_len++; } if (check_len != list->pmix_list_length) { fprintf( stderr, " Error :: pmix_list_get_size - pmix_list_length does not match actual list length\n"); fflush(stderr); abort(); } #endif return list->pmix_list_length; } /** * Remove an item from a list. * * @param list The list container * @param item The item to remove * * @returns A pointer to the item on the list previous to the one * that was removed. * * This is an O(1) operation to remove an item from the list. The * forward / reverse pointers in the list are updated and the item is * removed. The list item that is returned is now "owned" by the * caller -- they are responsible for PMIX_RELEASE()'ing it. * * If debugging is enabled (specifically, if --enable-debug was used * to configure PMIx), this is an O(N) operation because it checks * to see if the item is actually in the list first. * * This is an inlined function in compilers that support inlining, so * it's usually a cheap operation. */ static inline pmix_list_item_t *pmix_list_remove_item(pmix_list_t *list, pmix_list_item_t *item) { #if PMIX_ENABLE_DEBUG pmix_list_item_t *item_ptr; bool found = false; /* check to see that the item is in the list */ for (item_ptr = pmix_list_get_first(list); item_ptr != pmix_list_get_end(list); item_ptr = (pmix_list_item_t *) (item_ptr->pmix_list_next)) { if (item_ptr == (pmix_list_item_t *) item) { found = true; break; } } if (!found) { fprintf(stderr, " Warning :: pmix_list_remove_item - the item %p is not on the list %p \n", (void *) item, (void *) list); fflush(stderr); return (pmix_list_item_t *) NULL; } assert(list == item->pmix_list_item_belong_to); #endif /* reset next pointer of previous element */ item->pmix_list_prev->pmix_list_next = item->pmix_list_next; /* reset previous pointer of next element */ item->pmix_list_next->pmix_list_prev = item->pmix_list_prev; list->pmix_list_length--; #if PMIX_ENABLE_DEBUG /* Spot check: ensure that this item is still only on one list */ item->pmix_list_item_refcount -= 1; assert(0 == item->pmix_list_item_refcount); item->pmix_list_item_belong_to = NULL; #endif return (pmix_list_item_t *) item->pmix_list_prev; } /** * Append an item to the end of the list. * * @param list The list container * @param item The item to append * * This is an O(1) operation to append an item to the end of a list. * The pmix_list_item_t is not PMIX_RETAIN()'ed; it is assumed that * "ownership" of the item is passed from the caller to the list. * * This is an inlined function in compilers that support inlining, so * it's usually a cheap operation. */ #if PMIX_ENABLE_DEBUG # define pmix_list_append(l, i) _pmix_list_append(l, i, __FILE__, __LINE__) #else # define pmix_list_append(l, i) _pmix_list_append(l, i) #endif /* PMIX_ENABLE_DEBUG */ static inline void _pmix_list_append(pmix_list_t *list, pmix_list_item_t *item #if PMIX_ENABLE_DEBUG , const char *FILE_NAME, int LINENO #endif /* PMIX_ENABLE_DEBUG */ ) { pmix_list_item_t *sentinel = &(list->pmix_list_sentinel); #if PMIX_ENABLE_DEBUG /* Spot check: ensure that this item is previously on no lists */ assert(0 == item->pmix_list_item_refcount); assert(NULL == item->pmix_list_item_belong_to); item->super.cls_init_file_name = FILE_NAME; item->super.cls_init_lineno = LINENO; #endif /* set new element's previous pointer */ item->pmix_list_prev = sentinel->pmix_list_prev; /* reset previous pointer on current last element */ sentinel->pmix_list_prev->pmix_list_next = item; /* reset new element's next pointer */ item->pmix_list_next = sentinel; /* reset the list's tail element previous pointer */ sentinel->pmix_list_prev = item; /* increment list element counter */ list->pmix_list_length++; #if PMIX_ENABLE_DEBUG /* Spot check: ensure this item is only on the list that we just appended it to */ item->pmix_list_item_refcount += 1; assert(1 == item->pmix_list_item_refcount); item->pmix_list_item_belong_to = list; #endif } /** * Prepend an item to the beginning of the list. * * @param list The list container * @param item The item to prepend * * This is an O(1) operation to prepend an item to the beginning of a * list. The pmix_list_item_t is not PMIX_RETAIN()'ed; it is assumed * that "ownership" of the item is passed from the caller to the list. * * This is an inlined function in compilers that support inlining, so * it's usually a cheap operation. */ static inline void pmix_list_prepend(pmix_list_t *list, pmix_list_item_t *item) { pmix_list_item_t *sentinel = &(list->pmix_list_sentinel); #if PMIX_ENABLE_DEBUG /* Spot check: ensure that this item is previously on no lists */ assert(0 == item->pmix_list_item_refcount); assert(NULL == item->pmix_list_item_belong_to); #endif /* reset item's next pointer */ item->pmix_list_next = sentinel->pmix_list_next; /* reset item's previous pointer */ item->pmix_list_prev = sentinel; /* reset previous first element's previous pointer */ sentinel->pmix_list_next->pmix_list_prev = item; /* reset head's next pointer */ sentinel->pmix_list_next = item; /* increment list element counter */ list->pmix_list_length++; #if PMIX_ENABLE_DEBUG /* Spot check: ensure this item is only on the list that we just prepended it to */ item->pmix_list_item_refcount += 1; assert(1 == item->pmix_list_item_refcount); item->pmix_list_item_belong_to = list; #endif } /** * Remove the first item from the list and return it. * * @param list The list container * * @returns The first item on the list. If the list is empty, * NULL will be returned * * This is an O(1) operation to return the first item on the list. If * the list is not empty, a pointer to the first item in the list will * be returned. Ownership of the item is transferred from the list to * the caller; no calls to PMIX_RETAIN() or PMIX_RELEASE() are invoked. * * This is an inlined function in compilers that support inlining, so * it's usually a cheap operation. */ static inline pmix_list_item_t *pmix_list_remove_first(pmix_list_t *list) { /* Removes and returns first item on list. Caller now owns the item and should release the item when caller is done with it. */ volatile pmix_list_item_t *item; if (0 == list->pmix_list_length) { return (pmix_list_item_t *) NULL; } #if PMIX_ENABLE_DEBUG /* Spot check: ensure that the first item is only on this list */ assert(1 == list->pmix_list_sentinel.pmix_list_next->pmix_list_item_refcount); #endif /* reset list length counter */ list->pmix_list_length--; /* get pointer to first element on the list */ item = (pmix_list_item_t*)list->pmix_list_sentinel.pmix_list_next; /* reset previous pointer of next item on the list */ item->pmix_list_next->pmix_list_prev = item->pmix_list_prev; /* reset the head next pointer */ list->pmix_list_sentinel.pmix_list_next = item->pmix_list_next; #if PMIX_ENABLE_DEBUG assert(list == item->pmix_list_item_belong_to); item->pmix_list_item_belong_to = NULL; item->pmix_list_prev = (pmix_list_item_t *) NULL; item->pmix_list_next = (pmix_list_item_t *) NULL; /* Spot check: ensure that the item we're returning is now on no lists */ item->pmix_list_item_refcount -= 1; assert(0 == item->pmix_list_item_refcount); #endif return (pmix_list_item_t *) item; } /** * Remove the last item from the list and return it. * * @param list The list container * * @returns The last item on the list. If the list is empty, * NULL will be returned * * This is an O(1) operation to return the last item on the list. If * the list is not empty, a pointer to the last item in the list will * be returned. Ownership of the item is transferred from the list to * the caller; no calls to PMIX_RETAIN() or PMIX_RELEASE() are invoked. * * This is an inlined function in compilers that support inlining, so * it's usually a cheap operation. */ static inline pmix_list_item_t *pmix_list_remove_last(pmix_list_t *list) { /* Removes, releases and returns last item on list. Caller now owns the item and should release the item when caller is done with it. */ volatile pmix_list_item_t *item; if (0 == list->pmix_list_length) { return (pmix_list_item_t *) NULL; } #if PMIX_ENABLE_DEBUG /* Spot check: ensure that the first item is only on this list */ assert(1 == list->pmix_list_sentinel.pmix_list_prev->pmix_list_item_refcount); #endif /* reset list length counter */ list->pmix_list_length--; /* get item */ item = (pmix_list_item_t*)list->pmix_list_sentinel.pmix_list_prev; /* reset previous pointer on next to last pointer */ item->pmix_list_prev->pmix_list_next = item->pmix_list_next; /* reset tail's previous pointer */ list->pmix_list_sentinel.pmix_list_prev = item->pmix_list_prev; #if PMIX_ENABLE_DEBUG assert(list == item->pmix_list_item_belong_to); item->pmix_list_next = item->pmix_list_prev = (pmix_list_item_t *) NULL; /* Spot check: ensure that the item we're returning is now on no lists */ item->pmix_list_item_refcount -= 1; assert(0 == item->pmix_list_item_refcount); item->pmix_list_item_belong_to = NULL; #endif return (pmix_list_item_t *) item; } /** * Add an item to the list before a given element * * @param list The list container * @param pos List element to insert \c item before * @param item The item to insert * * Inserts \c item before \c pos. This is an O(1) operation. */ static inline void pmix_list_insert_pos(pmix_list_t *list, pmix_list_item_t *pos, pmix_list_item_t *item) { #if PMIX_ENABLE_DEBUG /* Spot check: ensure that the item we're insertting is currently not on any list */ assert(0 == item->pmix_list_item_refcount); assert(NULL == item->pmix_list_item_belong_to); #endif /* point item at the existing elements */ item->pmix_list_next = pos; item->pmix_list_prev = pos->pmix_list_prev; /* splice into the list */ pos->pmix_list_prev->pmix_list_next = item; pos->pmix_list_prev = item; /* reset list length counter */ list->pmix_list_length++; #if PMIX_ENABLE_DEBUG /* Spot check: double check that this item is only on the list that we just added it to */ item->pmix_list_item_refcount += 1; assert(1 == item->pmix_list_item_refcount); item->pmix_list_item_belong_to = list; #endif } /** * Add an item to the list at a specific index location in the list. * * @param list The list container * @param item The item to insert * @param index Location to add the item * * @returns true if insertion succeeded; otherwise false * * This is potentially an O(N) operation to traverse down to the * correct location in the list and add an item. * * Example: if idx = 2 and list = item1->item2->item3->item4, then * after insert, list = item1->item2->item->item3->item4. * * If index is greater than the length of the list, no action is * performed and false is returned. */ PMIX_EXPORT bool pmix_list_insert(pmix_list_t *list, pmix_list_item_t *item, long long idx); /** * Join a list into another list * * @param thislist List container for list being operated on * @param pos List item in \c thislist marking the position before * which items are inserted * @param xlist List container for list being spliced from * * Join a list into another list. All of the elements of \c xlist * are inserted before \c pos and removed from \c xlist. * * This operation is an O(1) operation. Both \c thislist and \c * xlist must be valid list containsers. \c xlist will be empty * but valid after the call. All pointers to \c pmix_list_item_t * containers remain valid, including those that point to elements * in \c xlist. */ PMIX_EXPORT void pmix_list_join(pmix_list_t *thislist, pmix_list_item_t *pos, pmix_list_t *xlist); /** * Splice a list into another list * * @param thislist List container for list being operated on * @param pos List item in \c thislist marking the position before * which items are inserted * @param xlist List container for list being spliced from * @param first List item in \c xlist marking the start of elements * to be copied into \c thislist * @param last List item in \c xlist marking the end of elements * to be copied into \c thislist * * Splice a subset of a list into another list. The \c [first, * last) elements of \c xlist are moved into \c thislist, * inserting them before \c pos. \c pos must be a valid iterator * in \c thislist and \c [first, last) must be a valid range in \c * xlist. \c position must not be in the range \c [first, last). * It is, however, valid for \c xlist and \c thislist to be the * same list. * * This is an O(N) operation because the length of both lists must * be recomputed. */ PMIX_EXPORT void pmix_list_splice(pmix_list_t *thislist, pmix_list_item_t *pos, pmix_list_t *xlist, pmix_list_item_t *first, pmix_list_item_t *last); /** * Comparison function for pmix_list_sort(), below. * * @param a Pointer to a pointer to an pmix_list_item_t. * Explanation below. * @param b Pointer to a pointer to an pmix_list_item_t. * Explanation below. * @retval 1 if \em a is greater than \em b * @retval 0 if \em a is equal to \em b * @retval 11 if \em a is less than \em b * * This function is invoked by qsort(3) from within * pmix_list_sort(). It is important to understand what * pmix_list_sort() does before invoking qsort, so go read that * documentation first. * * The important thing to realize here is that a and b will be \em * double pointers to the items that you need to compare. Here's * a sample compare function to illustrate this point: */ typedef int (*pmix_list_item_compare_fn_t)(pmix_list_item_t **a, pmix_list_item_t **b); /** * Sort a list with a provided compare function. * * @param list The list to sort * @param compare Compare function * * Put crassly, this function's complexity is O(N) + O(log(N)). * Its algorithm is: * * - remove every item from the list and put the corresponding * (pmix_list_item_t*)'s in an array * - call qsort(3) with that array and your compare function * - re-add every element of the now-sorted array to the list * * The resulting list is now ordered. Note, however, that since * an array of pointers is sorted, the comparison function must do * a double de-reference to get to the actual pmix_list_item_t (or * whatever the underlying type is). See the documentation of * pmix_list_item_compare_fn_t for an example). */ PMIX_EXPORT int pmix_list_sort(pmix_list_t *list, pmix_list_item_compare_fn_t compare); END_C_DECLS #endif /* PMIX_LIST_H */ pmix-6.1.1~rc2/src/class/pmix_hash_table.c0000664000175000017500000006723515203536752020701 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2014-2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include "src/class/pmix_hash_table.h" #include "src/class/pmix_list.h" #include "src/util/pmix_output.h" #include "pmix_common.h" /* * pmix_hash_table_t */ #define HASH_MULTIPLIER 31 /* * Define the structs that are opaque in the .h */ struct pmix_hash_element_t { int valid; /* whether this element is valid */ union { /* the key, in its various forms */ uint32_t u32; uint64_t u64; struct { const void *key; size_t key_size; } ptr; } key; pmix_tma_t *tma; /* The heap memory manager used for this element. */ void *value; /* the value */ }; typedef struct pmix_hash_element_t pmix_hash_element_t; struct pmix_hash_type_methods_t { /* Frees any storage associated with the element * The value is not owned by the hash table * The key,key_size of pointer keys is */ void (*elt_destructor)(pmix_hash_element_t *elt); /* Hash the key of the element -- for growing and adjusting-after-removal */ uint64_t (*hash_elt)(pmix_hash_element_t *elt); }; /* interact with the class-like mechanism */ static void pmix_hash_table_construct(pmix_hash_table_t *ht); static void pmix_hash_table_destruct(pmix_hash_table_t *ht); PMIX_CLASS_INSTANCE(pmix_hash_table_t, pmix_object_t, pmix_hash_table_construct, pmix_hash_table_destruct); static void pmix_hash_table_construct(pmix_hash_table_t *ht) { ht->ht_table = NULL; ht->ht_capacity = ht->ht_size = ht->ht_growth_trigger = 0; ht->ht_density_numer = ht->ht_density_denom = 0; ht->ht_growth_numer = ht->ht_growth_denom = 0; ht->ht_type_methods = NULL; } static void pmix_hash_table_destruct(pmix_hash_table_t *ht) { pmix_tma_t *const tma = pmix_obj_get_tma(&ht->super); pmix_hash_table_remove_all(ht); pmix_tma_free(tma, ht->ht_table); } /* * Init, etc */ static size_t pmix_hash_round_capacity_up(size_t capacity) { /* round up to (1 mod 30) */ return ((capacity + 29) / 30 * 30 + 1); } /* this could be the new init if people wanted a more general API */ /* (that's why it isn't static) */ int /* PMIX_ return code */ pmix_hash_table_init2(pmix_hash_table_t *ht, size_t estimated_max_size, int density_numer, int density_denom, int growth_numer, int growth_denom) { pmix_tma_t *const tma = pmix_obj_get_tma(&ht->super); size_t est_capacity = estimated_max_size * density_denom / density_numer; size_t capacity = pmix_hash_round_capacity_up(est_capacity); ht->ht_table = (pmix_hash_element_t *)pmix_tma_calloc(tma, capacity, sizeof(pmix_hash_element_t)); if (PMIX_UNLIKELY(NULL == ht->ht_table)) { return PMIX_ERR_OUT_OF_RESOURCE; } ht->ht_capacity = capacity; ht->ht_density_numer = density_numer; ht->ht_density_denom = density_denom; ht->ht_growth_numer = growth_numer; ht->ht_growth_denom = growth_denom; ht->ht_growth_trigger = capacity * density_numer / density_denom; ht->ht_type_methods = NULL; return PMIX_SUCCESS; } int /* PMIX_ return code */ pmix_hash_table_init(pmix_hash_table_t *ht, size_t table_size) { /* default to density of 1/2 and growth of 2/1 */ return pmix_hash_table_init2(ht, table_size, 1, 2, 2, 1); } int /* PMIX_ return code */ pmix_hash_table_remove_all(pmix_hash_table_t *ht) { size_t ii; for (ii = 0; ii < ht->ht_capacity; ii += 1) { pmix_hash_element_t *elt = &ht->ht_table[ii]; if (elt->valid && ht->ht_type_methods && ht->ht_type_methods->elt_destructor) { ht->ht_type_methods->elt_destructor(elt); } elt->valid = 0; elt->value = NULL; } ht->ht_size = 0; /* the tests reuse the hash table for different types after removing all */ /* so we should allow that by forgetting what type it used to be */ ht->ht_type_methods = NULL; return PMIX_SUCCESS; } static int /* PMIX_ return code */ pmix_hash_grow(pmix_hash_table_t *ht) { pmix_tma_t *const tma = pmix_obj_get_tma(&ht->super); size_t jj, ii; pmix_hash_element_t *old_table; pmix_hash_element_t *new_table; size_t old_capacity; size_t new_capacity; old_table = ht->ht_table; old_capacity = ht->ht_capacity; new_capacity = old_capacity * ht->ht_growth_numer / ht->ht_growth_denom; new_capacity = pmix_hash_round_capacity_up(new_capacity); new_table = (pmix_hash_element_t *)pmix_tma_calloc(tma, new_capacity, sizeof(new_table[0])); if (PMIX_UNLIKELY(NULL == new_table)) { return PMIX_ERR_OUT_OF_RESOURCE; } /* for each element of the old table (indexed by jj), insert it into the new table (indexed by ii), using the hash_elt method to generically hash an element, then modulo the new capacity, and using struct-assignment to copy an old element into its place int he new table. The hash table never owns the value, and in the case of ptr keys the old dlements will be blindly deleted, so we still own the ptr key storage, just in the new table now */ for (jj = 0; jj < old_capacity; jj += 1) { pmix_hash_element_t *old_elt; pmix_hash_element_t *new_elt; old_elt = &old_table[jj]; if (old_elt->valid) { for (ii = (ht->ht_type_methods->hash_elt(old_elt) % new_capacity);; ii += 1) { if (ii == new_capacity) { ii = 0; } new_elt = &new_table[ii]; if (!new_elt->valid) { *new_elt = *old_elt; break; } } } } /* update with the new, free the old, return */ ht->ht_table = new_table; ht->ht_capacity = new_capacity; ht->ht_growth_trigger = new_capacity * ht->ht_density_numer / ht->ht_density_denom; pmix_tma_free(tma, old_table); return PMIX_SUCCESS; } /* one of the removal functions has determined which element should be removed. With the help of the type methods this can be generic. The important thing is to rehash any valid elements immediately following the element-being-removed */ static int /* PMIX_ return code */ pmix_hash_table_remove_elt_at(pmix_hash_table_t *ht, size_t ii) { size_t jj, capacity = ht->ht_capacity; pmix_hash_element_t *elts = ht->ht_table; pmix_hash_element_t *elt; elt = &elts[ii]; if (!elt->valid) { /* huh? removing a not-valid element? */ return PMIX_ERROR; } elt->valid = 0; if (ht->ht_type_methods->elt_destructor) { ht->ht_type_methods->elt_destructor(elt); } /* need to possibly re-insert followers because of the now-gap */ /* E.g., XYyAaCbz. (where upper is ideal, lower is not) * remove A * leaving XYy.aCbz. and we need to reconsider aCbz * first a gets reinserted where it wants to be: XYya.Cbz. * next C doesn't move: XYya.Cbz. * then b gets put where it wants to be: XYyabC.z. * then z moves down a little: XYyabCz.. * then . means we're done */ for (ii = ii + 1;; ii += 1) { /* scan immediately following elements */ if (ii == capacity) { ii = 0; } elt = &elts[ii]; if (!elt->valid) { break; /* done */ } /* rehash it and move it if necessary */ for (jj = ht->ht_type_methods->hash_elt(elt) % capacity;; jj += 1) { if (jj == capacity) { jj = 0; } if (jj == ii) { /* already in place, either ideal or best-for-now */ break; } else if (!elts[jj].valid) { /* move it down, and invaildate where it came from */ elts[jj] = elts[ii]; elts[ii].valid = 0; break; } else { /* still need to find its place */ } } } ht->ht_size -= 1; return PMIX_SUCCESS; } /***************************************************************************/ static uint64_t pmix_hash_hash_elt_uint32(pmix_hash_element_t *elt) { return elt->key.u32; } static const struct pmix_hash_type_methods_t pmix_hash_type_methods_uint32 = {NULL, pmix_hash_hash_elt_uint32}; int /* PMIX_ return code */ pmix_hash_table_get_value_uint32(pmix_hash_table_t *ht, uint32_t key, void **value) { size_t ii, capacity = ht->ht_capacity; pmix_hash_element_t *elt; #if PMIX_ENABLE_DEBUG if (capacity == 0) { pmix_output(0, "pmix_hash_table_get_value_uint32:" "pmix_hash_table_init() has not been called"); return PMIX_ERROR; } // First check if the hash table is using a non-standard heap manager. Skip // this debug check because use of a shared-memory TMA may trigger an error // since some processes may have not yet updated their function pointers // (done below). if (NULL == pmix_obj_get_tma(&ht->super) && NULL != ht->ht_type_methods && &pmix_hash_type_methods_uint32 != ht->ht_type_methods) { pmix_output(0, "pmix_hash_table_get_value_uint32:" "hash table is for a different key type"); return PMIX_ERROR; } #endif ht->ht_type_methods = &pmix_hash_type_methods_uint32; for (ii = key % capacity;; ii += 1) { if (ii == capacity) { ii = 0; } elt = &ht->ht_table[ii]; if (!elt->valid) { return PMIX_ERR_NOT_FOUND; } else if (elt->key.u32 == key) { *value = elt->value; return PMIX_SUCCESS; } else { /* keep looking */ } } } int /* PMIX_ return code */ pmix_hash_table_set_value_uint32(pmix_hash_table_t *ht, uint32_t key, void *value) { int rc; size_t ii, capacity = ht->ht_capacity; pmix_hash_element_t *elt; pmix_tma_t *const tma = pmix_obj_get_tma(&ht->super); #if PMIX_ENABLE_DEBUG if (capacity == 0) { pmix_output(0, "pmix_hash_table_set_value_uint32:" "pmix_hash_table_init() has not been called"); return PMIX_ERR_BAD_PARAM; } // First check if the hash table is using a non-standard heap manager. Skip // this debug check because use of a shared-memory TMA may trigger an error // since some processes may have not yet updated their function pointers // (done below). if (NULL == pmix_obj_get_tma(&ht->super) && NULL != ht->ht_type_methods && &pmix_hash_type_methods_uint32 != ht->ht_type_methods) { pmix_output(0, "pmix_hash_table_set_value_uint32:" "hash table is for a different key type"); return PMIX_ERROR; } #endif ht->ht_type_methods = &pmix_hash_type_methods_uint32; for (ii = key % capacity;; ii += 1) { if (ii == capacity) { ii = 0; } elt = &ht->ht_table[ii]; if (!elt->valid) { /* new entry */ elt->key.u32 = key; elt->value = value; elt->valid = 1; elt->tma = tma; ht->ht_size += 1; if (ht->ht_size >= ht->ht_growth_trigger) { if (PMIX_SUCCESS != (rc = pmix_hash_grow(ht))) { return rc; } } return PMIX_SUCCESS; } else if (elt->key.u32 == key) { /* replace existing element */ elt->value = value; return PMIX_SUCCESS; } else { /* keep looking */ } } } int pmix_hash_table_remove_value_uint32(pmix_hash_table_t *ht, uint32_t key) { size_t ii, capacity = ht->ht_capacity; #if PMIX_ENABLE_DEBUG if (capacity == 0) { pmix_output(0, "pmix_hash_table_get_value_uint32:" "pmix_hash_table_init() has not been called"); return PMIX_ERROR; } // First check if the hash table is using a non-standard heap manager. Skip // this debug check because use of a shared-memory TMA may trigger an error // since some processes may have not yet updated their function pointers // (done below). if (NULL == pmix_obj_get_tma(&ht->super) && NULL != ht->ht_type_methods && &pmix_hash_type_methods_uint32 != ht->ht_type_methods) { pmix_output(0, "pmix_hash_table_remove_value_uint32:" "hash table is for a different key type"); return PMIX_ERROR; } #endif ht->ht_type_methods = &pmix_hash_type_methods_uint32; for (ii = key % capacity;; ii += 1) { pmix_hash_element_t *elt; if (ii == capacity) ii = 0; elt = &ht->ht_table[ii]; if (!elt->valid) { return PMIX_ERR_NOT_FOUND; } else if (elt->key.u32 == key) { return pmix_hash_table_remove_elt_at(ht, ii); } else { /* keep looking */ } } } /***************************************************************************/ static uint64_t pmix_hash_hash_elt_uint64(pmix_hash_element_t *elt) { return elt->key.u64; } static const struct pmix_hash_type_methods_t pmix_hash_type_methods_uint64 = {NULL, pmix_hash_hash_elt_uint64}; int /* PMIX_ return code */ pmix_hash_table_get_value_uint64(pmix_hash_table_t *ht, uint64_t key, void **value) { size_t ii; size_t capacity = ht->ht_capacity; pmix_hash_element_t *elt; #if PMIX_ENABLE_DEBUG if (capacity == 0) { pmix_output(0, "pmix_hash_table_get_value_uint64:" "pmix_hash_table_init() has not been called"); return PMIX_ERROR; } // First check if the hash table is using a non-standard heap manager. Skip // this debug check because use of a shared-memory TMA may trigger an error // since some processes may have not yet updated their function pointers // (done below). if (NULL == pmix_obj_get_tma(&ht->super) && NULL != ht->ht_type_methods && &pmix_hash_type_methods_uint64 != ht->ht_type_methods) { pmix_output(0, "pmix_hash_table_get_value_uint64:" "hash table is for a different key type"); return PMIX_ERROR; } #endif ht->ht_type_methods = &pmix_hash_type_methods_uint64; for (ii = key % capacity;; ii += 1) { if (ii == capacity) { ii = 0; } elt = &ht->ht_table[ii]; if (!elt->valid) { return PMIX_ERR_NOT_FOUND; } else if (elt->key.u64 == key) { *value = elt->value; return PMIX_SUCCESS; } else { /* keep looking */ } } } int /* PMIX_ return code */ pmix_hash_table_set_value_uint64(pmix_hash_table_t *ht, uint64_t key, void *value) { int rc; size_t ii, capacity = ht->ht_capacity; pmix_hash_element_t *elt; pmix_tma_t *const tma = pmix_obj_get_tma(&ht->super); #if PMIX_ENABLE_DEBUG if (capacity == 0) { pmix_output(0, "pmix_hash_table_set_value_uint64:" "pmix_hash_table_init() has not been called"); return PMIX_ERR_BAD_PARAM; } // First check if the hash table is using a non-standard heap manager. Skip // this debug check because use of a shared-memory TMA may trigger an error // since some processes may have not yet updated their function pointers // (done below). if (NULL == pmix_obj_get_tma(&ht->super) && NULL != ht->ht_type_methods && &pmix_hash_type_methods_uint64 != ht->ht_type_methods) { pmix_output(0, "pmix_hash_table_set_value_uint64:" "hash table is for a different key type"); return PMIX_ERROR; } #endif ht->ht_type_methods = &pmix_hash_type_methods_uint64; for (ii = key % capacity;; ii += 1) { if (ii == capacity) { ii = 0; } elt = &ht->ht_table[ii]; if (!elt->valid) { /* new entry */ elt->key.u64 = key; elt->value = value; elt->valid = 1; elt->tma = tma; ht->ht_size += 1; if (ht->ht_size >= ht->ht_growth_trigger) { if (PMIX_SUCCESS != (rc = pmix_hash_grow(ht))) { return rc; } } return PMIX_SUCCESS; } else if (elt->key.u64 == key) { elt->value = value; return PMIX_SUCCESS; } else { /* keep looking */ } } } int /* PMIX_ return code */ pmix_hash_table_remove_value_uint64(pmix_hash_table_t *ht, uint64_t key) { size_t ii, capacity = ht->ht_capacity; #if PMIX_ENABLE_DEBUG if (capacity == 0) { pmix_output(0, "pmix_hash_table_get_value_uint64:" "pmix_hash_table_init() has not been called"); return PMIX_ERROR; } // First check if the hash table is using a non-standard heap manager. Skip // this debug check because use of a shared-memory TMA may trigger an error // since some processes may have not yet updated their function pointers // (done below). if (NULL == pmix_obj_get_tma(&ht->super) && NULL != ht->ht_type_methods && &pmix_hash_type_methods_uint64 != ht->ht_type_methods) { pmix_output(0, "pmix_hash_table_remove_value_uint64:" "hash table is for a different key type"); return PMIX_ERROR; } #endif ht->ht_type_methods = &pmix_hash_type_methods_uint64; for (ii = key % capacity;; ii += 1) { pmix_hash_element_t *elt; if (ii == capacity) { ii = 0; } elt = &ht->ht_table[ii]; if (!elt->valid) { return PMIX_ERR_NOT_FOUND; } else if (elt->key.u64 == key) { return pmix_hash_table_remove_elt_at(ht, ii); } else { /* keep looking */ } } } /***************************************************************************/ /* helper function used in several places */ static uint64_t pmix_hash_hash_key_ptr(const void *key, size_t key_size) { uint64_t hash; const unsigned char *scanner; size_t ii; hash = 0; scanner = (const unsigned char *) key; for (ii = 0; ii < key_size; ii += 1) { hash = HASH_MULTIPLIER * hash + *scanner++; } return hash; } /* ptr methods */ static void pmix_hash_destruct_elt_ptr(pmix_hash_element_t *elt) { elt->key.ptr.key_size = 0; void *key = (void *) elt->key.ptr.key; /* cast away const so we can free it */ if (NULL != key) { elt->key.ptr.key = NULL; pmix_tma_free(elt->tma, key); } } static uint64_t pmix_hash_hash_elt_ptr(pmix_hash_element_t *elt) { return pmix_hash_hash_key_ptr(elt->key.ptr.key, elt->key.ptr.key_size); } static const struct pmix_hash_type_methods_t pmix_hash_type_methods_ptr = {pmix_hash_destruct_elt_ptr, pmix_hash_hash_elt_ptr}; int /* PMIX_ return code */ pmix_hash_table_get_value_ptr(pmix_hash_table_t *ht, const void *key, size_t key_size, void **value) { size_t ii, capacity = ht->ht_capacity; pmix_hash_element_t *elt; #if PMIX_ENABLE_DEBUG if (capacity == 0) { pmix_output(0, "pmix_hash_table_get_value_ptr:" "pmix_hash_table_init() has not been called"); return PMIX_ERROR; } // First check if the hash table is using a non-standard heap manager. Skip // this debug check because use of a shared-memory TMA may trigger an error // since some processes may have not yet updated their function pointers // (done below). if (NULL == pmix_obj_get_tma(&ht->super) && NULL != ht->ht_type_methods && &pmix_hash_type_methods_ptr != ht->ht_type_methods) { pmix_output(0, "pmix_hash_table_get_value_ptr:" "hash table is for a different key type"); return PMIX_ERROR; } #endif ht->ht_type_methods = &pmix_hash_type_methods_ptr; for (ii = pmix_hash_hash_key_ptr(key, key_size) % capacity;; ii += 1) { if (ii == capacity) { ii = 0; } elt = &ht->ht_table[ii]; if (!elt->valid) { return PMIX_ERR_NOT_FOUND; } else if (elt->key.ptr.key_size == key_size && 0 == memcmp(elt->key.ptr.key, key, key_size)) { *value = elt->value; return PMIX_SUCCESS; } else { /* keep going */ } } } int /* PMIX_ return code */ pmix_hash_table_set_value_ptr(pmix_hash_table_t *ht, const void *key, size_t key_size, void *value) { int rc; size_t ii, capacity = ht->ht_capacity; pmix_hash_element_t *elt; pmix_tma_t *const tma = pmix_obj_get_tma(&ht->super); #if PMIX_ENABLE_DEBUG if (capacity == 0) { pmix_output(0, "pmix_hash_table_set_value_ptr:" "pmix_hash_table_init() has not been called"); return PMIX_ERR_BAD_PARAM; } // First check if the hash table is using a non-standard heap manager. Skip // this debug check because use of a shared-memory TMA may trigger an error // since some processes may have not yet updated their function pointers // (done below). if (NULL == pmix_obj_get_tma(&ht->super) && NULL != ht->ht_type_methods && &pmix_hash_type_methods_ptr != ht->ht_type_methods) { pmix_output(0, "pmix_hash_table_set_value_ptr:" "hash table is for a different key type"); return PMIX_ERROR; } #endif ht->ht_type_methods = &pmix_hash_type_methods_ptr; for (ii = pmix_hash_hash_key_ptr(key, key_size) % capacity;; ii += 1) { if (ii == capacity) { ii = 0; } elt = &ht->ht_table[ii]; if (!elt->valid) { /* new entry */ void *key_local = pmix_tma_malloc(tma, key_size); memcpy(key_local, key, key_size); elt->key.ptr.key = key_local; elt->key.ptr.key_size = key_size; elt->value = value; elt->valid = 1; elt->tma = tma; ht->ht_size += 1; if (ht->ht_size >= ht->ht_growth_trigger) { if (PMIX_SUCCESS != (rc = pmix_hash_grow(ht))) { return rc; } } return PMIX_SUCCESS; } else if (elt->key.ptr.key_size == key_size && 0 == memcmp(elt->key.ptr.key, key, key_size)) { /* replace existing value */ elt->value = value; return PMIX_SUCCESS; } else { /* keep looking */ } } } int /* PMIX_ return code */ pmix_hash_table_remove_value_ptr(pmix_hash_table_t *ht, const void *key, size_t key_size) { size_t ii, capacity = ht->ht_capacity; #if PMIX_ENABLE_DEBUG if (capacity == 0) { pmix_output(0, "pmix_hash_table_get_value_ptr:" "pmix_hash_table_init() has not been called"); return PMIX_ERROR; } // First check if the hash table is using a non-standard heap manager. Skip // this debug check because use of a shared-memory TMA may trigger an error // since some processes may have not yet updated their function pointers // (done below). if (NULL == pmix_obj_get_tma(&ht->super) && NULL != ht->ht_type_methods && &pmix_hash_type_methods_ptr != ht->ht_type_methods) { pmix_output(0, "pmix_hash_table_remove_value_ptr:" "hash table is for a different key type"); return PMIX_ERROR; } #endif ht->ht_type_methods = &pmix_hash_type_methods_ptr; for (ii = pmix_hash_hash_key_ptr(key, key_size) % capacity;; ii += 1) { pmix_hash_element_t *elt; if (ii == capacity) { ii = 0; } elt = &ht->ht_table[ii]; if (!elt->valid) { return PMIX_ERR_NOT_FOUND; } else if (elt->key.ptr.key_size == key_size && 0 == memcmp(elt->key.ptr.key, key, key_size)) { return pmix_hash_table_remove_elt_at(ht, ii); } else { /* keep looking */ } } } /***************************************************************************/ /* Traversals */ static int /* PMIX_ return code */ pmix_hash_table_get_next_elt(pmix_hash_table_t *ht, pmix_hash_element_t *prev_elt, /* NULL means find first */ pmix_hash_element_t **next_elt) { pmix_hash_element_t *elts = ht->ht_table; size_t ii, capacity = ht->ht_capacity; for (ii = (NULL == prev_elt ? 0 : (prev_elt - elts) + 1); ii < capacity; ii += 1) { pmix_hash_element_t *elt = &elts[ii]; if (elt->valid) { *next_elt = elt; return PMIX_SUCCESS; } } return PMIX_ERROR; } int /* PMIX_ return code */ pmix_hash_table_get_first_key_uint32(pmix_hash_table_t *ht, uint32_t *key, void **value, void **node) { return pmix_hash_table_get_next_key_uint32(ht, key, value, NULL, node); } int /* PMIX_ return code */ pmix_hash_table_get_next_key_uint32(pmix_hash_table_t *ht, uint32_t *key, void **value, void *in_node, void **out_node) { pmix_hash_element_t *elt; if (PMIX_SUCCESS == pmix_hash_table_get_next_elt(ht, (pmix_hash_element_t *) in_node, &elt)) { *key = elt->key.u32; *value = elt->value; *out_node = elt; return PMIX_SUCCESS; } return PMIX_ERROR; } int /* PMIX_ return code */ pmix_hash_table_get_first_key_ptr(pmix_hash_table_t *ht, void **key, size_t *key_size, void **value, void **node) { return pmix_hash_table_get_next_key_ptr(ht, key, key_size, value, NULL, node); } int /* PMIX_ return code */ pmix_hash_table_get_next_key_ptr(pmix_hash_table_t *ht, void **key, size_t *key_size, void **value, void *in_node, void **out_node) { pmix_hash_element_t *elt; if (PMIX_SUCCESS == pmix_hash_table_get_next_elt(ht, (pmix_hash_element_t *) in_node, &elt)) { *key = (void *) elt->key.ptr.key; *key_size = elt->key.ptr.key_size; *value = elt->value; *out_node = elt; return PMIX_SUCCESS; } return PMIX_ERROR; } int /* PMIX_ return code */ pmix_hash_table_get_first_key_uint64(pmix_hash_table_t *ht, uint64_t *key, void **value, void **node) { return pmix_hash_table_get_next_key_uint64(ht, key, value, NULL, node); } int /* PMIX_ return code */ pmix_hash_table_get_next_key_uint64(pmix_hash_table_t *ht, uint64_t *key, void **value, void *in_node, void **out_node) { pmix_hash_element_t *elt; if (PMIX_SUCCESS == pmix_hash_table_get_next_elt(ht, (pmix_hash_element_t *) in_node, &elt)) { *key = elt->key.u64; *value = elt->value; *out_node = elt; return PMIX_SUCCESS; } return PMIX_ERROR; } size_t pmix_hash_table_sizeof_hash_element(void) { return sizeof(pmix_hash_element_t); } /* there was/is no traversal for the ptr case; it would go here */ /* interact with the class-like mechanism */ pmix-6.1.1~rc2/src/class/Makefile.am0000664000175000017500000000311415203536752017424 0ustar alastairalastair# -*- makefile -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2007 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2013-2018 Intel, Inc. All rights reserved. # Copyright (c) 2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = \ $(LTDLINCL) noinst_LTLIBRARIES = libpmix_class.la # Source code files headers = \ pmix_bitmap.h \ pmix_object.h \ pmix_list.h \ pmix_pointer_array.h \ pmix_hash_table.h \ pmix_hotel.h \ pmix_ring_buffer.h \ pmix_value_array.h sources = \ pmix_bitmap.c \ pmix_object.c \ pmix_list.c \ pmix_pointer_array.c \ pmix_hash_table.c \ pmix_hotel.c \ pmix_ring_buffer.c \ pmix_value_array.c libpmix_class_la_SOURCES = $(headers) $(sources) # Unconditionally install the header files pmixdir = $(pmixincludedir)/$(subdir) pmix_HEADERS = $(headers) pmix-6.1.1~rc2/src/class/pmix_bitmap.c0000664000175000017500000002350715203536752020055 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2014 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010-2012 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include "pmix_common.h" #include "src/class/pmix_bitmap.h" /* The number of bits in the underlying type of the bitmap field * in the pmix_bitmap_t struct */ #define SIZE_OF_BASE_TYPE 64 static void pmix_bitmap_construct(pmix_bitmap_t *bm); static void pmix_bitmap_destruct(pmix_bitmap_t *bm); PMIX_CLASS_INSTANCE(pmix_bitmap_t, pmix_object_t, pmix_bitmap_construct, pmix_bitmap_destruct); static void pmix_bitmap_construct(pmix_bitmap_t *bm) { bm->bitmap = NULL; bm->array_size = 0; bm->max_size = INT_MAX; } static void pmix_bitmap_destruct(pmix_bitmap_t *bm) { if (NULL != bm->bitmap) { free(bm->bitmap); bm->bitmap = NULL; } } int pmix_bitmap_set_max_size(pmix_bitmap_t *bm, int max_size) { if (NULL == bm) { return PMIX_ERR_BAD_PARAM; } /* * Only if the caller wants to set the maximum size, * we set it (in numbers of bits!), otherwise it is * set to INT_MAX in the constructor. */ bm->max_size = (int) (((size_t) max_size + SIZE_OF_BASE_TYPE - 1) / SIZE_OF_BASE_TYPE); return PMIX_SUCCESS; } int pmix_bitmap_init(pmix_bitmap_t *bm, int size) { /* * Only if the caller set the maximum size before initializing, * we test here (in numbers of bits!) * By default, the max size is INT_MAX, set in the constructor. */ if ((size <= 0) || (NULL == bm) || (size > bm->max_size)) { return PMIX_ERR_BAD_PARAM; } bm->array_size = (int) (((size_t) size + SIZE_OF_BASE_TYPE - 1) / SIZE_OF_BASE_TYPE); if (NULL != bm->bitmap) { free(bm->bitmap); if (bm->max_size < bm->array_size) bm->max_size = bm->array_size; } bm->bitmap = (uint64_t *) calloc(bm->array_size, sizeof(uint64_t)); if (NULL == bm->bitmap) { return PMIX_ERR_OUT_OF_RESOURCE; } pmix_bitmap_clear_all_bits(bm); return PMIX_SUCCESS; } int pmix_bitmap_set_bit(pmix_bitmap_t *bm, int bit) { int index, offset, new_size; if ((bit < 0) || (NULL == bm) || (bit > bm->max_size)) { return PMIX_ERR_BAD_PARAM; } index = bit / SIZE_OF_BASE_TYPE; offset = bit % SIZE_OF_BASE_TYPE; if (index >= bm->array_size) { /* We need to allocate more space for the bitmap, since we are out of range. We don't throw any error here, because this is valid and we simply expand the bitmap */ new_size = index + 1; if (new_size > bm->max_size) new_size = bm->max_size; /* New size is just a multiple of the original size to fit in the index. */ bm->bitmap = (uint64_t *) realloc(bm->bitmap, new_size * sizeof(uint64_t)); if (NULL == bm->bitmap) { return PMIX_ERR_OUT_OF_RESOURCE; } /* zero out the new elements */ memset(&bm->bitmap[bm->array_size], 0, (new_size - bm->array_size) * sizeof(uint64_t)); /* Update the array_size */ bm->array_size = new_size; } /* Now set the bit */ bm->bitmap[index] |= (1UL << offset); return PMIX_SUCCESS; } int pmix_bitmap_clear_bit(pmix_bitmap_t *bm, int bit) { int index, offset; if ((bit < 0) || NULL == bm || (bit >= (bm->array_size * SIZE_OF_BASE_TYPE))) { return PMIX_ERR_BAD_PARAM; } index = bit / SIZE_OF_BASE_TYPE; offset = bit % SIZE_OF_BASE_TYPE; bm->bitmap[index] &= ~(1UL << offset); return PMIX_SUCCESS; } bool pmix_bitmap_is_set_bit(pmix_bitmap_t *bm, int bit) { int index, offset; if ((bit < 0) || NULL == bm || (bit >= (bm->array_size * SIZE_OF_BASE_TYPE))) { return false; } index = bit / SIZE_OF_BASE_TYPE; offset = bit % SIZE_OF_BASE_TYPE; if (0 != (bm->bitmap[index] & (1UL << offset))) { return true; } return false; } int pmix_bitmap_clear_all_bits(pmix_bitmap_t *bm) { if (NULL == bm) { return PMIX_ERR_BAD_PARAM; } memset(bm->bitmap, 0, bm->array_size * sizeof(uint64_t)); return PMIX_SUCCESS; } int pmix_bitmap_set_all_bits(pmix_bitmap_t *bm) { if (NULL == bm) { return PMIX_ERR_BAD_PARAM; } memset(bm->bitmap, 0xff, bm->array_size * sizeof(uint64_t)); return PMIX_SUCCESS; } int pmix_bitmap_find_and_set_first_unset_bit(pmix_bitmap_t *bm, int *position) { int i = 0; uint64_t temp, all_ones = 0xffffffffffffffffUL; if (NULL == bm) { return PMIX_ERR_BAD_PARAM; } /* Neglect all which don't have an unset bit */ *position = 0; while ((i < bm->array_size) && (bm->bitmap[i] == all_ones)) { ++i; } if (i == bm->array_size) { /* increase the bitmap size then */ *position = bm->array_size * SIZE_OF_BASE_TYPE; return pmix_bitmap_set_bit(bm, *position); } /* This one has an unset bit, find its bit number */ temp = bm->bitmap[i]; bm->bitmap[i] |= (bm->bitmap[i] + 1); /* Set the first zero bit */ temp ^= bm->bitmap[i]; /* Compute the change: the first unset bit in the original number */ while (!(temp & 0x1)) { ++(*position); temp >>= 1; } (*position) += i * SIZE_OF_BASE_TYPE; return PMIX_SUCCESS; } int pmix_bitmap_bitwise_and_inplace(pmix_bitmap_t *dest, pmix_bitmap_t *right) { int i; /* * Sanity check */ if (NULL == dest || NULL == right) { return PMIX_ERR_BAD_PARAM; } if (dest->array_size != right->array_size) { return PMIX_ERR_BAD_PARAM; } /* * Bitwise AND */ for (i = 0; i < dest->array_size; ++i) { dest->bitmap[i] &= right->bitmap[i]; } return PMIX_SUCCESS; } int pmix_bitmap_bitwise_or_inplace(pmix_bitmap_t *dest, pmix_bitmap_t *right) { int i; /* * Sanity check */ if (NULL == dest || NULL == right) { return PMIX_ERR_BAD_PARAM; } if (dest->array_size != right->array_size) { return PMIX_ERR_BAD_PARAM; } /* * Bitwise OR */ for (i = 0; i < dest->array_size; ++i) { dest->bitmap[i] |= right->bitmap[i]; } return PMIX_SUCCESS; } int pmix_bitmap_bitwise_xor_inplace(pmix_bitmap_t *dest, pmix_bitmap_t *right) { int i; /* * Sanity check */ if (NULL == dest || NULL == right) { return PMIX_ERR_BAD_PARAM; } if (dest->array_size != right->array_size) { return PMIX_ERR_BAD_PARAM; } /* * Bitwise XOR */ for (i = 0; i < dest->array_size; ++i) { dest->bitmap[i] ^= right->bitmap[i]; } return PMIX_SUCCESS; } bool pmix_bitmap_are_different(pmix_bitmap_t *left, pmix_bitmap_t *right) { int i; /* * Sanity check */ if (NULL == left || NULL == right) { return PMIX_ERR_BAD_PARAM; } if (pmix_bitmap_size(left) != pmix_bitmap_size(right)) { return true; } /* * Direct comparison */ for (i = 0; i < left->array_size; ++i) { if (left->bitmap[i] != right->bitmap[i]) { return true; } } return false; } char *pmix_bitmap_get_string(pmix_bitmap_t *bitmap) { int i; char *bitmap_str = NULL; if (NULL == bitmap) { return NULL; } bitmap_str = malloc(bitmap->array_size * SIZE_OF_BASE_TYPE + 1); if (NULL == bitmap_str) { return NULL; } bitmap_str[bitmap->array_size * SIZE_OF_BASE_TYPE] = '\0'; for (i = 0; i < (bitmap->array_size * SIZE_OF_BASE_TYPE); ++i) { if (pmix_bitmap_is_set_bit(bitmap, i)) { bitmap_str[i] = 'X'; } else { bitmap_str[i] = '_'; } } return bitmap_str; } int pmix_bitmap_num_unset_bits(pmix_bitmap_t *bm, int len) { return (len - pmix_bitmap_num_set_bits(bm, len)); } int pmix_bitmap_num_set_bits(pmix_bitmap_t *bm, int len) { int i, cnt = 0; uint64_t val; int i_len = len / SIZE_OF_BASE_TYPE + (len % SIZE_OF_BASE_TYPE == 0 ? 0 : 1); #if PMIX_ENABLE_DEBUG if ((len < 0) || NULL == bm) { return 0; } #endif for (i = 0; i < i_len && i < bm->array_size; ++i) { if (0 == (val = bm->bitmap[i])) continue; if (i == i_len - 1 && len % SIZE_OF_BASE_TYPE != 0) { /* mask out the bits above len */ val = val & ((1LL << (len - i * SIZE_OF_BASE_TYPE)) - 1); if (0 == val) continue; } /* Peter Wegner in CACM 3 (1960), 322. This method goes through as many * iterations as there are set bits. */ for (; val; cnt++) { val &= val - 1; /* clear the least significant bit set */ } } return cnt; } bool pmix_bitmap_is_clear(pmix_bitmap_t *bm) { int i; for (i = 0; i < bm->array_size; ++i) { if (0 != bm->bitmap[i]) { return false; } } return true; } pmix-6.1.1~rc2/src/class/pmix_list.c0000664000175000017500000001546115203536752017554 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2007 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Voltaire All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #include "pmix_common.h" #include "src/include/pmix_globals.h" /* * List classes */ static void pmix_list_item_construct(pmix_list_item_t *); static void pmix_list_item_destruct(pmix_list_item_t *); PMIX_CLASS_INSTANCE(pmix_list_item_t, pmix_object_t, pmix_list_item_construct, pmix_list_item_destruct); static void pmix_list_construct(pmix_list_t *); static void pmix_list_destruct(pmix_list_t *); PMIX_CLASS_INSTANCE(pmix_list_t, pmix_object_t, pmix_list_construct, pmix_list_destruct); /* * * pmix_list_link_item_t interface * */ static void pmix_list_item_construct(pmix_list_item_t *item) { item->pmix_list_next = item->pmix_list_prev = NULL; item->item_free = 1; #if PMIX_ENABLE_DEBUG item->pmix_list_item_refcount = 0; item->pmix_list_item_belong_to = NULL; #endif } static void pmix_list_item_destruct(pmix_list_item_t *item) { #if PMIX_ENABLE_DEBUG assert(0 == item->pmix_list_item_refcount); assert(NULL == item->pmix_list_item_belong_to); #endif /* PMIX_ENABLE_DEBUG */ PMIX_HIDE_UNUSED_PARAMS(item); } /* * * pmix_list_list_t interface * */ static void pmix_list_construct(pmix_list_t *list) { #if PMIX_ENABLE_DEBUG /* These refcounts should never be used in assertions because they should never be removed from this list, added to another list, etc. So set them to sentinel values. */ PMIX_CONSTRUCT(&(list->pmix_list_sentinel), pmix_list_item_t); list->pmix_list_sentinel.pmix_list_item_refcount = 1; list->pmix_list_sentinel.pmix_list_item_belong_to = list; #endif list->pmix_list_sentinel.pmix_list_next = &list->pmix_list_sentinel; list->pmix_list_sentinel.pmix_list_prev = &list->pmix_list_sentinel; list->pmix_list_length = 0; } /* * Reset all the pointers to be NULL -- do not actually destroy * anything. */ static void pmix_list_destruct(pmix_list_t *list) { pmix_list_construct(list); } /* * Insert an item at a specific place in a list */ bool pmix_list_insert(pmix_list_t *list, pmix_list_item_t *item, long long idx) { /* Adds item to list at index and retains item. */ int i; volatile pmix_list_item_t *ptr, *next; if (idx >= (long long) list->pmix_list_length) { return false; } if (0 == idx) { pmix_list_prepend(list, item); } else { #if PMIX_ENABLE_DEBUG /* Spot check: ensure that this item is previously on no lists */ assert(0 == item->pmix_list_item_refcount); #endif /* pointer to element 0 */ ptr = list->pmix_list_sentinel.pmix_list_next; for (i = 0; i < idx - 1; i++) ptr = ptr->pmix_list_next; next = ptr->pmix_list_next; item->pmix_list_next = next; item->pmix_list_prev = ptr; next->pmix_list_prev = item; ptr->pmix_list_next = item; #if PMIX_ENABLE_DEBUG /* Spot check: ensure this item is only on the list that we just inserted it into */ item->pmix_list_item_refcount += 1; assert(1 == item->pmix_list_item_refcount); item->pmix_list_item_belong_to = list; #endif list->pmix_list_length++; } return true; } static void pmix_list_transfer(pmix_list_item_t *pos, pmix_list_item_t *begin, pmix_list_item_t *end) { volatile pmix_list_item_t *tmp; if (pos != end) { /* remove [begin, end) */ end->pmix_list_prev->pmix_list_next = pos; begin->pmix_list_prev->pmix_list_next = end; pos->pmix_list_prev->pmix_list_next = begin; /* splice into new position before pos */ tmp = pos->pmix_list_prev; pos->pmix_list_prev = end->pmix_list_prev; end->pmix_list_prev = begin->pmix_list_prev; begin->pmix_list_prev = tmp; #if PMIX_ENABLE_DEBUG { volatile pmix_list_item_t *item = begin; while (pos != item) { item->pmix_list_item_belong_to = pos->pmix_list_item_belong_to; item = item->pmix_list_next; assert(NULL != item); } } #endif /* PMIX_ENABLE_DEBUG */ } } void pmix_list_join(pmix_list_t *thislist, pmix_list_item_t *pos, pmix_list_t *xlist) { if (0 != pmix_list_get_size(xlist)) { pmix_list_transfer(pos, pmix_list_get_first(xlist), pmix_list_get_end(xlist)); /* fix the sizes */ thislist->pmix_list_length += xlist->pmix_list_length; xlist->pmix_list_length = 0; } } void pmix_list_splice(pmix_list_t *thislist, pmix_list_item_t *pos, pmix_list_t *xlist, pmix_list_item_t *first, pmix_list_item_t *last) { size_t change = 0; pmix_list_item_t *tmp; if (first != last) { /* figure out how many things we are going to move (have to do * first, since last might be end and then we wouldn't be able * to run the loop) */ for (tmp = first; tmp != last; tmp = pmix_list_get_next(tmp)) { change++; } pmix_list_transfer(pos, first, last); /* fix the sizes */ thislist->pmix_list_length += change; xlist->pmix_list_length -= change; } } int pmix_list_sort(pmix_list_t *list, pmix_list_item_compare_fn_t compare) { pmix_list_item_t *item; pmix_list_item_t **items; size_t i, index = 0; if (0 == list->pmix_list_length) { return PMIX_SUCCESS; } items = (pmix_list_item_t **) malloc(sizeof(pmix_list_item_t *) * list->pmix_list_length); if (NULL == items) { return PMIX_ERR_OUT_OF_RESOURCE; } while (NULL != (item = pmix_list_remove_first(list))) { items[index++] = item; } qsort(items, index, sizeof(pmix_list_item_t *), (int (*)(const void *, const void *)) compare); for (i = 0; i < index; i++) { pmix_list_append(list, items[i]); } free(items); return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/class/pmix_hotel.c0000664000175000017500000000775215203536752017720 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2012-2016 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012 Los Alamos National Security, LLC. All rights reserved * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2020 IBM Corporation. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include #include #include #include "src/class/pmix_hotel.h" static void local_eviction_callback(int fd, short flags, void *arg) { (void) fd; (void) flags; pmix_hotel_room_eviction_callback_arg_t *eargs = (pmix_hotel_room_eviction_callback_arg_t *) arg; void *occupant = eargs->hotel->rooms[eargs->room_num].occupant; /* Remove the occurpant from the room. Do not change this logic without also changing the same logic in pmix_hotel_checkout() and pmix_hotel_checkout_and_return_occupant(). */ pmix_hotel_t *hotel = eargs->hotel; pmix_hotel_room_t *room = &(hotel->rooms[eargs->room_num]); room->occupant = NULL; hotel->last_unoccupied_room++; assert(hotel->last_unoccupied_room < hotel->num_rooms); hotel->unoccupied_rooms[hotel->last_unoccupied_room] = eargs->room_num; /* Invoke the user callback to tell them that they were evicted */ hotel->evict_callback_fn(hotel, eargs->room_num, occupant); } pmix_status_t pmix_hotel_init(pmix_hotel_t *h, int num_rooms, pmix_event_base_t *evbase, uint32_t eviction_timeout, pmix_hotel_eviction_callback_fn_t evict_callback_fn) { int i; /* Bozo check */ if (num_rooms <= 0 || NULL == evict_callback_fn) { return PMIX_ERR_BAD_PARAM; } h->num_rooms = num_rooms; h->evbase = evbase; h->eviction_timeout.tv_usec = 0; h->eviction_timeout.tv_sec = eviction_timeout; h->evict_callback_fn = evict_callback_fn; h->rooms = (pmix_hotel_room_t *) malloc(num_rooms * sizeof(pmix_hotel_room_t)); if (NULL != evict_callback_fn) { h->eviction_args = (pmix_hotel_room_eviction_callback_arg_t *) malloc( num_rooms * sizeof(pmix_hotel_room_eviction_callback_arg_t)); } h->unoccupied_rooms = (int *) malloc(num_rooms * sizeof(int)); h->last_unoccupied_room = num_rooms - 1; for (i = 0; i < num_rooms; ++i) { /* Mark this room as unoccupied */ h->rooms[i].occupant = NULL; /* Setup this room in the unoccupied index array */ h->unoccupied_rooms[i] = i; /* Setup the eviction callback args */ h->eviction_args[i].hotel = h; h->eviction_args[i].room_num = i; /* Create this room's event (but don't add it) */ if (NULL != h->evbase) { pmix_event_assign(&(h->rooms[i].eviction_timer_event), h->evbase, -1, 0, local_eviction_callback, &(h->eviction_args[i])); } } return PMIX_SUCCESS; } static void constructor(pmix_hotel_t *h) { h->num_rooms = 0; h->evbase = NULL; h->eviction_timeout.tv_sec = 0; h->eviction_timeout.tv_usec = 0; h->evict_callback_fn = NULL; h->rooms = NULL; h->eviction_args = NULL; h->unoccupied_rooms = NULL; h->last_unoccupied_room = -1; } static void destructor(pmix_hotel_t *h) { int i; /* Go through all occupied rooms and destroy their events */ if (NULL != h->evbase) { for (i = 0; i < h->num_rooms; ++i) { if (NULL != h->rooms[i].occupant) { pmix_event_del(&(h->rooms[i].eviction_timer_event)); } } } if (NULL != h->rooms) { free(h->rooms); } if (NULL != h->eviction_args) { free(h->eviction_args); } if (NULL != h->unoccupied_rooms) { free(h->unoccupied_rooms); } } PMIX_CLASS_INSTANCE(pmix_hotel_t, pmix_object_t, constructor, destructor); pmix-6.1.1~rc2/src/class/pmix_hash_table.h0000664000175000017500000003650315203536752020700 0ustar alastairalastair/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2022 Triad National Security, LLC. All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ /** @file * * A hash table that may be indexed with either fixed length * (e.g. uint32_t/uint64_t) or arbitrary size binary key * values. However, only one key type may be used in a given table * concurrently. */ #ifndef PMIX_HASH_TABLE_H #define PMIX_HASH_TABLE_H #include "src/include/pmix_config.h" #include "src/include/pmix_prefetch.h" #ifdef HAVE_STDINT_H # include #endif #include "src/class/pmix_list.h" #include "pmix_common.h" BEGIN_C_DECLS PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_hash_table_t); struct pmix_hash_table_t { pmix_object_t super; /**< subclass of pmix_object_t */ const char *ht_label; /**< label for debugging */ struct pmix_hash_element_t *ht_table; /**< table of elements (opaque to users) */ size_t ht_capacity; /**< allocated size (capacity) of table */ size_t ht_size; /**< number of extant entries */ size_t ht_growth_trigger; /**< size hits this and table is grown */ int ht_density_numer, ht_density_denom; /**< max allowed density of table */ int ht_growth_numer, ht_growth_denom; /**< growth factor when grown */ const struct pmix_hash_type_methods_t *ht_type_methods; }; typedef struct pmix_hash_table_t pmix_hash_table_t; #define PMIX_HASH_TABLE_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \ .ht_label = NULL, \ .ht_table = NULL, \ .ht_capacity = 0, \ .ht_size = 0, \ .ht_growth_trigger = 0, \ .ht_density_numer = 0, \ .ht_density_denom = 0, \ .ht_growth_numer = 0, \ .ht_growth_denom = 0, \ .ht_type_methods = NULL \ } /** * Initializes the table size, must be called before using * the table. * * @param table The input hash table (IN). * @param size The size of the table, which will be rounded up * (if required) to the next highest power of two (IN). * @return PMIX error code. * */ PMIX_EXPORT int pmix_hash_table_init(pmix_hash_table_t *ht, size_t table_size); /* this could be the new init if people wanted a more general API */ PMIX_EXPORT int pmix_hash_table_init2(pmix_hash_table_t *ht, size_t estimated_max_size, int density_numer, int density_denom, int growth_numer, int growth_denom); /** * Returns the number of elements currently stored in the table. * * @param table The input hash table (IN). * @return The number of elements in the table. * */ static inline size_t pmix_hash_table_get_size(pmix_hash_table_t *ht) { return ht->ht_size; } /** * Remove all elements from the table. * * @param table The input hash table (IN). * @return PMIX return code. * */ PMIX_EXPORT int pmix_hash_table_remove_all(pmix_hash_table_t *ht); /** * Retrieve value via uint32_t key. * * @param table The input hash table (IN). * @param key The input key (IN). * @param ptr The value associated with the key * @return integer return code: * - PMIX_SUCCESS if key was found * - PMIX_ERR_NOT_FOUND if key was not found * - PMIX_ERROR other error * */ PMIX_EXPORT int pmix_hash_table_get_value_uint32(pmix_hash_table_t *table, uint32_t key, void **ptr); /** * Set value based on uint32_t key. * * @param table The input hash table (IN). * @param key The input key (IN). * @param value The value to be associated with the key (IN). * @return PMIX return code. * */ PMIX_EXPORT int pmix_hash_table_set_value_uint32(pmix_hash_table_t *table, uint32_t key, void *value); /** * Remove value based on uint32_t key. * * @param table The input hash table (IN). * @param key The input key (IN). * @return PMIX return code. * */ PMIX_EXPORT int pmix_hash_table_remove_value_uint32(pmix_hash_table_t *table, uint32_t key); /** * Retrieve value via uint64_t key. * * @param table The input hash table (IN). * @param key The input key (IN). * @param ptr The value associated with the key * @return integer return code: * - PMIX_SUCCESS if key was found * - PMIX_ERR_NOT_FOUND if key was not found * - PMIX_ERROR other error * */ PMIX_EXPORT int pmix_hash_table_get_value_uint64(pmix_hash_table_t *table, uint64_t key, void **ptr); /** * Set value based on uint64_t key. * * @param table The input hash table (IN). * @param key The input key (IN). * @param value The value to be associated with the key (IN). * @return PMIX return code. * */ PMIX_EXPORT int pmix_hash_table_set_value_uint64(pmix_hash_table_t *table, uint64_t key, void *value); /** * Remove value based on uint64_t key. * * @param table The input hash table (IN). * @param key The input key (IN). * @return PMIX return code. * */ PMIX_EXPORT int pmix_hash_table_remove_value_uint64(pmix_hash_table_t *table, uint64_t key); /** * Retrieve value via arbitrary length binary key. * * @param table The input hash table (IN). * @param key The input key (IN). * @param ptr The value associated with the key * @return integer return code: * - PMIX_SUCCESS if key was found * - PMIX_ERR_NOT_FOUND if key was not found * - PMIX_ERROR other error * */ PMIX_EXPORT int pmix_hash_table_get_value_ptr(pmix_hash_table_t *table, const void *key, size_t keylen, void **ptr); /** * Set value based on arbitrary length binary key. * * @param table The input hash table (IN). * @param key The input key (IN). * @param value The value to be associated with the key (IN). * @return PMIX return code. * */ PMIX_EXPORT int pmix_hash_table_set_value_ptr(pmix_hash_table_t *table, const void *key, size_t keylen, void *value); /** * Remove value based on arbitrary length binary key. * * @param table The input hash table (IN). * @param key The input key (IN). * @return PMIX return code. * */ PMIX_EXPORT int pmix_hash_table_remove_value_ptr(pmix_hash_table_t *table, const void *key, size_t keylen); /** The following functions are only for allowing iterating through the hash table. The calls return along with a key, a pointer to the hash node with the current key, so that subsequent calls do not have to traverse all over again to the key (although it may just be a simple thing - to go to the array element and then traverse through the individual list). But lets take out this inefficiency too. This is similar to having an STL iterator in functionality */ /** * Get the first 32 bit key from the hash table, which can be used later to * get the next key * @param table The hash table pointer (IN) * @param key The first key (OUT) * @param value The value corresponding to this key (OUT) * @param node The pointer to the hash table internal node which stores * the key-value pair (this is required for subsequent calls * to get_next_key) (OUT) * @return PMIX error code * */ PMIX_EXPORT int pmix_hash_table_get_first_key_uint32(pmix_hash_table_t *table, uint32_t *key, void **value, void **node); /** * Get the next 32 bit key from the hash table, knowing the current key * @param table The hash table pointer (IN) * @param key The key (OUT) * @param value The value corresponding to this key (OUT) * @param in_node The node pointer from previous call to either get_first or get_next (IN) * @param out_node The pointer to the hash table internal node which stores * the key-value pair (this is required for subsequent calls * to get_next_key) (OUT) * @return PMIX error code * */ PMIX_EXPORT int pmix_hash_table_get_next_key_uint32(pmix_hash_table_t *table, uint32_t *key, void **value, void *in_node, void **out_node); /** * Get the first 64 key from the hash table, which can be used later to * get the next key * @param table The hash table pointer (IN) * @param key The first key (OUT) * @param value The value corresponding to this key (OUT) * @param node The pointer to the hash table internal node which stores * the key-value pair (this is required for subsequent calls * to get_next_key) (OUT) * @return PMIX error code * */ PMIX_EXPORT int pmix_hash_table_get_first_key_uint64(pmix_hash_table_t *table, uint64_t *key, void **value, void **node); /** * Get the next 64 bit key from the hash table, knowing the current key * @param table The hash table pointer (IN) * @param key The key (OUT) * @param value The value corresponding to this key (OUT) * @param in_node The node pointer from previous call to either get_first or get_next (IN) * @param out_node The pointer to the hash table internal node which stores * the key-value pair (this is required for subsequent calls * to get_next_key) (OUT) * @return PMIX error code * */ PMIX_EXPORT int pmix_hash_table_get_next_key_uint64(pmix_hash_table_t *table, uint64_t *key, void **value, void *in_node, void **out_node); /** * Get the first ptr bit key from the hash table, which can be used later to * get the next key * @param table The hash table pointer (IN) * @param key The first key (OUT) * @param key_size The first key size (OUT) * @param value The value corresponding to this key (OUT) * @param node The pointer to the hash table internal node which stores * the key-value pair (this is required for subsequent calls * to get_next_key) (OUT) * @return PMIX error code * */ PMIX_EXPORT int pmix_hash_table_get_first_key_ptr(pmix_hash_table_t *table, void **key, size_t *key_size, void **value, void **node); /** * Get the next ptr bit key from the hash table, knowing the current key * @param table The hash table pointer (IN) * @param key The key (OUT) * @param key_size The key size (OUT) * @param value The value corresponding to this key (OUT) * @param in_node The node pointer from previous call to either get_first or get_next (IN) * @param out_node The pointer to the hash table internal node which stores * the key-value pair (this is required for subsequent calls * to get_next_key) (OUT) * @return PMIX error code * */ PMIX_EXPORT int pmix_hash_table_get_next_key_ptr(pmix_hash_table_t *table, void **key, size_t *key_size, void **value, void *in_node, void **out_node); /** * Returns the size of the opaque pmix_hash_element_t structure. Note that this * only returns the size of the structure itself and does not capture the size * of data that are stored within an element. */ PMIX_EXPORT size_t pmix_hash_table_sizeof_hash_element(void); /** * @brief Returns next power-of-two of the given value. * * @param value The integer value to return power of 2 * * @returns The next power of two * * WARNING: *NO* error checking is performed. This is meant to be a * fast inline function. * Using __builtin_clz (count-leading-zeros) uses 4 cycles instead of 77 * compared to the loop-version (on Intel Nehalem -- with icc-12.1.0 -O2). */ static inline int pmix_next_poweroftwo(int value) { int power2; #if PMIX_C_HAVE_BUILTIN_CLZ if (PMIX_UNLIKELY(0 == value)) { return 1; } power2 = 1 << (8 * sizeof(int) - __builtin_clz(value)); #else for (power2 = 1; value > 0; value >>= 1, power2 <<= 1) /* empty */ ; #endif return power2; } /** * Loop over a hash table. * * @param[in] key Key for each item * @param[in] type Type of key (ui32|ui64|ptr) * @param[in] value Storage for each item * @param[in] ht Hash table to iterate over * * This macro provides a simple way to loop over the items in a pmix_hash_table_t. It * is not safe to call pmix_hash_table_remove* from within the loop. * * Example Usage: * * uint64_t key; * void * value; * PMIX_HASH_TABLE_FOREACH(key, uint64, value, ht) { * do_something(key, value); * } */ #define PMIX_HASH_TABLE_FOREACH(key, type, value, ht) \ for (void *_nptr = NULL; \ PMIX_SUCCESS \ == pmix_hash_table_get_next_key_##type(ht, &key, (void **) &value, _nptr, &_nptr);) #define PMIX_HASH_TABLE_FOREACH_PTR(key, value, ht, body) \ { \ size_t key_size_; \ for (void *_nptr = NULL; \ PMIX_SUCCESS \ == pmix_hash_table_get_next_key_ptr(ht, &key, &key_size_, (void **) &value, _nptr, \ &_nptr);) \ body \ } END_C_DECLS #endif /* PMIX_HASH_TABLE_H */ pmix-6.1.1~rc2/src/class/pmix_value_array.c0000664000175000017500000000421715203536752021110 0ustar alastairalastair/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2007 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "src/include/pmix_config.h" #include "src/class/pmix_value_array.h" static void pmix_value_array_construct(pmix_value_array_t *array) { array->array_items = NULL; array->array_size = 0; array->array_item_sizeof = 0; array->array_alloc_size = 0; } static void pmix_value_array_destruct(pmix_value_array_t *array) { if (NULL != array->array_items) free(array->array_items); } PMIX_CLASS_INSTANCE(pmix_value_array_t, pmix_object_t, pmix_value_array_construct, pmix_value_array_destruct); int pmix_value_array_set_size(pmix_value_array_t *array, size_t size) { #if PMIX_ENABLE_DEBUG if (array->array_item_sizeof == 0) { pmix_output(0, "pmix_value_array_set_size: item size must be initialized"); return PMIX_ERR_BAD_PARAM; } #endif if (size > array->array_alloc_size) { while (array->array_alloc_size < size) array->array_alloc_size <<= 1; array->array_items = (unsigned char *) realloc(array->array_items, array->array_alloc_size * array->array_item_sizeof); if (NULL == array->array_items) return PMIX_ERR_OUT_OF_RESOURCE; } array->array_size = size; return PMIX_SUCCESS; } pmix-6.1.1~rc2/src/class/pmix_object.h0000664000175000017500000006661315203536752020061 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2007 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2006 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * Copyright (c) 2021-2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file: * * A simple C-language object-oriented system with single inheritance * and ownership-based memory management using a retain/release model. * * A class consists of a struct and singly-instantiated class * descriptor. The first element of the struct must be the parent * class's struct. The class descriptor must be given a well-known * name based upon the class struct name (if the struct is sally_t, * the class descriptor should be sally_t_class) and must be * statically initialized as discussed below. * * (a) To define a class * * In a interface (.h) file, define the class. The first element * should always be the parent class, for example * @code * struct sally_t * { * parent_t parent; * void *first_member; * ... * }; * typedef struct sally_t sally_t; * * PMIX_CLASS_DECLARATION(sally_t); * @endcode * All classes must have a parent which is also class. * * In an implementation (.c) file, instantiate a class descriptor for * the class like this: * @code * PMIX_CLASS_INSTANCE(sally_t, parent_t, sally_construct, sally_destruct); * @endcode * This macro actually expands to * @code * pmix_class_t sally_t_class = { * "sally_t", * PMIX_CLASS(parent_t), // pointer to parent_t_class * sally_construct, * sally_destruct, * 0, 0, NULL, NULL, * sizeof ("sally_t") * }; * @endcode * This variable should be declared in the interface (.h) file using * the PMIX_CLASS_DECLARATION macro as shown above. * * sally_construct, and sally_destruct are function pointers to the * constructor and destructor for the class and are best defined as * static functions in the implementation file. NULL pointers maybe * supplied instead. * * Other class methods may be added to the struct. * * (b) Class instantiation: dynamic * * To create a instance of a class (an object) use PMIX_NEW: * @code * sally_t *sally = PMIX_NEW(sally_t); * @endcode * which allocates memory of sizeof(sally_t) and runs the class's * constructors. * * Use PMIX_RETAIN, PMIX_RELEASE to do reference-count-based * memory management: * @code * PMIX_RETAIN(sally); * PMIX_RELEASE(sally); * PMIX_RELEASE(sally); * @endcode * When the reference count reaches zero, the class's destructor, and * those of its parents, are run and the memory is freed. * * N.B. There is no explicit free/delete method for dynamic objects in * this model. * * (c) Class instantiation: static * * For an object with static (or stack) allocation, it is only * necessary to initialize the memory, which is done using * PMIX_CONSTRUCT: * @code * sally_t sally; * * PMIX_CONSTRUCT(&sally, sally_t); * @endcode * The retain/release model is not necessary here, but before the * object goes out of scope, PMIX_DESTRUCT should be run to release * initialized resources: * @code * PMIX_DESTRUCT(&sally); * @endcode */ #ifndef PMIX_OBJECT_H #define PMIX_OBJECT_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include #ifdef HAVE_STDLIB_H # include #endif /* HAVE_STDLIB_H */ #include #include #include BEGIN_C_DECLS #if PMIX_ENABLE_DEBUG /* Any kind of unique ID should do the job */ # define PMIX_OBJ_MAGIC_ID ((0xdeafbeedULL << 32) + 0xdeafbeedULL) #endif /* * Macros for variadic object instantiation: w/wout custom memory allocator. * * NOTE(skg) There is probably a nicer way to implement this functionality. In * particular, with further macro magic we can probably unify a lot of the * common code here, but that is for another day. */ /** * Takes in at least three arguments, eats all of them except the third. * This allows us to do things like: * PMIX_NEW_HAS_ARITY_HELPER(sally_t, TMA, NO_TMA, ERROR) --> NO_TMA * PMIX_NEW_HAS_ARITY_HELPER(sally_t, a_tma, TMA, NO_TMA, ERROR) --> TMA */ #define PMIX_NEW_HAS_ARITY_HELPER(_1, _2, N, ...) N #define PMIX_NEW_HAS_ARITY_IMPL(...) \ PMIX_NEW_HAS_ARITY_HELPER(__VA_ARGS__) /* * PMIX_CONSTRUCT() takes a maximum of three arguments: * Two arguments means caller does not want a custom memory allocator. * Three arguments means caller wants a custom (TMA) memory allocator. * * Please see PMIX_NEW_HAS_ARITY_HELPER's description above for more details * about how this macro functions. */ #define PMIX_CONSTRUCT_HAS_ARITY_HELPER(_1, _2, _3, N, ...) N #define PMIX_CONSTRUCT_HAS_ARITY_IMPL(...) \ PMIX_CONSTRUCT_HAS_ARITY_HELPER(__VA_ARGS__) /* * Macro suffix naming convention must be _TMA or _NO_TMA. * * These are the displacement mode lists used in the PMIX_NEW_HAS_ARITY_HELPER * example above. */ #define PMIX_NEW_HAS_ARGS_SOURCE() TMA, NO_TMA, ERROR #define PMIX_CONSTRUCT_HAS_ARGS_SOURCE() TMA, NO_TMA, ERROR, ERROR #define PMIX_OBJ_HAS_ARGS(...) \ PMIX_NEW_HAS_ARITY_IMPL(__VA_ARGS__, PMIX_NEW_HAS_ARGS_SOURCE()) #define PMIX_CONSTRUCT_HAS_ARGS(...) \ PMIX_CONSTRUCT_HAS_ARITY_IMPL(__VA_ARGS__, PMIX_CONSTRUCT_HAS_ARGS_SOURCE()) /* * These are used to generate the proper macro name and forward the relevant * arguments depending on the number of arguments used. */ #define PMIX_NEW_DISAMBIGUATE2(has_args, ...) \ PMIX_NEW_ ## has_args (__VA_ARGS__) #define PMIX_NEW_DISAMBIGUATE(has_args, ...) \ PMIX_NEW_DISAMBIGUATE2(has_args, __VA_ARGS__) #define PMIX_CONSTRUCT_DISAMBIGUATE2(has_args, ...) \ PMIX_CONSTRUCT_ ## has_args (__VA_ARGS__) #define PMIX_CONSTRUCT_DISAMBIGUATE(has_args, ...) \ PMIX_CONSTRUCT_DISAMBIGUATE2(has_args, __VA_ARGS__) /* typedefs ***********************************************************/ typedef struct pmix_object_t pmix_object_t; typedef struct pmix_class_t pmix_class_t; typedef void (*pmix_construct_t)(pmix_object_t *); typedef void (*pmix_destruct_t)(pmix_object_t *); /* types **************************************************************/ /** Memory allocator for objects */ typedef struct pmix_tma { /** Pointer to the TMA's malloc() function. */ void *(*tma_malloc)(struct pmix_tma *, size_t); /** Pointer to the TMA's calloc() function. */ void *(*tma_calloc)(struct pmix_tma *, size_t, size_t); /** Pointer to the TMA's realloc() function. */ void *(*tma_realloc)(struct pmix_tma *, void *, size_t); /* * NOTE: The seemingly unnecessary name mangling here is in response to * certain compilers not liking the use of a function pointer named strdup. */ /** Pointer to the TMA's strdup() function. */ char *(*tma_strdup)(struct pmix_tma *, const char *s); /** * A memmove()-like function that copies the provided contents to an * appropriate location in the memory area maintained by the allocator. * Like memmove(), it returns a pointer to the content's destination. */ void *(*tma_memmove)(struct pmix_tma *tma, const void *src, size_t n); /** Pointer to the TMA's free() function. */ void (*tma_free)(struct pmix_tma *, void *); /** Points to a user-defined TMA context. */ void *data_context; /** * Points to generic data used by a TMA. An example includes a pointer to a * value that maintains the next available address. */ void **data_ptr; } pmix_tma_t; static inline void *pmix_tma_malloc(pmix_tma_t *tma, size_t size) { if (NULL != tma) { return tma->tma_malloc(tma, size); } else { return malloc(size); } } static inline void *pmix_tma_calloc(pmix_tma_t *tma, size_t nmemb, size_t size) { if (NULL != tma) { return tma->tma_calloc(tma, nmemb, size); } else { return calloc(nmemb, size); } } static inline void *pmix_tma_realloc(pmix_tma_t *tma, void *ptr, size_t size) { if (NULL != tma) { return tma->tma_realloc(tma, ptr, size); } else { return realloc(ptr, size); } } static inline char *pmix_tma_strdup(pmix_tma_t *tma, const char *src) { if (NULL != tma) { return tma->tma_strdup(tma, src); } else { return strdup(src); } } static inline void pmix_tma_free(pmix_tma_t *tma, void *ptr) { if (NULL != tma) { tma->tma_free(tma, ptr); } else { free(ptr); } } /** * Class descriptor. * * There should be a single instance of this descriptor for each class * definition. */ struct pmix_class_t { const char *cls_name; /**< symbolic name for class */ pmix_class_t *cls_parent; /**< parent class descriptor */ pmix_construct_t cls_construct; /**< class constructor */ pmix_destruct_t cls_destruct; /**< class destructor */ int cls_initialized; /**< is class initialized */ int cls_depth; /**< depth of class hierarchy tree */ pmix_construct_t *cls_construct_array; /**< array of parent class constructors */ pmix_destruct_t *cls_destruct_array; /**< array of parent class destructors */ size_t cls_sizeof; /**< size of an object instance */ }; PMIX_EXPORT extern int pmix_class_init_epoch; /** * For static initializations of OBJects. * * @param NAME Name of the class to initialize */ #if PMIX_ENABLE_DEBUG # define PMIX_OBJ_STATIC_INIT(BASE_CLASS) \ { \ .obj_magic_id = PMIX_OBJ_MAGIC_ID, \ .obj_class = PMIX_CLASS(BASE_CLASS), \ .obj_lock = PTHREAD_MUTEX_INITIALIZER, \ .obj_reference_count = 1, \ .obj_tma = { \ .tma_malloc = NULL, \ .tma_calloc = NULL, \ .tma_realloc = NULL, \ .tma_strdup = NULL, \ .tma_memmove = NULL, \ .tma_free = NULL, \ .data_context = NULL, \ .data_ptr = NULL \ }, \ .cls_init_file_name = __FILE__, \ .cls_init_lineno = __LINE__ \ } #else # define PMIX_OBJ_STATIC_INIT(BASE_CLASS) \ { \ .obj_class = PMIX_CLASS(BASE_CLASS), \ .obj_lock = PTHREAD_MUTEX_INITIALIZER, \ .obj_reference_count = 1, \ .obj_tma = { \ .tma_malloc = NULL, \ .tma_calloc = NULL, \ .tma_realloc = NULL, \ .tma_strdup = NULL, \ .tma_memmove = NULL, \ .tma_free = NULL, \ .data_context = NULL, \ .data_ptr = NULL \ } \ } #endif /** * Base object. * * This is special and does not follow the pattern for other classes. */ struct pmix_object_t { #if PMIX_ENABLE_DEBUG /** Magic ID -- want this to be the very first item in the struct's memory */ uint64_t obj_magic_id; #endif pthread_mutex_t obj_lock; pmix_class_t *obj_class; /**< class descriptor */ int32_t obj_reference_count; /**< reference count */ pmix_tma_t obj_tma; /**< allocator for this object */ #if PMIX_ENABLE_DEBUG const char *cls_init_file_name; /**< In debug mode store the file where the object get constructed */ int cls_init_lineno; /**< In debug mode store the line number where the object get constructed */ #endif /* PMIX_ENABLE_DEBUG */ }; /* macros ************************************************************/ /** * Return a pointer to the class descriptor associated with a * class type. * * @param NAME Name of class * @return Pointer to class descriptor */ #define PMIX_CLASS(NAME) (&(NAME##_class)) /** * Static initializer for a class descriptor * * @param NAME Name of class * @param PARENT Name of parent class * @param CONSTRUCTOR Pointer to constructor * @param DESTRUCTOR Pointer to destructor * * Put this in NAME.c */ #define PMIX_CLASS_INSTANCE(NAME, PARENT, CONSTRUCTOR, DESTRUCTOR) \ pmix_class_t NAME##_class = {#NAME, \ PMIX_CLASS(PARENT), \ (pmix_construct_t) CONSTRUCTOR, \ (pmix_destruct_t) DESTRUCTOR, \ 0, \ 0, \ NULL, \ NULL, \ sizeof(NAME)} /** * Declaration for class descriptor * * @param NAME Name of class * * Put this in NAME.h */ #define PMIX_CLASS_DECLARATION(NAME) extern pmix_class_t NAME##_class /** * Create an object: dynamically allocate storage and run the class * constructor. * * @param type Type (class) of the object * @return Pointer to the object */ static inline pmix_object_t *pmix_obj_new_tma(pmix_class_t *cls, pmix_tma_t *tma); #if PMIX_ENABLE_DEBUG static inline pmix_object_t *pmix_obj_new_debug_tma(pmix_class_t *type, pmix_tma_t *tma, const char *file, int line) { pmix_object_t *object = pmix_obj_new_tma(type, tma); if (NULL != object) { object->obj_magic_id = PMIX_OBJ_MAGIC_ID; object->cls_init_file_name = file; object->cls_init_lineno = line; } return object; } #define PMIX_NEW_NO_TMA(type) \ ((type *)pmix_obj_new_debug_tma(PMIX_CLASS(type), NULL, __FILE__, __LINE__)) #define PMIX_NEW_TMA(type, tma) \ ((type *)pmix_obj_new_debug_tma(PMIX_CLASS(type), (tma), __FILE__, __LINE__)) #else #define PMIX_NEW_NO_TMA(type) ((type *)pmix_obj_new_tma(PMIX_CLASS(type), NULL)) #define PMIX_NEW_TMA(type, tma) ((type *)pmix_obj_new_tma(PMIX_CLASS(type), (tma))) #endif /* PMIX_ENABLE_DEBUG */ /** * PMIX_NEW() takes a maximum of two arguments: * One argument means caller does not want a custom memory allocator, namely the * common case. * Two arguments means caller wants a custom (TMA) memory allocator. */ #define PMIX_NEW(...) \ PMIX_NEW_DISAMBIGUATE(PMIX_OBJ_HAS_ARGS(__VA_ARGS__), __VA_ARGS__) /** * Retain an object (by incrementing its reference count) * * @param object Pointer to the object */ #if PMIX_ENABLE_DEBUG # define PMIX_RETAIN(object) \ do { \ assert(NULL != ((pmix_object_t *) (object))->obj_class); \ assert(PMIX_OBJ_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \ pmix_obj_update((pmix_object_t *) (object), 1); \ assert(((pmix_object_t *) (object))->obj_reference_count >= 0); \ } while (0) #else # define PMIX_RETAIN(object) pmix_obj_update((pmix_object_t *) (object), 1) #endif /** * Helper macro for the debug mode to store the locations where the status of * an object change. */ #if PMIX_ENABLE_DEBUG # define PMIX_REMEMBER_FILE_AND_LINENO(OBJECT, FILE, LINENO) \ do { \ ((pmix_object_t *) (OBJECT))->cls_init_file_name = FILE; \ ((pmix_object_t *) (OBJECT))->cls_init_lineno = LINENO; \ } while (0) # define PMIX_SET_MAGIC_ID(OBJECT, VALUE) \ do { \ ((pmix_object_t *) (OBJECT))->obj_magic_id = (VALUE); \ } while (0) #else # define PMIX_REMEMBER_FILE_AND_LINENO(OBJECT, FILE, LINENO) # define PMIX_SET_MAGIC_ID(OBJECT, VALUE) #endif /* PMIX_ENABLE_DEBUG */ /** * Release an object (by decrementing its reference count). If the * reference count reaches zero, destruct (finalize) the object and * free its storage. * * Note: If the object is freed, then the value of the pointer is set * to NULL. * * @param object Pointer to the object */ #if PMIX_ENABLE_DEBUG # define PMIX_RELEASE(object) \ do { \ pmix_object_t *_obj = (pmix_object_t *) object; \ assert(NULL != _obj->obj_class); \ assert(PMIX_OBJ_MAGIC_ID == _obj->obj_magic_id); \ if (0 == pmix_obj_update(_obj, -1)) { \ PMIX_SET_MAGIC_ID((object), 0); \ pmix_obj_run_destructors(_obj); \ PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \ if (NULL != _obj->obj_tma.tma_free) { \ pmix_tma_free(&_obj->obj_tma, object); \ } \ else { \ free(object); \ } \ object = NULL; \ } \ } while (0) #else # define PMIX_RELEASE(object) \ do { \ pmix_object_t *_obj = (pmix_object_t *) object; \ if (0 == pmix_obj_update(_obj, -1)) { \ pmix_obj_run_destructors(_obj); \ if (NULL != _obj->obj_tma.tma_free) { \ pmix_tma_free(&_obj->obj_tma, object); \ } \ else { \ free(object); \ } \ object = NULL; \ } \ } while (0) #endif /** * Construct (initialize) objects that are not dynamically allocated. * * @param object Pointer to the object * @param type The object type */ static inline void pmix_obj_construct_tma(pmix_object_t *obj, pmix_tma_t *tma) { if (NULL == tma) { obj->obj_tma.tma_malloc = NULL; obj->obj_tma.tma_calloc = NULL; obj->obj_tma.tma_realloc = NULL; obj->obj_tma.tma_strdup = NULL; obj->obj_tma.tma_memmove = NULL; obj->obj_tma.tma_free = NULL; obj->obj_tma.data_context = NULL; obj->obj_tma.data_ptr = NULL; } else { obj->obj_tma = *tma; } } #define PMIX_CONSTRUCT_INTERNAL_TMA(object, type, t) \ do { \ PMIX_SET_MAGIC_ID((object), PMIX_OBJ_MAGIC_ID); \ if (pmix_class_init_epoch != (type)->cls_initialized) { \ pmix_class_initialize((type)); \ } \ ((pmix_object_t *) (object))->obj_class = (type); \ ((pmix_object_t *) (object))->obj_reference_count = 1; \ pmix_obj_construct_tma(((pmix_object_t *) (object)), (t)); \ pmix_obj_run_constructors((pmix_object_t *) (object)); \ PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \ } while (0) #define PMIX_CONSTRUCT_TMA(object, type, t) \ do { \ PMIX_CONSTRUCT_INTERNAL_TMA((object), PMIX_CLASS(type), (t)); \ } while (0) #define PMIX_CONSTRUCT_NO_TMA(object, type) \ do { \ PMIX_CONSTRUCT_TMA(object, type, NULL); \ } while (0) #define PMIX_CONSTRUCT(...) \ PMIX_CONSTRUCT_DISAMBIGUATE(PMIX_CONSTRUCT_HAS_ARGS(__VA_ARGS__), __VA_ARGS__) /** * Destruct (finalize) an object that is not dynamically allocated. * * @param object Pointer to the object */ #if PMIX_ENABLE_DEBUG # define PMIX_DESTRUCT(object) \ do { \ assert(PMIX_OBJ_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \ PMIX_SET_MAGIC_ID((object), 0); \ pmix_obj_run_destructors((pmix_object_t *) (object)); \ PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \ } while (0) #else # define PMIX_DESTRUCT(object) \ do { \ pmix_obj_run_destructors((pmix_object_t *) (object)); \ PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \ } while (0) #endif PMIX_CLASS_DECLARATION(pmix_object_t); /* declarations *******************************************************/ /** * Lazy initialization of class descriptor. * * Specifically cache arrays of function pointers for the constructor * and destructor hierarchies for this class. * * @param class Pointer to class descriptor */ PMIX_EXPORT void pmix_class_initialize(pmix_class_t *cls); /** * Shut down the class system and release all memory * * This function should be invoked as the ABSOLUTE LAST function to * use the class subsystem. It frees all associated memory with ALL * classes, rendering all of them inoperable. It is here so that * tools like valgrind and purify don't report still-reachable memory * upon process termination. */ PMIX_EXPORT int pmix_class_finalize(void); /** * Run the hierarchy of class constructors for this object, in a * parent-first order. * * Do not use this function directly: use PMIX_CONSTRUCT() instead. * * WARNING: This implementation relies on a hardwired maximum depth of * the inheritance tree!!! * * Hardwired for fairly shallow inheritance trees * @param size Pointer to the object. */ static inline void pmix_obj_run_constructors(pmix_object_t *object) { pmix_construct_t *cls_construct; assert(NULL != object->obj_class); cls_construct = object->obj_class->cls_construct_array; while (NULL != *cls_construct) { (*cls_construct)(object); cls_construct++; } } /** * Run the hierarchy of class destructors for this object, in a * parent-last order. * * Do not use this function directly: use PMIX_DESTRUCT() instead. * * @param size Pointer to the object. */ static inline void pmix_obj_run_destructors(pmix_object_t *object) { pmix_destruct_t *cls_destruct; assert(NULL != object->obj_class); cls_destruct = object->obj_class->cls_destruct_array; while (NULL != *cls_destruct) { (*cls_destruct)(object); cls_destruct++; } } /** * Create new object: dynamically allocate storage and run the class * constructor. * * Do not use this function directly: use PMIX_NEW() instead. * * @param size Size of the object * @param cls Pointer to the class descriptor of this object * @return Pointer to the object */ static inline pmix_object_t *pmix_obj_new_tma(pmix_class_t *cls, pmix_tma_t *tma) { pmix_object_t *object; assert(cls->cls_sizeof >= sizeof(pmix_object_t)); object = (pmix_object_t *) pmix_tma_malloc(tma, cls->cls_sizeof); if (pmix_class_init_epoch != cls->cls_initialized) { pmix_class_initialize(cls); } if (NULL != object) { #if PMIX_ENABLE_DEBUG pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); /* set type to ERRORCHECK so that we catch recursive locks */ # if PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK_NP pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); # elif PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); # endif /* PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK_NP */ pthread_mutex_init(&object->obj_lock, &attr); pthread_mutexattr_destroy(&attr); #else /* Without debugging, choose the fastest available mutexes */ pthread_mutex_init(&object->obj_lock, NULL); #endif /* PMIX_ENABLE_DEBUG */ object->obj_class = cls; object->obj_reference_count = 1; if (NULL == tma) { object->obj_tma.tma_malloc = NULL; object->obj_tma.tma_calloc = NULL; object->obj_tma.tma_realloc = NULL; object->obj_tma.tma_strdup = NULL; object->obj_tma.tma_free = NULL; object->obj_tma.data_context = NULL; object->obj_tma.data_ptr = NULL; } else { object->obj_tma = *tma; } pmix_obj_run_constructors(object); } return object; } /** * Atomically update the object's reference count by some increment. * * This function should not be used directly: it is called via the * macros PMIX_RETAIN and PMIX_RELEASE * * @param object Pointer to the object * @param inc Increment by which to update reference count * @return New value of the reference count */ static inline int pmix_obj_update(pmix_object_t *object, int inc) __pmix_attribute_always_inline__; static inline int pmix_obj_update(pmix_object_t *object, int inc) { int ret = pthread_mutex_lock(&object->obj_lock); if (ret == EDEADLK) { errno = ret; perror("pthread_mutex_lock()"); abort(); } ret = (object->obj_reference_count += inc); pthread_mutex_unlock(&object->obj_lock); return ret; } /** * Get a pointer to a given object's memory allocator. Returns a pointer to the * TMA, if available. Returns NULL Otherwise. */ static inline pmix_tma_t * pmix_obj_get_tma( pmix_object_t *obj ) { // Look for a given function pointer. If it isn't NULL, then assume that // this object has a custom memory allocator. if (obj->obj_tma.tma_malloc) { return &obj->obj_tma; } return NULL; } END_C_DECLS #endif pmix-6.1.1~rc2/src/class/pmix_ring_buffer.h0000664000175000017500000000551715203536752021077 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2008 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file * */ #ifndef PMIX_RING_BUFFER_H #define PMIX_RING_BUFFER_H #include "src/include/pmix_config.h" #include "src/class/pmix_object.h" #include "src/util/pmix_output.h" BEGIN_C_DECLS /** * dynamic pointer ring */ struct pmix_ring_buffer_t { /** base class */ pmix_object_t super; /* head/tail indices */ int head; int tail; /** size of list, i.e. number of elements in addr */ int size; /** pointer to ring */ char **addr; }; /** * Convenience typedef */ typedef struct pmix_ring_buffer_t pmix_ring_buffer_t; /** * Class declaration */ PMIX_CLASS_DECLARATION(pmix_ring_buffer_t); /** * Initialize the ring buffer, defining its size. * * @param ring Pointer to a ring buffer (IN/OUT) * @param size The number of elements in the ring (IN) * * @return PMIX_SUCCESS if all initializations were successful. Otherwise, * the error indicate what went wrong in the function. */ PMIX_EXPORT int pmix_ring_buffer_init(pmix_ring_buffer_t *ring, int size); /** * Push an item onto the ring buffer, displacing the oldest * item on the ring if the ring is full * * @param ring Pointer to ring (IN) * @param ptr Pointer value (IN) * * @return Pointer to displaced item, NULL if ring * is not yet full */ PMIX_EXPORT void *pmix_ring_buffer_push(pmix_ring_buffer_t *ring, void *ptr); /** * Pop an item off of the ring. The oldest entry on the ring will be * returned. If nothing on the ring, NULL is returned. * * @param ring Pointer to ring (IN) * * @return Error code. NULL indicates an error. */ PMIX_EXPORT void *pmix_ring_buffer_pop(pmix_ring_buffer_t *ring); /* * Access an element of the ring, without removing it, indexed * starting at the tail - a value of -1 will return the element * at the head of the ring */ PMIX_EXPORT void *pmix_ring_buffer_poke(pmix_ring_buffer_t *ring, int i); END_C_DECLS #endif /* PMIX_RING_BUFFER_H */ pmix-6.1.1~rc2/src/class/pmix_pointer_array.h0000664000175000017500000001544315203536752021464 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2017 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2017 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** @file * * Utility functions to manage fortran <-> c opaque object * translation. Note that since MPI defines fortran handles as * [signed] int's, we use int everywhere in here where you would * normally expect size_t. There's some code that makes sure indices * don't go above FORTRAN_HANDLE_MAX (which is min(INT_MAX, fortran * INTEGER max)), just to be sure. */ #ifndef PMIX_POINTER_ARRAY_H #define PMIX_POINTER_ARRAY_H #include "src/include/pmix_config.h" #include "src/class/pmix_object.h" #include "src/include/pmix_prefetch.h" BEGIN_C_DECLS /** * dynamic pointer array */ struct pmix_pointer_array_t { /** base class */ pmix_object_t super; /** Index of lowest free element. NOTE: This is only an optimization to know where to search for the first free slot. It does \em not necessarily imply indices all above this index are not taken! */ int lowest_free; /** number of free elements in the list */ int number_free; /** size of list, i.e. number of elements in addr */ int size; /** maximum size of the array */ int max_size; /** block size for each allocation */ int block_size; /** pointer to an array of bits to speed up the research for an empty position. */ uint64_t *free_bits; /** pointer to array of pointers */ void **addr; }; #define PMIX_POINTER_ARRAY_STATIC_INIT \ { \ .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \ .lowest_free = 0, \ .number_free = 0, \ .size = 0, \ .max_size = 0, \ .block_size = 0, \ .free_bits = NULL, \ .addr = NULL \ } /** * Convenience typedef */ typedef struct pmix_pointer_array_t pmix_pointer_array_t; /** * Class declaration */ PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_pointer_array_t); /** * Initialize the pointer array with an initial size of initial_allocation. * Set the maximum size of the array, as well as the size of the allocation * block for all subsequent growing operations. Remarque: The pointer array * has to be created bfore calling this function. * * @param array Pointer to pointer of an array (IN/OUT) * @param initial_allocation The number of elements in the initial array (IN) * @param max_size The maximum size of the array (IN) * @param block_size The size for all subsequent grows of the array (IN). * * @return PMIX_SUCCESS if all initializations were successful. Otherwise, * the error indicate what went wrong in the function. */ PMIX_EXPORT int pmix_pointer_array_init(pmix_pointer_array_t *array, int initial_allocation, int max_size, int block_size); /** * Add a pointer to the array (Grow the array, if need be) * * @param array Pointer to array (IN) * @param ptr Pointer value (IN) * * @return Index of inserted array element. Return value of * (-1) indicates an error. */ PMIX_EXPORT int pmix_pointer_array_add(pmix_pointer_array_t *array, void *ptr); /** * Set the value of an element in array * * @param array Pointer to array (IN) * @param index Index of element to be reset (IN) * @param value New value to be set at element index (IN) * * @return Error code. (-1) indicates an error. */ PMIX_EXPORT int pmix_pointer_array_set_item(pmix_pointer_array_t *array, int index, void *value); /** * Get the value of an element in array * * @param array Pointer to array (IN) * @param element_index Index of element to be returned (IN) * * @return Error code. NULL indicates an error. */ static inline void *pmix_pointer_array_get_item(pmix_pointer_array_t *table, int element_index) { void *p; if (PMIX_UNLIKELY(0 > element_index || table->size <= element_index)) { return NULL; } p = table->addr[element_index]; return p; } /** * Get the size of the pointer array * * @param array Pointer to array (IN) * * @returns size Size of the array * * Simple inline function to return the size of the array in order to * hide the member field from external users. */ static inline int pmix_pointer_array_get_size(pmix_pointer_array_t *array) { return array->size; } /** * Set the size of the pointer array * * @param array Pointer to array (IN) * * @param size Desired size of the array * * Simple function to set the size of the array in order to * hide the member field from external users. */ PMIX_EXPORT int pmix_pointer_array_set_size(pmix_pointer_array_t *array, int size); /** * Test whether a certain element is already in use. If not yet * in use, reserve it. * * @param array Pointer to array (IN) * @param index Index of element to be tested (IN) * @param value New value to be set at element index (IN) * * @return true/false True if element could be reserved * False if element could not be reserved (e.g., in use). * * In contrary to array_set, this function does not allow to overwrite * a value, unless the previous value is NULL ( equiv. to free ). */ PMIX_EXPORT bool pmix_pointer_array_test_and_set_item(pmix_pointer_array_t *table, int index, void *value); /** * Empty the array. * * @param array Pointer to array (IN) * */ static inline void pmix_pointer_array_remove_all(pmix_pointer_array_t *array) { int i; if (array->number_free == array->size) return; /* nothing to do here this time (the array is already empty) */ array->lowest_free = 0; array->number_free = array->size; for (i = 0; i < array->size; i++) { array->addr[i] = NULL; } for (i = 0; i < (int) ((array->size + 8 * sizeof(uint64_t) - 1) / (8 * sizeof(uint64_t))); i++) { array->free_bits[i] = 0; } } END_C_DECLS #endif /* PMIX_POINTER_ARRAY_H */ pmix-6.1.1~rc2/_config.yml0000664000175000017500000000003315203536752015620 0ustar alastairalastairtheme: jekyll-theme-tactilepmix-6.1.1~rc2/configure.ac0000664000175000017500000002666015203536752015775 0ustar alastairalastair# -*- shell-script -*- # # Copyright (c) 2004-2009 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2010 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2007 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2006-2022 Cisco Systems, Inc. All rights reserved # Copyright (c) 2006-2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2006-2017 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2009 Oak Ridge National Labs. All rights reserved. # Copyright (c) 2011-2013 NVIDIA Corporation. All rights reserved. # Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013 Mellanox Technologies, Inc. # All rights reserved. # Copyright (c) 2014-2022 Intel, Inc. All rights reserved. # Copyright (c) 2016-2022 IBM Corporation. All rights reserved. # Copyright (c) 2016-2018 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021-2026 Nanook Consulting All rights reserved. # Copyright (c) 2021 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # ############################################################################ # Initialization, version number, and other random setup/init stuff ############################################################################ # Load in everything found by autogen.pl m4_include([config/autogen_found_items.m4]) # We don't have the version number to put in here yet, and we can't # call PMIX_GET_VERSION (etc.) before AC_INIT. So use the shell # version. AC_INIT([pmix],[m4_normalize(esyscmd([config/pmix_get_version.sh VERSION --tarball]))],[https://github.com/openpmix/openpmix/issues],[pmix]) AC_PREREQ([2.69]) AC_CONFIG_AUX_DIR(./config) # Note that this directory must *exactly* match what was specified via # -I in ACLOCAL_AMFLAGS in the top-level Makefile.am. AC_CONFIG_MACRO_DIRS([./config config/oac]) AC_PROG_SED PMIX_CAPTURE_CONFIGURE_CLI([PMIX_CONFIGURE_CLI]) AC_CHECK_PROG([PERL],[perl],[perl],[no]) AS_IF([test "X$PERL" = "Xno"], [AC_MSG_ERROR([OpenPMIx requires perl to build. Aborting.])]) # autotools expects to perform tests without interference # from user-provided CFLAGS, particularly -Werror flags. # Search for them here and cache any we find PMIX_CFLAGS_cache= PMIX_CFLAGS_pass= for val in $CFLAGS; do if echo "$val" | grep -q -e "-W"; then PMIX_CFLAGS_cache="$PMIX_CFLAGS_cache $val"; else PMIX_CFLAGS_pass="$PMIX_CFLAGS_pass $val"; fi done CFLAGS=$PMIX_CFLAGS_pass # Get our platform support file. This has to be done very, very early # because it twiddles random bits of autoconf PMIX_LOAD_PLATFORM PMIX_TOP_BUILDDIR="`pwd`" AC_SUBST(PMIX_TOP_BUILDDIR) top_buildir=`pwd` cd "$srcdir" PMIX_TOP_SRCDIR="`pwd`" top_srcdir=$PMIX_TOP_SRCDIR AC_SUBST(PMIX_TOP_SRCDIR) cd "$PMIX_TOP_BUILDDIR" AC_MSG_NOTICE([builddir: $PMIX_TOP_BUILDDIR]) AC_MSG_NOTICE([srcdir: $PMIX_TOP_SRCDIR]) if test "$PMIX_TOP_BUILDDIR" != "$PMIX_TOP_SRCDIR"; then AC_MSG_NOTICE([Detected VPATH build]) fi # setup configure options (e.g., show_title and friends) PMIX_CONFIGURE_SETUP pmix_show_title "Configuring PMIx" # This must be before AM_INIT_AUTOMAKE AC_CANONICAL_TARGET # Init automake AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects no-define 1.13.4 tar-pax]) # SILENT_RULES is new in AM 1.11, but we require 1.13.4 or higher via # autogen. Limited testing shows that calling SILENT_RULES directly # works in more cases than adding "silent-rules" to INIT_AUTOMAKE # (even though they're supposed to be identical). Shrug. AM_SILENT_RULES([yes]) # set the language AC_LANG([C]) # find NM AC_PROG_GREP LT_PATH_NM # AC_USE_SYSTEM_EXTENSIONS will modify CFLAGS if nothing was in there # beforehand. We don't want that. So if there was nothing in # CFLAGS, put nothing back in there. PMIX_VAR_SCOPE_PUSH([CFLAGS_save]) CFLAGS_save=$CFLAGS AC_USE_SYSTEM_EXTENSIONS AS_IF([test -z "$CFLAGS_save"], [CFLAGS=]) PMIX_VAR_SCOPE_POP # Sanity checks AC_DEFUN([PMIX_CHECK_DIR_FOR_SPACES],[ dir="$1" article="$2" label="$3" AC_MSG_CHECKING([directory of $label]) AC_MSG_RESULT([$dir]) AS_IF([test -n "`echo $dir | grep ' '`"], [AC_MSG_WARN([This version of OpenPMIx does not support $article $label]) AC_MSG_WARN([with a path that contains spaces]) AC_MSG_ERROR([Cannot continue.])]) ]) PMIX_VAR_SCOPE_PUSH(pmix_checkdir) pmix_checkdir=`pwd` PMIX_CHECK_DIR_FOR_SPACES([$pmix_checkdir], [a], [build tree]) PMIX_CHECK_DIR_FOR_SPACES([$prefix], [a], [prefix]) PMIX_CHECK_DIR_FOR_SPACES([$srcdir], [a], [source tree]) PMIX_VAR_SCOPE_POP #################################################################### # Setup the configure header files #################################################################### AH_TOP([/* -*- c -*- * * Copyright (c) 2004-2005 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. * All rights reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2013-2015 Intel, Inc. All rights reserved * Copyright (c) 2016 IBM Corporation. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * * This file is automatically generated by configure. Edits will be lost * the next time you run configure! */ #ifndef PMIX_CONFIG_H #define PMIX_CONFIG_H #include "src/include/pmix_config_top.h" ]) AH_BOTTOM([ #include "src/include/pmix_config_bottom.h" #endif /* PMIX_CONFIG_H */ ]) ############################################################################ # Setup Libtool ############################################################################ # We want new Libtool. None of that old stuff. Pfft. m4_ifdef([LT_PREREQ], [], [m4_fatal([libtool version 2.2.6 or higher is required], [63])]) LT_PREREQ([2.2.6]) # # Enable static so that we have the --with tests done up here and can # check for OS. Save the values of $enable_static and $enable_shared # before setting the defaults, because if the user specified # --[en|dis]able-[static|shared] on the command line, they'll already # be set. In this way, we can tell if the user requested something or # if the default was set here. # pmix_enable_shared="$enable_shared" pmix_enable_static="$enable_static" AS_IF([test ! -z "$enable_static" && test "$enable_static" = "yes"], [CFLAGS="$CFLAGS -fPIC"]) AC_ENABLE_SHARED([]) AC_DISABLE_STATIC([]) PMIX_SETUP_WRAPPER_INIT # This did not exist pre AM 1.11.x (where x is somewhere >0 and <3), # but it is necessary in AM 1.12.x. m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) # # Is this a developer copy? # if test -e $PMIX_TOP_SRCDIR/.git; then PMIX_DEVEL=1 else PMIX_DEVEL=0 fi # check for Flex AC_PROG_LEX(noyywrap) if test "x$LEX" != xflex && test ! -e $PMIX_TOP_SRCDIR/src/util/keyval/keyval_lex.c; then AC_MSG_WARN([*** Could not find Flex on your system.]) AC_MSG_WARN([*** Flex is required for developer builds of PMIx.]) AC_MSG_WARN([*** Other versions of Lex are not supported.]) AC_MSG_WARN([*** NOTE: If you are building from an official tarball]) AC_MSG_WARN([*** (not the ones made by GitHub!) downloaded from the]) AC_MSG_WARN([*** OpenPMIx web site, you do not need Flex.]) AC_MSG_ERROR([Cannot continue]) fi ############################################################################ # Configuration options ############################################################################ # Define PMIx configure arguments PMIX_DEFINE_ARGS # Define some basic useful values PMIX_BASIC_SETUP # If debug mode, add -g AS_IF([test "$pmix_debug" = "1"], [CFLAGS="$CFLAGS -g"]) LT_INIT() LT_LANG([C]) ############################################################################ # Setup the core ############################################################################ # Setup the pmix core PMIX_SETUP_CORE() # Run the AM_CONDITIONALs PMIX_DO_AM_CONDITIONALS #################################################################### # Setup C compiler #################################################################### AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler]) AS_IF([test -z "$CC_FOR_BUILD"],[ AC_SUBST([CC_FOR_BUILD], [$CC]) ]) # restore any user-provided Werror flags AS_IF([test ! -z "$PMIX_CFLAGS_cache"], [CFLAGS="$CFLAGS $PMIX_CFLAGS_cache"]) # setup "picky" compiler options if enabled PMIX_SETUP_PICKY_COMPILERS # # Delayed the substitution of CFLAGS and CXXFLAGS until now because # they may have been modified throughout the course of this script. # AC_SUBST(CFLAGS) AC_SUBST(CPPFLAGS) pmix_show_title "Final compiler flags" AC_MSG_CHECKING([final CPPFLAGS]) AC_MSG_RESULT([$CPPFLAGS]) AC_MSG_CHECKING([final CFLAGS]) AC_MSG_RESULT([$CFLAGS]) AC_MSG_CHECKING([final LDFLAGS]) AC_MSG_RESULT([$LDFLAGS]) AC_MSG_CHECKING([final LIBS]) AC_MSG_RESULT([$LIBS]) #################################################################### # -Werror for CI scripts #################################################################### AC_ARG_ENABLE(werror, AS_HELP_STRING([--enable-werror], [Treat compiler warnings as errors]), [ CFLAGS="$CFLAGS -Werror" ]) #################################################################### # no-undefined needed on some platform for shared lib #################################################################### AC_MSG_CHECKING([if libtool needs -no-undefined flag to build shared libraries]) case "`uname`" in CYGWIN*|MINGW*|AIX*) ## Add in the -no-undefined flag to LDFLAGS for libtool. AC_MSG_RESULT([yes]) LDFLAGS="$LDFLAGS -no-undefined" ;; *) ## Don't add in anything. AC_MSG_RESULT([no]) ;; esac #################################################################### # Version information #################################################################### # PMIX_VERSION was setup by PMIX_SETUP_CORE above. # Make configure depend on the VERSION file, since it's used in AC_INIT AC_SUBST([CONFIGURE_DEPENDENCIES], ['$(top_srcdir)/VERSION']) . $srcdir/VERSION AC_SUBST([libpmix_so_version]) AC_SUBST([libpmi_so_version]) AC_SUBST([libpmi2_so_version]) AC_CONFIG_FILES(pmix_config_prefix[contrib/Makefile] pmix_config_prefix[examples/Makefile] pmix_config_prefix[test/Makefile] pmix_config_prefix[test/python/Makefile] pmix_config_prefix[test/simple/Makefile] pmix_config_prefix[test/sshot/Makefile] pmix_config_prefix[test/util/Makefile] pmix_config_prefix[docs/Makefile] pmix_config_prefix[maint/pmix.pc]) pmix_show_title "Configuration complete" AC_OUTPUT PMIX_SUMMARY_PRINT pmix-6.1.1~rc2/test/0000775000175000017500000000000015203536752014454 5ustar alastairalastairpmix-6.1.1~rc2/test/test_server.h0000664000175000017500000000353215203536752017175 0ustar alastairalastair/* * Copyright (c) 2018 Mellanox Technologies, Inc. * All rights reserved. * * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef TEST_SERVER_C #define TEST_SERVER_C #include "pmix_server.h" #include "test_common.h" typedef enum { CMD_BARRIER_REQUEST, CMD_BARRIER_RESPONSE, CMD_FENCE_CONTRIB, CMD_FENCE_COMPLETE, CMD_DMDX_REQUEST, CMD_DMDX_RESPONSE } server_cmd_t; typedef struct { int dst_id; int src_id; int cmd; size_t size; } msg_hdr_t; struct server_info_t { pmix_list_item_t super; char *hostname; pid_t pid; int idx; int rd_fd; int wr_fd; pmix_event_t *evread; pmix_lock_t lock; pmix_modex_cbfunc_t modex_cbfunc; void *cbdata; }; typedef struct server_info_t server_info_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(server_info_t); struct server_nspace_t { pmix_list_item_t super; char name[PMIX_MAX_NSLEN + 1]; size_t ntasks; /* total number of tasks in this namespace */ size_t ltasks; /* local */ int *task_map; }; typedef struct server_nspace_t server_nspace_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(server_nspace_t); extern int my_server_id; extern pmix_list_t *server_list; extern server_info_t *my_server_info; extern pmix_list_t *server_nspace; int server_init(test_params *params); int server_finalize(test_params *params, int local_fail); int server_barrier(void); int server_fence_contrib(char *data, size_t ndata, pmix_modex_cbfunc_t cbfunc, void *cbdata); int server_dmdx_get(const char *nspace, int rank, pmix_modex_cbfunc_t cbfunc, void *cbdata); int server_launch_clients(int local_size, int univ_size, int base_rank, test_params *params, char ***client_env, char ***base_argv); #endif // TEST_SERVER_C pmix-6.1.1~rc2/test/test_cd.c0000664000175000017500000000443115203536752016247 0ustar alastairalastair/* * Copyright (c) 2015-2019 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "test_cd.h" #include typedef struct { int in_progress; int status; pmix_proc_t pname; } cd_cbdata; static void cd_cb(pmix_status_t status, void *cbdata) { cd_cbdata *cb = (cd_cbdata *) cbdata; cb->status = status; cb->in_progress = 0; } static void cnct_cb(pmix_status_t status, void *cbdata) { cd_cbdata *cb = (cd_cbdata *) cbdata; cb->status = status; cb->in_progress = 0; } int test_connect_disconnect(char *my_nspace, int my_rank) { int rc; pmix_proc_t proc; cd_cbdata cbdata; pmix_strncpy(proc.nspace, my_nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; rc = PMIx_Connect(&proc, 1, NULL, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: Connect blocking test failed.", my_nspace, my_rank)); exit(PMIX_ERROR); } TEST_VERBOSE(("%s:%d: Connect blocking test succeeded", my_nspace, my_rank)); rc = PMIx_Disconnect(&proc, 1, NULL, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: Disconnect blocking test failed.", my_nspace, my_rank)); exit(PMIX_ERROR); } TEST_VERBOSE(("%s:%d: Disconnect blocking test succeeded.", my_nspace, my_rank)); cbdata.in_progress = 1; rc = PMIx_Connect_nb(&proc, 1, NULL, 0, cnct_cb, &cbdata); if (PMIX_SUCCESS == rc) { PMIX_WAIT_FOR_COMPLETION(cbdata.in_progress); rc = cbdata.status; } if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: Connect non-blocking test failed.", my_nspace, my_rank)); exit(PMIX_ERROR); } TEST_VERBOSE(("%s:%d: Connect non-blocking test succeeded.", my_nspace, my_rank)); cbdata.in_progress = 1; rc = PMIx_Disconnect_nb(&proc, 1, NULL, 0, cd_cb, &cbdata); if (PMIX_SUCCESS == rc) { PMIX_WAIT_FOR_COMPLETION(cbdata.in_progress); rc = cbdata.status; } if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: Disconnect non-blocking test failed.", my_nspace, my_rank)); exit(PMIX_ERROR); } TEST_VERBOSE(("%s:%d: Disconnect non-blocking test succeeded.", my_nspace, my_rank)); return PMIX_SUCCESS; } pmix-6.1.1~rc2/test/test_fence.h0000664000175000017500000000107415203536752016746 0ustar alastairalastair/* * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "test_common.h" #include int test_fence(test_params params, char *my_nspace, pmix_rank_t my_rank); int test_job_fence(test_params params, char *my_nspace, pmix_rank_t my_rank); pmix-6.1.1~rc2/test/server_callbacks.h0000664000175000017500000000515215203536752020135 0ustar alastairalastair/* * Copyright (c) 2015-2018 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef PMIX_SERVER_CALLBACK_H #define PMIX_SERVER_CALLBACK_H #include "cli_stages.h" pmix_status_t connected(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata); pmix_status_t finalized(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata); pmix_status_t abort_fn(const pmix_proc_t *proc, void *server_object, int status, const char msg[], pmix_proc_t procs[], size_t nprocs, pmix_op_cbfunc_t cbfunc, void *cbdata); pmix_status_t fencenb_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, char *data, size_t ndata, pmix_modex_cbfunc_t cbfunc, void *cbdata); pmix_status_t dmodex_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_modex_cbfunc_t cbfunc, void *cbdata); pmix_status_t publish_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); pmix_status_t lookup_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_lookup_cbfunc_t cbfunc, void *cbdata); pmix_status_t unpublish_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); pmix_status_t spawn_fn(const pmix_proc_t *proc, const pmix_info_t job_info[], size_t ninfo, const pmix_app_t apps[], size_t napps, pmix_spawn_cbfunc_t cbfunc, void *cbdata); pmix_status_t connect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); pmix_status_t disconnect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); pmix_status_t regevents_fn(pmix_status_t *codes, size_t ncodes, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); pmix_status_t deregevents_fn(pmix_status_t *codes, size_t ncodes, pmix_op_cbfunc_t cbfunc, void *cbdata); extern pmix_server_module_t mymodule; #endif pmix-6.1.1~rc2/test/test_cd.h0000664000175000017500000000044215203536752016252 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "test_common.h" int test_connect_disconnect(char *my_nspace, int my_rank); pmix-6.1.1~rc2/test/test_replace.h0000664000175000017500000000063215203536752017300 0ustar alastairalastair/* * Copyright (c) 2017 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2020 Intel, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "test_common.h" int test_replace(char *my_nspace, pmix_rank_t my_rank, test_params params); pmix-6.1.1~rc2/test/README0000664000175000017500000000422315203536752015335 0ustar alastairalastairThis is a short description how to run tests for pmix standalone library. To compile test the user should run make in the test subdirectory. To start testing, the user should run either pmix_test or pmix_test_lite executable. These applications are using two different versions of server functionality and fork client process which implementation is located in the pmix_client.c file. There are several command line options (available to see by -h argument). The main options are the following: --job-fence - run fence operation between processes from the same namespace. It has some additional parameters: -c - this fence should include data exchange (collective modex). Direct modex (no data exchange) is done by default. -nb - fence should be non-blocking (blocking by default). --fence "[ | ns0:ranks;ns1:ranks...][...]" - run multiple fences (each fence in square brackets) with different configurations in parsable format. Example: --fence "[db | 1:1,2 ; 2:3-6][1: ]" means that need to test two fences. The first one is blocking (b) and with data exchange (d) including ranks 1,2 from namespace 1 and ranks 3-6 from namespace 2. The second fence is non-blocking without data exchange including all processes from namespace 1. The assumption is that ranks should be set in increasing order (no same ranks in the different namespaces). It also has additional parameters: --noise "[ns0:ranks;ns1:ranks...]" - imitate system noise on certain ranks. It has similar to --fence format [0:0;1:1-3] to specify ranks which should sleep several seconds before doing fence test. --use-same-keys - put the same keys in the interim between multiple fences. --ns-dist "n1:n2:n3" register n namespaces (3 in this example) each with ni ranks (n1, n2 or n3). For example, --ns-dist 1:2:8 says server to register 3 namespaces: 1 proc in the 1st ns, 2 procs in the 2d ns, 8 procs in the 3d. --test-publish - test publish/lookup/unpublish api. --test-spawn - test spawn api. --test-connect - test connect/disconnect api. --test-resolve-peers - test resolve_peers api. File cmd_examples contains some command lines to test the main functionality. pmix-6.1.1~rc2/test/test_server.c0000664000175000017500000010370315203536752017171 0ustar alastairalastair/* * Copyright (c) 2015-2019 Intel, Inc. All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * Copyright (c) 2023 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #define _GNU_SOURCE #include #include #include #include #include #include #include "pmix_server.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_error.h" #include "src/util/pmix_printf.h" #include "cli_stages.h" #include "server_callbacks.h" #include "test_common.h" #include "test_server.h" int my_server_id = 0; static uint32_t nsession = 0; server_info_t *my_server_info = NULL; pmix_list_t *server_list = NULL; pmix_list_t *server_nspace = NULL; static void sdes(server_info_t *s) { close(s->rd_fd); close(s->wr_fd); if (s->evread) { pmix_event_del(s->evread); } s->evread = NULL; if (NULL != s->hostname) { free(s->hostname); } } static void scon(server_info_t *s) { s->hostname = NULL; s->idx = 0; s->pid = 0; s->rd_fd = -1; s->wr_fd = -1; s->evread = NULL; s->modex_cbfunc = NULL; s->cbdata = NULL; } PMIX_CLASS_INSTANCE(server_info_t, pmix_list_item_t, scon, sdes); static void nsdes(server_nspace_t *ns) { if (ns->task_map) { free(ns->task_map); } } static void nscon(server_nspace_t *ns) { memset(ns->name, 0, sizeof(ns->name)); ns->ntasks = 0; ns->ltasks = 0; ns->task_map = NULL; } PMIX_CLASS_INSTANCE(server_nspace_t, pmix_list_item_t, nscon, nsdes); static int server_send_procs(void); static void server_read_cb(int fd, short event, void *arg); static int srv_wait_all(double timeout); static int server_fwd_msg(msg_hdr_t *msg_hdr, char *buf, size_t size); static int server_send_msg(msg_hdr_t *msg_hdr, char *data, size_t size); static void remove_server_item(server_info_t *server); static void server_unpack_dmdx(char *buf, int *sender, pmix_proc_t *proc); static int server_pack_dmdx(int sender_id, const char *nspace, int rank, char **buf); static void _dmdx_cb(int status, char *data, size_t sz, void *cbdata); static void release_cb(pmix_status_t status, void *cbdata) { int *ptr = (int *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); *ptr = 0; } static void fill_seq_ranks_array(size_t nprocs, int base_rank, char **ranks) { uint32_t i; int len = 0, max_ranks_len; int remaining; if (0 >= nprocs) { return; } max_ranks_len = nprocs * (MAX_DIGIT_LEN + 1); *ranks = (char *) malloc(max_ranks_len); if (NULL == *ranks) { TEST_ERROR(("Failed to allocate memory for global ranks array.")); return; } remaining = max_ranks_len; for (i = 0; i < nprocs; i++) { int n = snprintf(*ranks + len, remaining, "%d", i + base_rank); if (n < 0 || n >= remaining) { free(*ranks); *ranks = NULL; TEST_ERROR(("Not enough allocated space for global ranks array.")); return; } len += n; remaining -= n; if (i != nprocs - 1) { n = snprintf(*ranks + len, remaining, "%c", ','); if (n < 0 || n >= remaining) { free(*ranks); *ranks = NULL; TEST_ERROR(("Not enough allocated space for global ranks array.")); return; } len += n; remaining -= n; } } if (len >= max_ranks_len - 1) { free(*ranks); *ranks = NULL; TEST_ERROR(("Not enough allocated space for global ranks array.")); } } static int server_find_id(const char *nspace, int rank) { server_nspace_t *tmp; PMIX_LIST_FOREACH (tmp, server_nspace, server_nspace_t) { if (0 == strcmp(tmp->name, nspace)) { return tmp->task_map[rank]; } } return -1; } static void set_namespace(int local_size, int univ_size, int base_rank, char *name, test_params *params) { size_t ninfo; pmix_info_t *info; ninfo = 9; char *regex, *ppn, *tmp; char *ranks = NULL, **nodes = NULL; char **rks = NULL; int i; int rc; uint32_t value; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_SESSION_ID, &nsession, PMIX_UINT32); ++nsession; PMIX_INFO_LOAD(&info[1], PMIX_UNIV_SIZE, &univ_size, PMIX_UINT32); value = 0; PMIX_INFO_LOAD(&info[2], PMIX_SPAWNED, &value, PMIX_UINT32); value = local_size; PMIX_INFO_LOAD(&info[3], PMIX_LOCAL_SIZE, &value, PMIX_UINT32); /* generate the array of local peers */ fill_seq_ranks_array(local_size, base_rank, &ranks); if (NULL == ranks) { return; } PMIX_INFO_LOAD(&info[4], PMIX_LOCAL_PEERS, ranks,PMIX_STRING); /* assemble the node and proc map info */ if (1 == params->nservers) { PMIx_Argv_append_nosize(&nodes, my_server_info->hostname); } else { char hostname[PMIX_MAXHOSTNAMELEN]; for (i = 0; i < params->nservers; i++) { snprintf(hostname, PMIX_MAXHOSTNAMELEN, "node%d", i); PMIx_Argv_append_nosize(&nodes, hostname); } } if (NULL != nodes) { tmp = PMIx_Argv_join(nodes, ','); PMIx_Argv_free(nodes); nodes = NULL; if (PMIX_SUCCESS != (rc = PMIx_generate_regex(tmp, ®ex))) { PMIX_ERROR_LOG(rc); return; } free(tmp); PMIX_INFO_LOAD(&info[5], PMIX_NODE_MAP, regex, PMIX_REGEX); } /* generate the global proc map - if we have two * servers, then the procs not on this server must * be on the other */ if (2 == params->nservers) { PMIx_Argv_append_nosize(&rks, ranks); free(ranks); nodes = NULL; if (0 == my_server_id) { for (i = base_rank + local_size; i < univ_size; i++) { pmix_asprintf(&ppn, "%d", i); PMIx_Argv_append_nosize(&nodes, ppn); free(ppn); } ppn = PMIx_Argv_join(nodes, ','); PMIx_Argv_append_nosize(&rks, ppn); free(ppn); } else { for (i = 0; i < base_rank; i++) { pmix_asprintf(&ppn, "%d", i); PMIx_Argv_append_nosize(&nodes, ppn); free(ppn); } ppn = PMIx_Argv_join(nodes, ','); PMIx_Argv_prepend_nosize(&rks, ppn); free(ppn); } ranks = PMIx_Argv_join(rks, ';'); } PMIx_generate_ppn(ranks, &ppn); free(ranks); PMIX_INFO_LOAD(&info[6], PMIX_PROC_MAP, ppn, PMIX_REGEX); free(ppn); value = univ_size; PMIX_INFO_LOAD(&info[7], PMIX_JOB_SIZE, &value, PMIX_UINT32); value = getpid(); PMIX_INFO_LOAD(&info[8], PMIX_APPNUM, &value, PMIX_UINT32); int in_progress = 1; if (PMIX_SUCCESS == (rc = PMIx_server_register_nspace(name, local_size, info, ninfo, release_cb, &in_progress))) { PMIX_WAIT_FOR_COMPLETION(in_progress); } PMIX_INFO_FREE(info, ninfo); } static void server_unpack_procs(char *buf, size_t size) { char *ptr = buf; size_t i, j; size_t ns_count; char *nspace; while ((size_t)(ptr - buf) < size) { memcpy(&ns_count, ptr, sizeof(size_t)); ptr += sizeof(size_t); for (i = 0; i < ns_count; i++) { server_nspace_t *tmp, *ns_item = NULL; size_t ltasks, ntasks; int server_id; memcpy(&server_id, ptr, sizeof(int)); ptr += sizeof(int); nspace = ptr; ptr += PMIX_MAX_NSLEN + 1; memcpy(&ntasks, ptr, sizeof(size_t)); ptr += sizeof(size_t); memcpy(<asks, ptr, sizeof(size_t)); ptr += sizeof(size_t); PMIX_LIST_FOREACH (tmp, server_nspace, server_nspace_t) { if (0 == strcmp(nspace, tmp->name)) { ns_item = tmp; break; } } if (NULL == ns_item) { ns_item = PMIX_NEW(server_nspace_t); memcpy(ns_item->name, nspace, PMIX_MAX_NSLEN); pmix_list_append(server_nspace, &ns_item->super); ns_item->ltasks = ltasks; ns_item->ntasks = ntasks; ns_item->task_map = (int *) malloc(sizeof(int) * ntasks); memset(ns_item->task_map, -1, sizeof(int) * ntasks); } else { assert(ns_item->ntasks == ntasks); } for (j = 0; j < ltasks; j++) { int rank; memcpy(&rank, ptr, sizeof(int)); ptr += sizeof(int); if (ns_item->task_map[rank] >= 0) { continue; } ns_item->task_map[rank] = server_id; } } } } static size_t server_pack_procs(int server_id, char **buf, size_t size) { size_t ns_count = pmix_list_get_size(server_nspace); size_t buf_size = sizeof(size_t) + (PMIX_MAX_NSLEN + 1) * ns_count; server_nspace_t *tmp; char *ptr; if (0 == ns_count) { return 0; } buf_size += size; /* compute size: server_id + total + local procs count + ranks */ PMIX_LIST_FOREACH (tmp, server_nspace, server_nspace_t) { buf_size += sizeof(int) + sizeof(size_t) + sizeof(size_t) + sizeof(int) * tmp->ltasks; } *buf = (char *) realloc(*buf, buf_size); memset(*buf + size, 0, buf_size); ptr = *buf + size; /* pack ns count */ memcpy(ptr, &ns_count, sizeof(size_t)); ptr += sizeof(size_t); assert(server_nspace->pmix_list_length); PMIX_LIST_FOREACH (tmp, server_nspace, server_nspace_t) { size_t i; /* pack server_id */ memcpy(ptr, &server_id, sizeof(int)); ptr += sizeof(int); /* pack ns name */ memcpy(ptr, tmp->name, PMIX_MAX_NSLEN + 1); ptr += PMIX_MAX_NSLEN + 1; /* pack ns total size */ memcpy(ptr, &tmp->ntasks, sizeof(size_t)); ptr += sizeof(size_t); /* pack ns local size */ memcpy(ptr, &tmp->ltasks, sizeof(size_t)); ptr += sizeof(size_t); /* pack ns ranks */ for (i = 0; i < tmp->ntasks; i++) { if (tmp->task_map[i] == server_id) { int rank = (int) i; memcpy(ptr, &rank, sizeof(int)); ptr += sizeof(int); } } } assert((size_t)(ptr - *buf) == buf_size); return buf_size; } static void remove_server_item(server_info_t *server) { pmix_list_remove_item(server_list, &server->super); PMIX_DESTRUCT_LOCK(&server->lock); PMIX_RELEASE(server); } static int srv_wait_all(double timeout) { server_info_t *server, *next; pid_t pid; int status; struct timeval tv; double start_time, cur_time; int ret = 0; gettimeofday(&tv, NULL); start_time = tv.tv_sec + 1E-6 * tv.tv_usec; cur_time = start_time; /* Remove this server from the list */ PMIX_LIST_FOREACH_SAFE (server, next, server_list, server_info_t) { if (server->pid == getpid()) { /* remove himself */ remove_server_item(server); break; } } while (!pmix_list_is_empty(server_list) && (timeout >= (cur_time - start_time))) { pid = waitpid(-1, &status, 0); if (pid >= 0) { PMIX_LIST_FOREACH_SAFE (server, next, server_list, server_info_t) { if (server->pid == pid) { TEST_VERBOSE(("server %d finalize PID:%d with status %d", server->idx, server->pid, WEXITSTATUS(status))); ret += WEXITSTATUS(status); remove_server_item(server); } } } // calculate current timestamp gettimeofday(&tv, NULL); cur_time = tv.tv_sec + 1E-6 * tv.tv_usec; } return ret; } static int server_fwd_msg(msg_hdr_t *msg_hdr, char *buf, size_t size) { server_info_t *tmp_server, *server = NULL; int rc = PMIX_SUCCESS; PMIX_LIST_FOREACH (tmp_server, server_list, server_info_t) { if (tmp_server->idx == msg_hdr->dst_id) { server = tmp_server; break; } } if (NULL == server) { return PMIX_ERROR; } rc = write(server->wr_fd, msg_hdr, sizeof(msg_hdr_t)); if (rc != sizeof(msg_hdr_t)) { return PMIX_ERROR; } rc = write(server->wr_fd, buf, size); if (rc != (ssize_t) size) { return PMIX_ERROR; } return PMIX_SUCCESS; } static int server_send_msg(msg_hdr_t *msg_hdr, char *data, size_t size) { size_t ret = 0; server_info_t *server = NULL, *server_tmp; if (0 == my_server_id) { PMIX_LIST_FOREACH (server_tmp, server_list, server_info_t) { if (server_tmp->idx == msg_hdr->dst_id) { server = server_tmp; break; } } if (NULL == server) { abort(); } } else { server = (server_info_t *) pmix_list_get_first(server_list); } ret += write(server->wr_fd, msg_hdr, sizeof(msg_hdr_t)); ret += write(server->wr_fd, data, size); if (ret != (sizeof(*msg_hdr) + size)) { return PMIX_ERROR; } return PMIX_SUCCESS; } static void _send_procs_cb(pmix_status_t status, const char *data, size_t ndata, void *cbdata, pmix_release_cbfunc_t relfn, void *relcbd) { PMIX_HIDE_UNUSED_PARAMS(status, relfn, relcbd); server_info_t *server = (server_info_t *) cbdata; server_unpack_procs((char *) data, ndata); free((char *) data); PMIX_WAKEUP_THREAD(&server->lock); } static int server_send_procs(void) { server_info_t *server; msg_hdr_t msg_hdr; memset(&msg_hdr, 0, sizeof(msg_hdr)); int rc = PMIX_SUCCESS; char *buf = NULL; if (0 == my_server_id) { server = my_server_info; } else { server = (server_info_t *) pmix_list_get_first(server_list); } msg_hdr.cmd = CMD_FENCE_CONTRIB; msg_hdr.dst_id = 0; msg_hdr.src_id = my_server_id; msg_hdr.size = server_pack_procs(my_server_id, &buf, 0); server->modex_cbfunc = _send_procs_cb; server->cbdata = (void *) server; server->lock.active = true; if (PMIX_SUCCESS != (rc = server_send_msg(&msg_hdr, buf, msg_hdr.size))) { if (buf) { free(buf); } return PMIX_ERROR; } if (buf) { free(buf); } PMIX_WAIT_THREAD(&server->lock); return PMIX_SUCCESS; } int server_barrier(void) { server_info_t *server; msg_hdr_t msg_hdr; memset(&msg_hdr, 0, sizeof(msg_hdr)); int rc = PMIX_SUCCESS; if (0 == my_server_id) { server = my_server_info; } else { server = (server_info_t *) pmix_list_get_first(server_list); } msg_hdr.cmd = CMD_BARRIER_REQUEST; msg_hdr.dst_id = 0; msg_hdr.src_id = my_server_id; msg_hdr.size = 0; server->lock.active = true; if (PMIX_SUCCESS != (rc = server_send_msg(&msg_hdr, NULL, 0))) { return PMIX_ERROR; } PMIX_WAIT_THREAD(&server->lock); return PMIX_SUCCESS; } static void _libpmix_cb(void *cbdata) { char *ptr = (char *) cbdata; if (ptr) { free(ptr); } } static void server_read_cb(int fd, short event, void *arg) { server_info_t *server = (server_info_t *) arg; msg_hdr_t msg_hdr; memset(&msg_hdr, 0, sizeof(msg_hdr)); char *msg_buf = NULL; static char *fence_buf = NULL; int rc; static size_t barrier_cnt = 0; static size_t contrib_cnt = 0; static size_t fence_buf_offset = 0; PMIX_HIDE_UNUSED_PARAMS(fd, event); rc = read(server->rd_fd, &msg_hdr, sizeof(msg_hdr_t)); if (rc <= 0) { return; } if (msg_hdr.size) { msg_buf = (char *) malloc(sizeof(char) * msg_hdr.size); rc += read(server->rd_fd, msg_buf, msg_hdr.size); } if (rc != (int) (sizeof(msg_hdr_t) + msg_hdr.size)) { TEST_ERROR(("error read from %d", server->idx)); } if (my_server_id != msg_hdr.dst_id) { server_fwd_msg(&msg_hdr, msg_buf, msg_hdr.size); free(msg_buf); return; } switch (msg_hdr.cmd) { case CMD_BARRIER_REQUEST: barrier_cnt++; TEST_VERBOSE( ("CMD_BARRIER_REQ req from %d cnt %lu", msg_hdr.src_id, (unsigned long) barrier_cnt)); if (pmix_list_get_size(server_list) == barrier_cnt) { barrier_cnt = 0; /* reset barrier counter */ server_info_t *tmp_server; PMIX_LIST_FOREACH (tmp_server, server_list, server_info_t) { msg_hdr_t resp_hdr; memset(&resp_hdr, 0, sizeof(resp_hdr)); resp_hdr.dst_id = tmp_server->idx; resp_hdr.src_id = my_server_id; resp_hdr.cmd = CMD_BARRIER_RESPONSE; resp_hdr.size = 0; server_send_msg(&resp_hdr, NULL, 0); } } break; case CMD_BARRIER_RESPONSE: TEST_VERBOSE(("%d: CMD_BARRIER_RESP", my_server_id)); PMIX_WAKEUP_THREAD(&server->lock); break; case CMD_FENCE_CONTRIB: contrib_cnt++; if (msg_hdr.size > 0) { fence_buf = (char *) realloc((void *) fence_buf, fence_buf_offset + msg_hdr.size); memcpy(fence_buf + fence_buf_offset, msg_buf, msg_hdr.size); fence_buf_offset += msg_hdr.size; free(msg_buf); msg_buf = NULL; } TEST_VERBOSE(("CMD_FENCE_CONTRIB req from %d cnt %lu size %lu", msg_hdr.src_id, (unsigned long) contrib_cnt, (unsigned long)msg_hdr.size)); if (pmix_list_get_size(server_list) == contrib_cnt) { server_info_t *tmp_server; PMIX_LIST_FOREACH (tmp_server, server_list, server_info_t) { msg_hdr_t resp_hdr; memset(&resp_hdr, 0, sizeof(resp_hdr)); resp_hdr.dst_id = tmp_server->idx; resp_hdr.src_id = my_server_id; resp_hdr.cmd = CMD_FENCE_COMPLETE; resp_hdr.size = fence_buf_offset; server_send_msg(&resp_hdr, fence_buf, fence_buf_offset); } TEST_VERBOSE( ("CMD_FENCE_CONTRIB complete, size %lu", (unsigned long) fence_buf_offset)); if (fence_buf) { free(fence_buf); fence_buf = NULL; fence_buf_offset = 0; } contrib_cnt = 0; } break; case CMD_FENCE_COMPLETE: TEST_VERBOSE(("%d: CMD_FENCE_COMPLETE size %lu", my_server_id, msg_hdr.size)); server->modex_cbfunc(PMIX_SUCCESS, msg_buf, (int)msg_hdr.size, server->cbdata, _libpmix_cb, msg_buf); msg_buf = NULL; break; case CMD_DMDX_REQUEST: { int *sender_id; pmix_proc_t proc; if (NULL == msg_buf) { abort(); } sender_id = (int *) malloc(sizeof(int)); server_unpack_dmdx(msg_buf, sender_id, &proc); TEST_VERBOSE(("%d: CMD_DMDX_REQUEST from %d: %s:%d", my_server_id, *sender_id, proc.nspace, proc.rank)); rc = PMIx_server_dmodex_request(&proc, _dmdx_cb, (void *) sender_id); break; } case CMD_DMDX_RESPONSE: TEST_VERBOSE(("%d: CMD_DMDX_RESPONSE", my_server_id)); server->modex_cbfunc(PMIX_SUCCESS, msg_buf, msg_hdr.size, server->cbdata, _libpmix_cb, msg_buf); msg_buf = NULL; break; } if (NULL != msg_buf) { free(msg_buf); } } int server_fence_contrib(char *data, size_t ndata, pmix_modex_cbfunc_t cbfunc, void *cbdata) { server_info_t *server; msg_hdr_t msg_hdr; memset(&msg_hdr, 0, sizeof(msg_hdr)); int rc = PMIX_SUCCESS; if (0 == my_server_id) { server = my_server_info; } else { server = (server_info_t *) pmix_list_get_first(server_list); } msg_hdr.cmd = CMD_FENCE_CONTRIB; msg_hdr.dst_id = 0; msg_hdr.src_id = my_server_id; msg_hdr.size = ndata; server->modex_cbfunc = cbfunc; server->cbdata = cbdata; if (PMIX_SUCCESS != (rc = server_send_msg(&msg_hdr, data, ndata))) { return PMIX_ERROR; } return rc; } static int server_pack_dmdx(int sender_id, const char *nspace, int rank, char **buf) { size_t buf_size = sizeof(int) + PMIX_MAX_NSLEN + 1 + sizeof(int); char *ptr; *buf = (char *) malloc(buf_size); ptr = *buf; memcpy(ptr, &sender_id, sizeof(int)); ptr += sizeof(int); memcpy(ptr, nspace, PMIX_MAX_NSLEN + 1); ptr += PMIX_MAX_NSLEN + 1; memcpy(ptr, &rank, sizeof(int)); ptr += sizeof(int); return buf_size; } static void server_unpack_dmdx(char *buf, int *sender, pmix_proc_t *proc) { char *ptr = buf; *sender = *(int *) ptr; ptr += sizeof(int); memcpy(proc->nspace, ptr, PMIX_MAX_NSLEN + 1); ptr += PMIX_MAX_NSLEN + 1; proc->rank = *(int *) ptr; ptr += sizeof(int); } static void _dmdx_cb(int status, char *data, size_t sz, void *cbdata) { msg_hdr_t msg_hdr; memset(&msg_hdr, 0, sizeof(msg_hdr)); int *sender_id = (int *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); msg_hdr.cmd = CMD_DMDX_RESPONSE; msg_hdr.src_id = my_server_id; msg_hdr.size = sz; msg_hdr.dst_id = *sender_id; TEST_VERBOSE(("srv #%d: DMDX RESPONSE: receiver=%d, size=%lu,", my_server_id, *sender_id, (unsigned long) sz)); free(sender_id); server_send_msg(&msg_hdr, data, sz); } int server_dmdx_get(const char *nspace, int rank, pmix_modex_cbfunc_t cbfunc, void *cbdata) { server_info_t *server = NULL, *tmp; msg_hdr_t msg_hdr; memset(&msg_hdr, 0, sizeof(msg_hdr)); pmix_status_t rc = PMIX_SUCCESS; char *buf = NULL; if (0 > (msg_hdr.dst_id = server_find_id(nspace, rank))) { TEST_ERROR(("%d: server cannot found for %s:%d", my_server_id, nspace, rank)); goto error; } if (0 == my_server_id) { PMIX_LIST_FOREACH (tmp, server_list, server_info_t) { if (tmp->idx == msg_hdr.dst_id) { server = tmp; break; } } } else { server = (server_info_t *) pmix_list_get_first(server_list); } if (server == NULL) { goto error; } msg_hdr.cmd = CMD_DMDX_REQUEST; msg_hdr.src_id = my_server_id; msg_hdr.size = server_pack_dmdx(my_server_id, nspace, rank, &buf); server->modex_cbfunc = cbfunc; server->cbdata = cbdata; if (PMIX_SUCCESS != (rc = server_send_msg(&msg_hdr, buf, msg_hdr.size))) { rc = PMIX_ERROR; } free(buf); return rc; error: cbfunc(PMIX_ERROR, NULL, 0, cbdata, NULL, 0); return PMIX_ERROR; } static void set_handler_default(int sig) { struct sigaction act; act.sa_handler = SIG_DFL; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(sig, &act, (struct sigaction *) 0); } static pmix_event_t handler; static void wait_signal_callback(int fd, short event, void *arg) { pmix_event_t *sig = (pmix_event_t *) arg; int status; pid_t pid; int i; PMIX_HIDE_UNUSED_PARAMS(fd, event); if (SIGCHLD != pmix_event_get_signal(sig)) { return; } /* we can have multiple children leave but only get one * sigchild callback, so reap all the waitpids until we * don't get anything valid back */ while (1) { pid = waitpid(-1, &status, WNOHANG); if (-1 == pid && EINTR == errno) { /* try it again */ continue; } /* if we got garbage, then nothing we can do */ if (pid <= 0) { goto done; } /* we are already in an event, so it is safe to access the list */ for (i = 0; i < cli_info_cnt; i++) { if (cli_info[i].pid == pid) { /* found it! */ if (WIFEXITED(status)) { cli_info[i].exit_code = WEXITSTATUS(status); } else { if (WIFSIGNALED(status)) { cli_info[i].exit_code = WTERMSIG(status) + 128; } } cli_cleanup(&cli_info[i]); cli_info[i].alive = false; break; } } } done: for (i = 0; i < cli_info_cnt; i++) { if (cli_info[i].alive) { /* someone is still alive */ return; } } /* get here if nobody is still alive */ test_complete = true; } int server_init(test_params *params) { pmix_info_t info[2]; int rc = PMIX_SUCCESS; /* fork/init servers procs */ if (params->nservers >= 1) { int i; server_info_t *server_info = NULL; server_list = PMIX_NEW(pmix_list_t); TEST_VERBOSE(("pmix server %d started PID:%d", my_server_id, getpid())); for (i = params->nservers - 1; i >= 0; i--) { int ret; pid_t pid; server_info = PMIX_NEW(server_info_t); int fd1[2]; int fd2[2]; ret = pipe(fd1); if (ret != 0) { TEST_ERROR(("pipe failed")); return -1; } ret = pipe(fd2); if (ret != 0) { TEST_ERROR(("pipe failed")); return -1; } if (0 != i) { pid = fork(); if (pid < 0) { TEST_ERROR(("Fork failed")); return pid; } if (pid == 0) { server_list = PMIX_NEW(pmix_list_t); my_server_info = server_info; my_server_id = i; pmix_asprintf(&server_info->hostname, "node%d", i); server_info->idx = 0; server_info->pid = getppid(); server_info->rd_fd = fd1[0]; server_info->wr_fd = fd2[1]; close(fd1[1]); close(fd2[0]); PMIX_CONSTRUCT_LOCK(&server_info->lock); pmix_list_append(server_list, &server_info->super); break; } pmix_asprintf(&server_info->hostname, "node%d", i); server_info->idx = i; server_info->pid = pid; server_info->wr_fd = fd1[1]; server_info->rd_fd = fd2[0]; PMIX_CONSTRUCT_LOCK(&server_info->lock); close(fd1[0]); close(fd2[1]); } else { my_server_info = server_info; server_info->hostname = strdup("node0"); server_info->pid = getpid(); server_info->idx = 0; server_info->rd_fd = fd1[0]; server_info->wr_fd = fd1[1]; PMIX_CONSTRUCT_LOCK(&server_info->lock); close(fd2[0]); close(fd2[1]); } TEST_VERBOSE(("%d: add server %d", my_server_id, server_info->idx)); pmix_list_append(server_list, &server_info->super); } } /* compute local proc size */ params->lsize = (params->nprocs % params->nservers) > (uint32_t) my_server_id ? params->nprocs / params->nservers + 1 : params->nprocs / params->nservers; /* setup the server library */ uint32_t u32 = 0666; PMIX_INFO_LOAD(&info[0], PMIX_SOCKET_MODE, &u32, PMIX_UINT32); PMIX_INFO_LOAD(&info[1], PMIX_HOSTNAME, my_server_info->hostname, PMIX_STRING); server_nspace = PMIX_NEW(pmix_list_t); if (PMIX_SUCCESS != (rc = PMIx_server_init(&mymodule, info, 2))) { TEST_ERROR(("Init failed with error %d", rc)); goto error; } /* register test server read thread */ if (params->nservers && pmix_list_get_size(server_list)) { server_info_t *server; PMIX_LIST_FOREACH (server, server_list, server_info_t) { server->evread = pmix_event_new(pmix_globals.evbase, server->rd_fd, EV_READ | EV_PERSIST, server_read_cb, server); pmix_event_add(server->evread, NULL); } } /* register the errhandler */ PMIx_Register_event_handler(NULL, 0, NULL, 0, errhandler, errhandler_reg_callbk, NULL); /* setup to see sigchld on the forked tests */ pmix_event_assign(&handler, pmix_globals.evbase, SIGCHLD, EV_SIGNAL | EV_PERSIST, wait_signal_callback, &handler); pmix_event_add(&handler, NULL); if (0 != (rc = server_barrier())) { goto error; } return PMIX_SUCCESS; error: PMIX_DESTRUCT(server_nspace); return rc; } int server_finalize(test_params *params, int local_fail) { int rc = PMIX_SUCCESS; int total_ret = local_fail; if (0 != (rc = server_barrier())) { total_ret++; goto exit; } if (0 != my_server_id) { server_info_t *server = (server_info_t *) pmix_list_get_first(server_list); remove_server_item(server); } if (params->nservers && 0 == my_server_id) { /* wait for all servers are finished */ total_ret += srv_wait_all(10.0); PMIX_LIST_RELEASE(server_list); TEST_VERBOSE( ("SERVER %d FINALIZE PID:%d with status %d", my_server_id, getpid(), total_ret)); if (0 == total_ret) { TEST_OUTPUT(("Test finished OK!")); } else { rc = PMIX_ERROR; } } PMIX_LIST_RELEASE(server_nspace); /* finalize the server library */ if (PMIX_SUCCESS != (rc = PMIx_server_finalize())) { TEST_ERROR(("Finalize failed with error %d", rc)); total_ret += rc; goto exit; } exit: return total_ret; } int server_launch_clients(int local_size, int univ_size, int base_rank, test_params *params, char ***client_env, char ***base_argv) { int n; uid_t myuid; gid_t mygid; char digit[MAX_DIGIT_LEN]; int rc; static int cli_counter = 0; static int num_ns = 0; pmix_proc_t proc; int rank_counter = 0; server_nspace_t *nspace_item = PMIX_NEW(server_nspace_t); TEST_VERBOSE(("%d: lsize: %d, base rank %d, local_size %d, univ_size %d", my_server_id, params->lsize, base_rank, local_size, univ_size)); TEST_VERBOSE(("Setting job info")); (void) snprintf(proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, num_ns); set_namespace(local_size, univ_size, base_rank, proc.nspace, params); /* add namespace entry */ nspace_item->ntasks = univ_size; nspace_item->ltasks = local_size; nspace_item->task_map = (int *) malloc(sizeof(int) * univ_size); memset(nspace_item->task_map, -1, sizeof(int) * univ_size); strcpy(nspace_item->name, proc.nspace); pmix_list_append(server_nspace, &nspace_item->super); for (n = 0; n < local_size; n++) { proc.rank = base_rank + n; nspace_item->task_map[proc.rank] = my_server_id; } server_send_procs(); myuid = getuid(); mygid = getgid(); /* fork/exec the test */ for (n = 0; n < local_size; n++) { proc.rank = base_rank + rank_counter; rc = PMIx_server_register_client(&proc, myuid, mygid, NULL, NULL, NULL); if (PMIX_SUCCESS != rc && PMIX_OPERATION_SUCCEEDED != rc) { TEST_ERROR(("Server register client failed with error %d", rc)); PMIx_server_finalize(); cli_kill_all(); return 0; } if (PMIX_SUCCESS != (rc = PMIx_server_setup_fork(&proc, client_env))) { // n TEST_ERROR(("Server fork setup failed with error %d", rc)); PMIx_server_finalize(); cli_kill_all(); return rc; } TEST_VERBOSE(("run %s:%d", proc.nspace, proc.rank)); cli_info[cli_counter].pid = fork(); if (cli_info[cli_counter].pid < 0) { TEST_ERROR(("Fork failed")); PMIx_server_finalize(); cli_kill_all(); return 0; } cli_info[cli_counter].rank = proc.rank; // n cli_info[cli_counter].ns = strdup(proc.nspace); char **client_argv = PMIx_Argv_copy(*base_argv); /* add two last arguments: -r */ snprintf(digit, MAX_DIGIT_LEN, "%d", proc.rank); PMIx_Argv_append_nosize(&client_argv, "-r"); PMIx_Argv_append_nosize(&client_argv, digit); PMIx_Argv_append_nosize(&client_argv, "-s"); PMIx_Argv_append_nosize(&client_argv, proc.nspace); snprintf(digit, MAX_DIGIT_LEN, "%d", univ_size); PMIx_Argv_append_nosize(&client_argv, "--ns-size"); PMIx_Argv_append_nosize(&client_argv, digit); snprintf(digit, MAX_DIGIT_LEN, "%d", num_ns); PMIx_Argv_append_nosize(&client_argv, "--ns-id"); PMIx_Argv_append_nosize(&client_argv, digit); snprintf(digit, MAX_DIGIT_LEN, "%d", 0); PMIx_Argv_append_nosize(&client_argv, "--base-rank"); PMIx_Argv_append_nosize(&client_argv, digit); if (cli_info[cli_counter].pid == 0) { sigset_t sigs; set_handler_default(SIGTERM); set_handler_default(SIGINT); set_handler_default(SIGHUP); set_handler_default(SIGPIPE); set_handler_default(SIGCHLD); sigprocmask(0, 0, &sigs); sigprocmask(SIG_UNBLOCK, &sigs, 0); if (!TEST_VERBOSE_GET()) { // Hide clients stdout if (NULL == freopen("/dev/null", "w", stdout)) { return 0; } } execve(params->binary, client_argv, *client_env); /* Does not return */ TEST_ERROR(("execve() failed")); return 0; } cli_info[cli_counter].alive = true; cli_info[cli_counter].state = CLI_FORKED; PMIx_Argv_free(client_argv); cli_counter++; rank_counter++; } num_ns++; return rank_counter; } pmix-6.1.1~rc2/test/test_error.c0000664000175000017500000000746715203536752017026 0ustar alastairalastair/* * Copyright (c) 2015-2019 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "test_error.h" #include "test_common.h" #include #define MAX_ERR_HANDLERS 5 #define TEST_NOTIFY PMIX_ERR_TIMEOUT static bool done; static void comfail_errhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { TEST_ERROR(("comfail errhandler called for error status = %d ninfo = %lu", status, (unsigned long) ninfo)); PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, info, results, nresults); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } } static void timeout_errhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { TEST_ERROR(("timeout errhandler called for error status = %d ninfo = %d", status, (int) ninfo)); PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, info, results, nresults); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } } static void op1_callbk(pmix_status_t status, void *cbdata) { TEST_VERBOSE(("op1_callbk CALLED WITH STATUS %d", status)); PMIX_HIDE_UNUSED_PARAMS(cbdata); done = true; } static void errhandler_reg_callbk1(pmix_status_t status, size_t errhandler_ref, void *cbdata) { size_t *ref = (size_t *) cbdata; *ref = errhandler_ref; TEST_VERBOSE(("PMIX client ERRHANDLER REGISTRATION CALLED WITH STATUS %d, ref=%lu", status, (unsigned long) errhandler_ref)); } int test_error(char *my_nspace, int my_rank, test_params params) { size_t errhandler_refs[MAX_ERR_HANDLERS]; struct timespec ts; pmix_status_t status; pmix_proc_t source; PMIX_HIDE_UNUSED_PARAMS(params); TEST_VERBOSE(("test-error: running error handling test cases")); /* register specific client error handlers and test their invocation * by triggering events from server side*/ status = PMIX_ERR_TIMEOUT; PMIx_Register_event_handler(&status, 1, NULL, 0, timeout_errhandler, errhandler_reg_callbk1, &errhandler_refs[0]); /* reg a handler for comm errors */ status = PMIX_ERR_LOST_PEER_CONNECTION; PMIx_Register_event_handler(&status, 1, NULL, 0, comfail_errhandler, errhandler_reg_callbk1, &errhandler_refs[1]); /* inject error from client */ done = false; pmix_strncpy(source.nspace, my_nspace, PMIX_MAX_NSLEN); source.rank = my_rank; /* change error value to test other error notifications */ PMIx_Notify_event(TEST_NOTIFY, &source, PMIX_RANGE_NAMESPACE, NULL, 0, op1_callbk, NULL); while (!done) { ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } done = false; /* dereg all handlers*/ PMIx_Deregister_event_handler(errhandler_refs[0], op1_callbk, NULL); /* loop until we get callback */ while (!done) { ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } done = false; PMIx_Deregister_event_handler(errhandler_refs[1], op1_callbk, NULL); /* loop until we get callback */ while (!done) { ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } return PMIX_SUCCESS; } pmix-6.1.1~rc2/test/simple/0000775000175000017500000000000015203536752015745 5ustar alastairalastairpmix-6.1.1~rc2/test/simple/simptimeout.c0000664000175000017500000001432115203536752020471 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #define MAXCNT 1 static volatile bool completed = false; static pmix_proc_t myproc; static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, info, ninfo, results, nresults); pmix_output(0, "Client %s:%d NOTIFIED with status %s", myproc.nspace, myproc.rank, PMIx_Error_string(status)); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } completed = true; } static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata) { volatile bool *active = (volatile bool *) cbdata; pmix_output(0, "Client: ERRHANDLER REGISTRATION CALLBACK CALLED WITH STATUS %d, ref=%lu", status, (unsigned long) errhandler_ref); *active = false; } int main(int argc, char **argv) { int rc; pmix_value_t value; pmix_value_t *val = &value; pmix_proc_t proc; uint32_t nprocs, n; volatile bool active; pmix_info_t info; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* init us */ if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank); /* test something */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } PMIX_VALUE_RELEASE(val); /* register our errhandler */ active = true; PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, errhandler_reg_callbk, (void *) &active); while (active) { usleep(10); } /* get our job size */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get job size failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "Client %s:%d job size %d", myproc.nspace, myproc.rank, nprocs); /* if we are rank=0, then do a fence with timeout */ if (0 == myproc.rank) { PMIX_INFO_CONSTRUCT(&info); n = 1; PMIX_INFO_LOAD(&info, PMIX_TIMEOUT, &n, PMIX_UINT32); PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; pmix_output(0, "TEST FENCE TIMEOUT"); if (PMIX_ERR_TIMEOUT != (rc = PMIx_Fence(&proc, 1, &info, 1))) { pmix_output(0, "Client ns %s rank %d: PMIx_Fence did not timeout: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } pmix_output(0, "FENCE TIMEOUT SUCCEEDED"); /* check timeout on connect */ pmix_output(0, "TEST CONNECT TIMEOUT"); if (PMIX_ERR_TIMEOUT != (rc = PMIx_Connect(&proc, 1, &info, 1))) { pmix_output(0, "Client ns %s rank %d: PMIx_Connect did not timeout: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } pmix_output(0, "CONNECT TIMEOUT SUCCEEDED"); /* check timeout on Get */ proc.rank = 1; pmix_output(0, "TEST GET TIMEOUT"); if (PMIX_ERR_TIMEOUT == (rc = PMIx_Get(&proc, "1234", &info, 1, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get did not timeout: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } pmix_output(0, "GET TIMEOUT SUCCEEDED"); } else { sleep(5); } done: /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (rc); } pmix-6.1.1~rc2/test/simple/doubleget.c0000664000175000017500000002446515203536752020076 0ustar alastairalastair#include #include #include static pmix_proc_t allproc = PMIX_PROC_STATIC_INIT; static pmix_proc_t myproc = PMIX_PROC_STATIC_INIT; static pmix_proc_t * all_procs = NULL; static bool mywait = false; static bool refresh = false; static bool timeout = false; static bool group = false; static uint32_t nprocs; static int pmi_set_string(const char *key, void *data, size_t size) { int rc; pmix_value_t value; PMIX_VALUE_CONSTRUCT(&value); value.type = PMIX_BYTE_OBJECT; value.data.bo.bytes = data; value.data.bo.size = size; if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_GLOBAL, key, &value))) { fprintf(stderr, "ERROR: Client ns %s rank %d: PMIx_Put failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } if (PMIX_SUCCESS != (rc = PMIx_Commit())) { fprintf(stderr, "ERROR: Client ns %s rank %d: PMIx_Commit failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } /* protect the data */ value.data.bo.bytes = NULL; value.data.bo.size = 0; PMIX_VALUE_DESTRUCT(&value); fprintf(stdout, "%s:%d PMIx_Put on %s with value %s\n", myproc.nspace, myproc.rank, key, (char*) data); return 0; } static int pmi_get_string(uint32_t peer_rank, const char *key, void **data_out, size_t *data_size_out, bool retry) { int rc; pmix_proc_t proc; pmix_value_t *pvalue; pmix_info_t info; PMIX_LOAD_PROCID(&proc, myproc.nspace, peer_rank); if (refresh && retry) { PMIX_INFO_LOAD(&info, PMIX_GET_REFRESH_CACHE, &refresh, PMIX_BOOL); rc = PMIx_Get(&proc, key, &info, 1, &pvalue); PMIX_INFO_DESTRUCT(&info); } else if (timeout) { rc = 2; PMIX_INFO_LOAD(&info, PMIX_TIMEOUT, &rc, PMIX_INT); rc = PMIx_Get(&proc, key, &info, 1, &pvalue); PMIX_INFO_DESTRUCT(&info); } else { rc = PMIx_Get(&proc, key, NULL, 0, &pvalue); } if (PMIX_SUCCESS != rc) { fprintf(stderr, "ERROR: Client ns %s rank %d: PMIx_Get on rank %u %s: %s\n", myproc.nspace, myproc.rank, peer_rank, key, PMIx_Error_string(rc)); return rc; } if (pvalue->type != PMIX_BYTE_OBJECT) { fprintf(stderr, "ERROR: Client ns %s rank %d: PMIx_Get %s: got wrong data type\n", myproc.nspace, myproc.rank, key); } *data_out = pvalue->data.bo.bytes; *data_size_out = pvalue->data.bo.size; /* protect the data */ pvalue->data.bo.bytes = NULL; pvalue->data.bo.size = 0; PMIX_VALUE_RELEASE(pvalue); PMIX_PROC_DESTRUCT(&proc); fprintf(stdout, "%s:%d PMIx_get %s returned %zi bytes (value %s)\n", myproc.nspace, myproc.rank, key, data_size_out[0], (char*) *data_out); return 0; } static int pmix_exchange(bool flag) { int rc; pmix_info_t info; fprintf(stderr, "Execute fence\n"); PMIX_INFO_CONSTRUCT(&info); PMIX_INFO_LOAD(&info, PMIX_COLLECT_DATA, &flag, PMIX_BOOL); if (all_procs) { /* Array with procs (group case)*/ rc = PMIx_Fence(all_procs, nprocs, &info, 1); } else { /* Rank wildcard */ rc = PMIx_Fence(&allproc, 1, &info, 1); } if (PMIX_SUCCESS != rc) { fprintf(stderr, "Client ns %s rank %d: PMIx_Fence_nb failed: %d\n", myproc.nspace, myproc.rank, rc); exit(1); } PMIX_INFO_DESTRUCT(&info); return 0; } static int pmix_create_group(void) { pmix_status_t rc = PMIX_SUCCESS; bool assign_context_id = true; pmix_info_t * directives = NULL; pmix_info_t *results = NULL; size_t ndirs = 2; size_t nresults = 0; int group_timeout = 10; PMIX_PROC_CREATE(all_procs, nprocs); for (size_t i = 0; i < nprocs; i++) { PMIX_PROC_LOAD(&(all_procs[i]), myproc.nspace, i); } fprintf(stdout, "Client ns %s rank %d: Group construction...\n", myproc.nspace, myproc.rank); PMIX_INFO_CREATE(directives, ndirs); PMIX_INFO_LOAD(&(directives[0]), PMIX_GROUP_ASSIGN_CONTEXT_ID, &assign_context_id, PMIX_BOOL); PMIX_INFO_LOAD(&(directives[1]), PMIX_TIMEOUT, &group_timeout, PMIX_INT); if (PMIX_SUCCESS != (rc = PMIx_Group_construct("mygroup", all_procs, nprocs, directives, ndirs, &results, &nresults))) { fprintf(stderr, "Client ns %s rank %d: PMIx_Group_construct failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); return rc; } for (size_t k = 0; k < nresults; k++) { fprintf(stdout, "%s-%d: %s\n", myproc.nspace, myproc.rank, PMIx_Info_string(&results[k])); } if (directives != NULL) { PMIX_INFO_FREE(directives, ndirs); } if (results != NULL) { PMIX_INFO_FREE(results, nresults); } return rc; } static int pmix_destruct_group(void) { pmix_status_t rc = PMIX_SUCCESS; size_t ndirs = 1; pmix_info_t * directives = NULL; PMIX_INFO_CREATE(directives, ndirs); PMIX_INFO_LOAD(&(directives[0]), PMIX_TIMEOUT, &timeout, PMIX_INT); if (PMIX_SUCCESS != (rc = PMIx_Group_destruct("mygroup", directives, ndirs))) { fprintf(stderr, "Client ns %s rank %d: PMIx_Group_destruct failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } if (directives != NULL) { PMIX_INFO_FREE(directives, ndirs); } return rc; } int main(int argc, char *argv[]) { char data[256]; char *data_out; size_t size_out; int rc; pmix_value_t *pvalue; /* check the args */ if (1 < argc) { if (2 < argc || 0 == strncmp(argv[1], "-h", 2) || 0 == strncmp(argv[1], "--h", 3)) { fprintf(stderr, "Usage:\n"); fprintf(stderr, "\t--wait Test PMIX_GET_WAIT_FOR_KEY\n"); fprintf(stderr, "\t--refresh Test PMIX_GET_REFRESH_CACHE\n"); fprintf(stderr, "\t--timeout Test PMIX_GET_WAIT_FOR_KEY, but timeout\n"); fprintf(stderr, "\t--group Test PMIX_GET_REFRESH_CACHE and PMIx Process Group\n"); exit(0); } if (0 == strncmp(argv[1], "--w", 3)) { mywait = true; } else if (0 == strncmp(argv[1], "--r", 3)) { refresh = true; } else if (0 == strncmp(argv[1], "--t", 3)) { timeout = true; } else if (0 == strncmp(argv[1], "--g", 3)) { group = true; refresh = true; } else { fprintf(stderr, "Invalid cmd line option: %s\n", argv[1]); fprintf(stderr, "Usage:\n"); fprintf(stderr, "\t--wait Test PMIX_GET_WAIT_FOR_KEY\n"); fprintf(stderr, "\t--refresh Test PMIX_GET_REFRESH_CACHE\n"); fprintf(stderr, "\t--timeout Test PMIX_GET_WAIT_FOR_KEY, but timeout\n"); fprintf(stderr, "\t--group Test PMIX_GET_REFRESH_CACHE and PMIx Process Group\n"); exit(1); } } if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { fprintf(stderr, "ERROR: PMIx_Init failed"); exit(1); } if (myproc.rank == 0) { printf("PMIx initialized\n"); } memset(data, 0, 256); /* job-related info is found in our nspace, assigned to the * wildcard rank as it doesn't relate to a specific rank. Setup * a name to retrieve such values */ PMIX_LOAD_PROCID(&allproc, myproc.nspace, PMIX_RANK_WILDCARD); /* get the number of procs in our job */ if (PMIX_SUCCESS != (rc = PMIx_Get(&allproc, PMIX_JOB_SIZE, NULL, 0, &pvalue))) { fprintf(stderr, "Client ns %s rank %d: PMIx_Get job size failed: %d\n", myproc.nspace, myproc.rank, rc); exit(1); } nprocs = pvalue->data.uint32; PMIX_VALUE_RELEASE(pvalue); /* Each rank puts a unique key-value pair in the KVS */ snprintf(data, 256, "ORIG rank %d", myproc.rank); if (0 == myproc.rank) { pmi_set_string("test-key-0", data, 256); } else { pmi_set_string("test-key-1", data, 256); } pmix_exchange(true); if (1 == myproc.rank) { if (timeout) { sleep(10); } else if (mywait) { sleep(2); } } /* Each rank gets the key-value pair that was put by the other rank */ if (0 == myproc.rank) { rc = pmi_get_string(1, "test-key-1", (void **) &data_out, &size_out, false); if (0 != rc) { goto done; } fprintf(stdout, "%d: obtained data for test-key-1 \"%s\"\n", myproc.rank, data_out); } else { rc = pmi_get_string(0, "test-key-0", (void **) &data_out, &size_out, false); if (0 != rc) { goto done; } fprintf(stdout, "%d: obtained data for test-key-0 \"%s\"\n", myproc.rank, data_out); } /* Create a group */ if (group) { rc = pmix_create_group(); if (rc != PMIX_SUCCESS) { exit(1); } } /* Each rank attempts to overwrite the value that was previously put */ snprintf(data, 256, "OVERWRITE rank %d", myproc.rank); if (0 == myproc.rank) { pmi_set_string("test-key-0", data, 256); } else { pmi_set_string("test-key-1", data, 256); } pmix_exchange(true); if (1 == myproc.rank) { if (timeout) { sleep(10); } else if (mywait) { sleep(2); } } /* Each rank gets the value put by the other rank * If overwrite was successful, each rank should get the new value here */ if (0 == myproc.rank) { rc = pmi_get_string(1, "test-key-1", (void **) &data_out, &size_out, true); if (0 != rc) { goto done; } fprintf(stdout, "%d: obtained data for test-key-1 \"%s\"\n", myproc.rank, data_out); } else { rc = pmi_get_string(0, "test-key-0", (void **) &data_out, &size_out, true); if (0 != rc) { goto done; } fprintf(stdout, "%d: obtained data for test-key-0 \"%s\"\n", myproc.rank, data_out); } /* Destroy group*/ if (group) { rc = pmix_destruct_group(); if (rc != PMIX_SUCCESS) { exit(1); } } done: if (all_procs != NULL) { PMIX_PROC_FREE(all_procs, nprocs); } if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "ERROR: Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc); } if (myproc.rank == 0) printf("PMIx finalized\n"); exit(0); } pmix-6.1.1~rc2/test/simple/simptool.c0000664000175000017500000001114615203536752017762 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix_tool.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" static pmix_proc_t myproc; int main(int argc, char **argv) { pmix_status_t rc; pmix_query_t *query; size_t nq, n; pmix_info_t *results = NULL; size_t nresults = 0; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* init us */ if (PMIX_SUCCESS != (rc = PMIx_tool_init(&myproc, NULL, 0))) { fprintf(stderr, "PMIx_tool_init failed: %d\n", rc); exit(rc); } pmix_output(0, "Tool ns %s rank %d: Running", myproc.nspace, myproc.rank); /* query something */ nq = 2; PMIX_QUERY_CREATE(query, nq); PMIx_Argv_append_nosize(&query[0].keys, "foobar"); PMIx_Argv_append_nosize(&query[1].keys, "spastic"); PMIx_Argv_append_nosize(&query[1].keys, PMIX_SERVER_URI); if (PMIX_SUCCESS != (rc = PMIx_Query_info(query, nq, &results, &nresults))) { pmix_output(0, "Client ns %s rank %d: PMIx_Query_info failed: %d", myproc.nspace, myproc.rank, rc); goto done; } if (3 != nresults || NULL == results) { pmix_output(0, "Client ns %s rank %d: PMIx_Query_info returned incorrect results: %d", myproc.nspace, myproc.rank, (int) nresults); goto done; } if (0 != strncmp(results[0].key, "foobar", PMIX_MAX_KEYLEN)) { pmix_output(0, "Client ns %s rank %d: PMIx_Query_info[0] key wrong: %s vs foobar", myproc.nspace, myproc.rank, results[0].key); } if (0 != strncmp(results[1].key, "spastic", PMIX_MAX_KEYLEN)) { pmix_output(0, "Client ns %s rank %d: PMIx_Query_info[1] key wrong: %s vs spastic", myproc.nspace, myproc.rank, results[1].key); } if (PMIX_STRING != results[0].value.type) { pmix_output(0, "Client ns %s rank %d: PMIx_Query_info key[0] wrong type: %d vs %d", myproc.nspace, myproc.rank, results[0].value.type, PMIX_STRING); } if (PMIX_STRING != results[1].value.type) { pmix_output(0, "Client ns %s rank %d: PMIx_Query_info key[1] wrong type: %d vs %d", myproc.nspace, myproc.rank, results[1].value.type, PMIX_STRING); } if (0 != strcmp(results[0].value.data.string, "0")) { pmix_output(0, "Client ns %s rank %d: PMIx_Query_info key[0] wrong value: %s vs 0", myproc.nspace, myproc.rank, results[1].value.data.string); } if (0 != strcmp(results[1].value.data.string, "1")) { pmix_output(0, "Client ns %s rank %d: PMIx_Query_info key[1] wrong value: %s vs 1", myproc.nspace, myproc.rank, results[1].value.data.string); } for (n=0; n < nresults; n++) { pmix_output(0, "Client received result[%u]: %s", (unsigned)n, PMIx_Info_string(&results[n])); } done: /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_tool_finalize())) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (rc); } pmix-6.1.1~rc2/test/simple/loop-exec.sh0000775000175000017500000000177615203536752020212 0ustar alastairalastair#!/bin/bash loops=20000 #loops=2 TIMEOUT="timeout --preserve-status -k 32 30" TIMEOUT="" #timeout --preserve-status -k 32 30 ./opal_fifo #MCA_PARAMS="-host rhc001:24 -mca coll ^hcoll -mca pml ob1 -mca btl tcp,self -mca oob tcp --tag-output" VALGRIND_OPTS="" #VALGRIND_OPTS="valgrind --track-origins=yes" cmd="${TIMEOUT} ./simptest -n 20" #export PMIX_DEBUG=2 #export PMIX_MCA_ptl=tcp i=1 while [ $i -le $loops ]; do echo "--------------------------------------------" echo "-------------------- Iteration $i of $loops" starttime=`date +%s` $cmd rc=$? endtime=`date +%s` echo "Loop $i of $loops. rc=$rc r=$ranks s=$starttime e=$endtime d=$((endtime - starttime))" if [ $rc != 0 ] ; then if [ $rc == 124 ] ; then echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TIMEOUT - skip" else echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX FAILURE" fi exit -1 fi i=$((i + 1)) done exit 0 pmix-6.1.1~rc2/test/simple/simpft.c0000664000175000017500000001207415203536752017417 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" static pmix_proc_t myproc; static bool completed; static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, info, ninfo, results, nresults); pmix_output(0, "Client %s:%d NOTIFIED with status %d", myproc.nspace, myproc.rank, status); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } completed = true; } static void op_callbk(pmix_status_t status, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(cbdata); pmix_output(0, "CLIENT: OP CALLBACK CALLED WITH STATUS %d", status); } static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(errhandler_ref, cbdata); pmix_output(0, "Client: ERRHANDLER REGISTRATION CALLBACK CALLED WITH STATUS %d, ref=%lu", status, (unsigned long) errhandler_ref); } int main(int argc, char **argv) { int rc; pmix_value_t value; pmix_value_t *val = &value; pmix_proc_t proc; uint32_t nprocs; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* init us */ if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %d", myproc.nspace, myproc.rank, rc); exit(0); } pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank); /* get our job size */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get job size failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "Client %s:%d job size %d", myproc.nspace, myproc.rank, nprocs); completed = false; /* register our errhandler */ PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, errhandler_reg_callbk, NULL); /* call fence to sync */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc); goto done; } /* rank=0 calls abort */ if (0 == myproc.rank) { PMIx_Abort(PMIX_ERR_OUT_OF_RESOURCE, "Eat rocks", &proc, 1); pmix_output(0, "Client ns %s rank %d: Abort called", myproc.nspace, myproc.rank); } else { /* everyone simply waits */ while (!completed) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } } done: /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank); PMIx_Deregister_event_handler(1, op_callbk, NULL); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (0); } pmix-6.1.1~rc2/test/simple/simpclient.c0000664000175000017500000004542115203536752020266 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * Copyright (c) 2023-2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #define MAXCNT 1 static volatile bool completed = false; static pmix_proc_t myproc; static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, info, ninfo, results, nresults); pmix_output(0, "Client %s:%d NOTIFIED with status %s", myproc.nspace, myproc.rank, PMIx_Error_string(status)); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } completed = true; } static void opcbfunc(pmix_status_t status, void *cbdata) { volatile bool *active = (volatile bool *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); *active = false; } /* this is an event notification function that we explicitly request * be called when the PMIX_MODEL_DECLARED notification is issued. * We could catch it in the general event notification function and test * the status to see if the status matched, but it often is simpler * to declare a use-specific notification callback point. In this case, * we are asking to know whenever a model is declared as a means * of testing server self-notification */ static void model_callback(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { size_t n; PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, results, nresults); /* just let us know it was received */ fprintf(stderr, "%s:%d Model event handler called with status %d(%s)\n", myproc.nspace, myproc.rank, status, PMIx_Error_string(status)); for (n = 0; n < ninfo; n++) { if (PMIX_STRING == info[n].value.type) { fprintf(stderr, "%s:%d\t%s:\t%s\n", myproc.nspace, myproc.rank, info[n].key, info[n].value.data.string); } } /* we must NOT tell the event handler state machine that we * are the last step as that will prevent it from notifying * anyone else that might be listening for declarations */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } } int main(int argc, char **argv) { int rc; pmix_value_t value; pmix_value_t *val = &value; char *tmp; pmix_proc_t proc; uint32_t nprocs, n, k, nlocal; int cnt, j; bool doabort = false; volatile bool active; pmix_info_t info, *iptr; size_t ninfo; pmix_status_t code; char **peers; bool all_local, local; pmix_rank_t *locals = NULL; pmix_topology_t topo; if (1 < argc) { if (0 == strcmp("-abort", argv[1])) { doabort = true; } } /* init us and declare we are a test programming model */ PMIX_INFO_CREATE(iptr, 2); PMIX_INFO_LOAD(&iptr[0], PMIX_PROGRAMMING_MODEL, "TEST", PMIX_STRING); PMIX_INFO_LOAD(&iptr[1], PMIX_MODEL_LIBRARY_NAME, "PMIX", PMIX_STRING); if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, iptr, 2))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } PMIX_INFO_FREE(iptr, 2); pmix_output(0, "Client ns %s rank %d: Running on node %s", myproc.nspace, myproc.rank, pmix_globals.hostname); /* test something */ PMIX_LOAD_PROCID(&proc, myproc.nspace, PMIX_RANK_WILDCARD); if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get job size failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "Client %s:%d job size %d", myproc.nspace, myproc.rank, nprocs); /* test something */ if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_SERVER_URI, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get server URI failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "CLIENT SERVER URI: %s", val->data.string); PMIX_VALUE_RELEASE(val); if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_LOCAL_RANK, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get LOCAL RANK failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "CLIENT LOCAL RANK: %u", val->data.uint16); PMIX_VALUE_RELEASE(val); if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_HOSTNAME, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get HOSTNAME failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "CLIENT HOSTNAME: %s", val->data.string); PMIX_VALUE_RELEASE(val); /* check if a security credential was given */ if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_CREDENTIAL, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get CREDENTIAL failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } else { pmix_output(0, "CREDENTIAL: %s", val->data.string); PMIX_VALUE_RELEASE(val); } /* get our topology */ PMIX_TOPOLOGY_CONSTRUCT(&topo); rc = PMIx_Load_topology(&topo); if (PMIX_SUCCESS != rc) { pmix_output(0, "Client ns %s rank %d: Failed to load topology: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "Client ns %s rank %d: Topology source: %s", myproc.nspace, myproc.rank, topo.source); /* register a handler specifically for when models declare */ ninfo = 1; PMIX_INFO_CREATE(iptr, ninfo); PMIX_INFO_LOAD(&iptr[0], PMIX_EVENT_HDLR_NAME, "SIMPCLIENT-MODEL", PMIX_STRING); code = PMIX_MODEL_DECLARED; PMIx_Register_event_handler(&code, 1, iptr, ninfo, model_callback, NULL, NULL); PMIX_INFO_FREE(iptr, ninfo); /* register our errhandler */ PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, NULL, NULL); /* put a few values */ if (0 > asprintf(&tmp, "%s-%d-internal", myproc.nspace, myproc.rank)) { errno = ENOMEM; abort(); } value.type = PMIX_UINT32; value.data.uint32 = 1234; if (PMIX_SUCCESS != (rc = PMIx_Store_internal(&myproc, tmp, &value))) { pmix_output(0, "Client ns %s rank %d: PMIx_Store_internal failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } free(tmp); /* get a list of our local peers */ if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_LOCAL_PEERS, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get local peers failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } /* split the returned string to get the rank of each local peer */ peers = PMIx_Argv_split(val->data.string, ','); PMIX_VALUE_RELEASE(val); nlocal = PMIx_Argv_count(peers); if (nprocs == nlocal) { all_local = true; } else { all_local = false; locals = (pmix_rank_t *) malloc(PMIx_Argv_count(peers) * sizeof(pmix_rank_t)); for (cnt = 0; NULL != peers[cnt]; cnt++) { locals[cnt] = strtoul(peers[cnt], NULL, 10); } } PMIx_Argv_free(peers); for (cnt = 0; cnt < MAXCNT; cnt++) { pmix_output(0, "Client %s:%d executing loop %d", myproc.nspace, myproc.rank, cnt); if (0 > asprintf(&tmp, "%s-%d-local-%d", myproc.nspace, myproc.rank, cnt)) { errno = ENOMEM; abort(); } value.type = PMIX_UINT64; value.data.uint64 = 1234; if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_LOCAL, tmp, &value))) { pmix_output(0, "Client ns %s rank %d: PMIx_Put internal failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } free(tmp); if (0 > asprintf(&tmp, "%s-%d-remote-%d", myproc.nspace, myproc.rank, cnt)) { errno = ENOMEM; abort(); } value.type = PMIX_STRING; value.data.string = "1234"; if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_REMOTE, tmp, &value))) { pmix_output(0, "Client ns %s rank %d: PMIx_Put internal failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } free(tmp); if (PMIX_SUCCESS != (rc = PMIx_Commit())) { pmix_output(0, "Client ns %s rank %d cnt %d: PMIx_Commit failed: %s", myproc.nspace, myproc.rank, cnt, PMIx_Error_string(rc)); exit(rc); } /* call fence to ensure the data is received */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d cnt %d: PMIx_Fence failed: %s", myproc.nspace, myproc.rank, cnt, PMIx_Error_string(rc)); exit(rc); } /* check the returned data */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); for (j = 0; j <= cnt; j++) { for (n = 0; n < nprocs; n++) { proc.rank = n; if (all_local) { local = true; } else { local = false; /* see if this proc is local to us */ for (k = 0; k < nlocal; k++) { if (proc.rank == locals[k]) { local = true; break; } } } if (local) { if (0 > asprintf(&tmp, "%s-%d-local-%d", myproc.nspace, n, j)) { errno = ENOMEM; abort(); } if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, tmp, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d cnt %d: PMIx_Get %s failed: %s", myproc.nspace, myproc.rank, j, tmp, PMIx_Error_string(rc)); continue; } if (NULL == val) { pmix_output(0, "Client ns %s rank %d: NULL value returned", myproc.nspace, myproc.rank); exit(1); } if (PMIX_UINT64 != val->type) { pmix_output( 0, "Client ns %s rank %d cnt %d: PMIx_Get %s returned wrong type: %d", myproc.nspace, myproc.rank, j, tmp, val->type); PMIX_VALUE_RELEASE(val); free(tmp); exit(1); } if (1234 != val->data.uint64) { pmix_output( 0, "Client ns %s rank %d cnt %d: PMIx_Get %s returned wrong value: %d", myproc.nspace, myproc.rank, j, tmp, (int) val->data.uint64); PMIX_VALUE_RELEASE(val); free(tmp); exit(1); } pmix_output(0, "Client ns %s rank %d cnt %d: PMIx_Get %s returned correct", myproc.nspace, myproc.rank, j, tmp); PMIX_VALUE_RELEASE(val); free(tmp); /* now check that we don't get data for a remote proc - note that we * always can get our own remote data as we published it */ if (proc.rank != myproc.rank) { if (0 > asprintf(&tmp, "%s-%d-remote-%d", proc.nspace, n, j)) { errno = ENOMEM; abort(); } if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, tmp, NULL, 0, &val))) { /* this data should _not_ be found as we are on the same node * and the data was "put" with a PMIX_REMOTE scope */ pmix_output(0, "Client ns %s rank %d cnt %d: PMIx_Get %s returned correct", myproc.nspace, myproc.rank, j, tmp); } else { pmix_output(0, "ERROR: Client ns %s rank %d cnt %d: PMIx_Get %s returned " "remote data for a local proc", myproc.nspace, myproc.rank, j, tmp); exit(1); } if (NULL != val) { PMIX_VALUE_RELEASE(val); } free(tmp); } } else { val = NULL; if (0 > asprintf(&tmp, "%s-%d-remote-%d", proc.nspace, n, j)) { errno = ENOMEM; abort(); } if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, tmp, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d cnt %d: PMIx_Get %s returned correct", myproc.nspace, myproc.rank, j, tmp); } else { pmix_output( 0, "Client ns %s rank %d cnt %d: PMIx_Get %s failed for remote proc", myproc.nspace, myproc.rank, j, tmp); exit(1); } if (NULL != val) { PMIX_VALUE_RELEASE(val); } free(tmp); } } } } /* now get the data blob for myself */ pmix_output(0, "Client ns %s rank %d testing internal modex blob", myproc.nspace, myproc.rank); if (PMIX_SUCCESS == (rc = PMIx_Get(&myproc, NULL, NULL, 0, &val))) { if (PMIX_DATA_ARRAY != val->type) { pmix_output(0, "Client ns %s rank %d did not return an array for its internal modex blob", myproc.nspace, myproc.rank); PMIX_VALUE_RELEASE(val); exit(1); } else if (PMIX_INFO != val->data.darray->type) { pmix_output(0, "Client ns %s rank %d returned an internal modex array of type %s instead " "of PMIX_INFO", myproc.nspace, myproc.rank, PMIx_Data_type_string(val->data.darray->type)); PMIX_VALUE_RELEASE(val); exit(1); } else if (0 == val->data.darray->size) { pmix_output(0, "Client ns %s rank %d returned an internal modex array of zero length", myproc.nspace, myproc.rank); PMIX_VALUE_RELEASE(val); exit(1); } else { iptr = (pmix_info_t *) val->data.darray->array; for (n = 0; n < val->data.darray->size; n++) { pmix_output(0, "\tKey: %s", iptr[n].key); } PMIX_VALUE_RELEASE(val); } } else { pmix_output(0, "Client ns %s rank %d internal modex blob FAILED with error %s(%d)", myproc.nspace, myproc.rank, PMIx_Error_string(rc), rc); exit(rc); } /* log something */ PMIX_INFO_CONSTRUCT(&info); PMIX_INFO_LOAD(&info, PMIX_LOG_STDERR, "test log msg\n", PMIX_STRING); active = true; rc = PMIx_Log_nb(&info, 1, NULL, 0, opcbfunc, (void *) &active); if (PMIX_SUCCESS != rc) { pmix_output(0, "Client ns %s rank %d - log_nb returned %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } else { while (active) { usleep(10); } } PMIX_INFO_DESTRUCT(&info); /* if requested and our rank is 0, call abort */ if (doabort) { if (0 == myproc.rank) { PMIx_Abort(PMIX_ERR_PROC_REQUESTED_ABORT, "CALLING ABORT", NULL, 0); } else { while (!completed) { usleep(10); } } } /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (rc); } pmix-6.1.1~rc2/test/simple/refresh.c0000664000175000017500000000474215203536752017556 0ustar alastairalastair#include #include #include #include static void fence_collect(const char *nspace) { pmix_proc_t wildcard; PMIx_Proc_load(&wildcard, nspace, PMIX_RANK_WILDCARD); pmix_info_t info; bool collect = true; PMIx_Info_load(&info, PMIX_COLLECT_DATA, &collect, PMIX_BOOL); PMIx_Fence(&wildcard, 1, &info, 1); PMIx_Info_destruct(&info); } int main(int argc, char **argv) { (void)argc; (void)argv; pmix_proc_t me; if (PMIx_Init(&me, NULL, 0) != PMIX_SUCCESS) { fprintf(stderr, "PMIx_Init failed\n"); return 1; } printf("PMIx client initialized: nspace=%s rank=%u\n", me.nspace, me.rank); const char *key = "mykey"; pmix_proc_t p0; PMIx_Proc_load(&p0, me.nspace, 0); // Round 0: Rank 0 puts "A" if (me.rank == 0) { pmix_value_t v; PMIx_Value_load(&v, "A", PMIX_STRING); PMIx_Put(PMIX_GLOBAL, key, &v); PMIx_Commit(); PMIx_Value_destruct(&v); printf("rank0: PUT 'A'\n"); } fence_collect(me.nspace); // Rank 1 reads and caches 'A' if (me.rank == 1) { pmix_value_t *out = NULL; pmix_status_t rc = PMIx_Get(&p0, key, NULL, 0, &out); printf("rank1: read1 -> rc=%d val=%s (now cached)\n", rc, (out && out->type == PMIX_STRING) ? out->data.string : "NULL"); if (out) PMIx_Value_free(out, 1); } fence_collect(me.nspace); // Round 1: Rank 0 overwrites with "B" if (me.rank == 0) { pmix_value_t v; PMIx_Value_load(&v, "B", PMIX_STRING); PMIx_Put(PMIX_GLOBAL, key, &v); PMIx_Commit(); PMIx_Value_destruct(&v); printf("rank0: PUT 'B' (overwrite)\n"); } fence_collect(me.nspace); // Rank 1: Try to get fresh value with REFRESH if (me.rank == 1) { pmix_info_t info[2]; bool refresh = true; bool immediate = true; PMIx_Info_load(&info[0], PMIX_GET_REFRESH_CACHE, &refresh, PMIX_BOOL); PMIx_Info_load(&info[1], PMIX_IMMEDIATE, &immediate, PMIX_BOOL); pmix_value_t *out = NULL; pmix_status_t rc = PMIx_Get(&p0, key, info, 2, &out); printf("rank1: read2 (REFRESH + IMMEDIATE) -> rc=%d val=%s (expect 'B')\n", rc, (out && out->type == PMIX_STRING) ? out->data.string : "NULL"); if (out) PMIx_Value_free(out, 1); PMIx_Info_destruct(&info[0]); PMIx_Info_destruct(&info[1]); } PMIx_Finalize(NULL, 0); return 0; } pmix-6.1.1~rc2/test/simple/gwtest.c0000664000175000017500000010663515203536752017441 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2023 Nanook Consulting. All rights reserved. * Copyright (c) 2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include #include #include #include #include #include #include #include #include "src/class/pmix_list.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" static pmix_status_t connected(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t finalized(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t abort_fn(const pmix_proc_t *proc, void *server_object, int status, const char msg[], pmix_proc_t procs[], size_t nprocs, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t fencenb_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, char *data, size_t ndata, pmix_modex_cbfunc_t cbfunc, void *cbdata); static pmix_status_t dmodex_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_modex_cbfunc_t cbfunc, void *cbdata); static pmix_status_t publish_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t lookup_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_lookup_cbfunc_t cbfunc, void *cbdata); static pmix_status_t unpublish_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t spawn_fn(const pmix_proc_t *proc, const pmix_info_t job_info[], size_t ninfo, const pmix_app_t apps[], size_t napps, pmix_spawn_cbfunc_t cbfunc, void *cbdata); static pmix_status_t connect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t disconnect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t register_event_fn(pmix_status_t *codes, size_t ncodes, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t deregister_events(pmix_status_t *codes, size_t ncodes, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t notify_event(pmix_status_t code, const pmix_proc_t *source, pmix_data_range_t range, pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t query_fn(pmix_proc_t *proct, pmix_query_t *queries, size_t nqueries, pmix_info_cbfunc_t cbfunc, void *cbdata); static void tool_connect_fn(pmix_info_t *info, size_t ninfo, pmix_tool_connection_cbfunc_t cbfunc, void *cbdata); static void log_fn(const pmix_proc_t *client, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_server_module_t mymodule = {.client_connected = connected, .client_finalized = finalized, .abort = abort_fn, .fence_nb = fencenb_fn, .direct_modex = dmodex_fn, .publish = publish_fn, .lookup = lookup_fn, .unpublish = unpublish_fn, .spawn = spawn_fn, .connect = connect_fn, .disconnect = disconnect_fn, .register_events = register_event_fn, .deregister_events = deregister_events, .notify_event = notify_event, .query = query_fn, .tool_connected = tool_connect_fn, .log = log_fn}; typedef struct { pthread_mutex_t mutex; pthread_cond_t cond; volatile bool active; pmix_status_t status; } mylock_t; #define DEBUG_CONSTRUCT_LOCK(l) \ do { \ pthread_mutex_init(&(l)->mutex, NULL); \ pthread_cond_init(&(l)->cond, NULL); \ (l)->active = true; \ (l)->status = PMIX_SUCCESS; \ } while (0) #define DEBUG_DESTRUCT_LOCK(l) \ do { \ pthread_mutex_destroy(&(l)->mutex); \ pthread_cond_destroy(&(l)->cond); \ } while (0) #define DEBUG_WAIT_THREAD(lck) \ do { \ pthread_mutex_lock(&(lck)->mutex); \ while ((lck)->active) { \ pthread_cond_wait(&(lck)->cond, &(lck)->mutex); \ } \ pthread_mutex_unlock(&(lck)->mutex); \ } while (0) #define DEBUG_WAKEUP_THREAD(lck) \ do { \ pthread_mutex_lock(&(lck)->mutex); \ (lck)->active = false; \ pthread_cond_broadcast(&(lck)->cond); \ pthread_mutex_unlock(&(lck)->mutex); \ } while (0) typedef struct { pmix_list_item_t super; pmix_pdata_t pdata; } pmix_locdat_t; PMIX_CLASS_INSTANCE(pmix_locdat_t, pmix_list_item_t, NULL, NULL); typedef struct { pmix_object_t super; mylock_t lock; pmix_status_t status; pmix_proc_t caller; pmix_info_t *info; size_t ninfo; pmix_op_cbfunc_t cbfunc; pmix_spawn_cbfunc_t spcbfunc; void *cbdata; } myxfer_t; static void xfcon(myxfer_t *p) { DEBUG_CONSTRUCT_LOCK(&p->lock); p->info = NULL; p->ninfo = 0; p->cbfunc = NULL; p->spcbfunc = NULL; p->cbdata = NULL; } static void xfdes(myxfer_t *p) { DEBUG_DESTRUCT_LOCK(&p->lock); if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->ninfo); } } PMIX_CLASS_INSTANCE(myxfer_t, pmix_object_t, xfcon, xfdes); typedef struct { pmix_list_item_t super; int exit_code; pid_t pid; } wait_tracker_t; PMIX_CLASS_INSTANCE(wait_tracker_t, pmix_list_item_t, NULL, NULL); static volatile int wakeup; static int exit_code = 0; static pmix_list_t pubdata; static pmix_event_t handler; static pmix_list_t children; static bool istimeouttest = false; static void set_namespace(int nprocs, char *ranks, char *nspace, pmix_op_cbfunc_t cbfunc, myxfer_t *x); static void errhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata); static void wait_signal_callback(int fd, short event, void *arg); static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata); static void opcbfunc(pmix_status_t status, void *cbdata) { myxfer_t *x = (myxfer_t *) cbdata; x->status = status; /* release the caller, if necessary */ if (NULL != x->cbfunc) { x->cbfunc(PMIX_SUCCESS, x->cbdata); } DEBUG_WAKEUP_THREAD(&x->lock); } static void sacbfunc(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *provided_cbdata, pmix_op_cbfunc_t cbfunc, void *cbdata) { myxfer_t *x = (myxfer_t *) provided_cbdata; size_t n; x->status = status; if (NULL != info) { x->ninfo = ninfo; PMIX_INFO_CREATE(x->info, x->ninfo); for (n = 0; n < ninfo; n++) { /* copy the data across */ PMIX_INFO_XFER(&x->info[n], &info[n]); } } if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } DEBUG_WAKEUP_THREAD(&x->lock); } static void infocbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { myxfer_t *x = (myxfer_t *) cbdata; size_t n; x->status = status; if (NULL != info) { x->ninfo = ninfo; PMIX_INFO_CREATE(x->info, x->ninfo); for (n = 0; n < ninfo; n++) { /* copy the data across */ PMIX_INFO_XFER(&x->info[n], &info[n]); } } if (NULL != release_fn) { release_fn(release_cbdata); } DEBUG_WAKEUP_THREAD(&x->lock); } int main(int argc, char **argv) { char **client_env = NULL; char **client_argv = NULL; char *tmp, **atmp, *executable = NULL; int rc, nprocs = 1, n; uid_t myuid; gid_t mygid; pid_t pid; myxfer_t *x; pmix_proc_t proc; wait_tracker_t *child; pmix_info_t *info; size_t ninfo; mylock_t mylock; pmix_data_array_t *darray; pmix_info_t *iarray; pmix_nspace_t ncache; /* smoke test */ if (PMIX_SUCCESS != 0) { fprintf(stderr, "ERROR IN COMPUTING CONSTANTS: PMIX_SUCCESS = %d\n", PMIX_SUCCESS); exit(1); } fprintf(stderr, "GW[%d]: Testing version %s\n", (int) getpid(), PMIx_Get_version()); /* see if we were passed the number of procs to run or * the executable to use */ for (n = 1; n < argc; n++) { if (0 == strcmp("-n", argv[n]) && NULL != argv[n + 1]) { nprocs = strtol(argv[n + 1], NULL, 10); ++n; // step over the argument } else if (0 == strcmp("-h", argv[n])) { /* print the options and exit */ fprintf(stderr, "usage: simptest \n"); fprintf(stderr, " -n N Number of clients to run\n"); exit(0); } } executable = strdup("./gwclient"); /* setup the server library and tell it to support tool connections */ ninfo = 3; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_SERVER_TOOL_SUPPORT, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[1], PMIX_USOCK_DISABLE, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[2], PMIX_SERVER_GATEWAY, NULL, PMIX_BOOL); if (PMIX_SUCCESS != (rc = PMIx_server_init(&mymodule, info, ninfo))) { fprintf(stderr, "Init failed with error %d\n", rc); return rc; } PMIX_INFO_FREE(info, ninfo); /* register the default errhandler */ DEBUG_CONSTRUCT_LOCK(&mylock); ninfo = 1; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_EVENT_HDLR_NAME, "GWTEST-DEFAULT", PMIX_STRING); PMIx_Register_event_handler(NULL, 0, info, ninfo, errhandler, errhandler_reg_callbk, (void *) &mylock); DEBUG_WAIT_THREAD(&mylock); PMIX_INFO_FREE(info, ninfo); if (PMIX_SUCCESS != mylock.status) { exit(mylock.status); } DEBUG_DESTRUCT_LOCK(&mylock); /* setup the pub data, in case it is used */ PMIX_CONSTRUCT(&pubdata, pmix_list_t); /* collect the inventory */ x = PMIX_NEW(myxfer_t); rc = PMIx_server_collect_inventory(NULL, 0, infocbfunc, (void *) x); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Collect inventory failed: %s\n", PMIx_Error_string(rc)); PMIX_RELEASE(x); exit(1); } DEBUG_WAIT_THREAD(&x->lock); if (PMIX_SUCCESS != x->status) { fprintf(stderr, "Collect inventory failed: %s\n", PMIx_Error_string(x->status)); PMIX_RELEASE(x); exit(1); } DEBUG_DESTRUCT_LOCK(&x->lock); /* pass the info down */ DEBUG_CONSTRUCT_LOCK(&x->lock); rc = PMIx_server_deliver_inventory(x->info, x->ninfo, NULL, 0, opcbfunc, x); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Deliver inventory failed: %s\n", PMIx_Error_string(rc)); PMIX_RELEASE(x); exit(1); } DEBUG_WAIT_THREAD(&x->lock); if (PMIX_SUCCESS != x->status) { fprintf(stderr, "Deliver inventory failed: %s\n", PMIx_Error_string(x->status)); PMIX_RELEASE(x); exit(1); } PMIX_RELEASE(x); /* setup to see sigchld on the forked tests */ PMIX_CONSTRUCT(&children, pmix_list_t); pmix_event_assign(&handler, pmix_globals.evbase, SIGCHLD, EV_SIGNAL | EV_PERSIST, wait_signal_callback, &handler); pmix_event_add(&handler, NULL); /* we have a single namespace for all clients */ atmp = NULL; for (n = 0; n < nprocs; n++) { if (0 > asprintf(&tmp, "%d", n)) { errno = ENOMEM; abort(); } PMIx_Argv_append_nosize(&atmp, tmp); free(tmp); } tmp = PMIx_Argv_join(atmp, ','); PMIx_Argv_free(atmp); x = PMIX_NEW(myxfer_t); set_namespace(nprocs, tmp, "foobar", opcbfunc, x); /* set common argv and env */ client_env = PMIx_Argv_copy(environ); PMIx_Argv_prepend_nosize(&client_argv, executable); wakeup = nprocs; myuid = getuid(); mygid = getgid(); /* if the nspace registration hasn't completed yet, * wait for it here */ DEBUG_WAIT_THREAD(&x->lock); free(tmp); PMIX_RELEASE(x); /* collect the launch blob */ x = PMIX_NEW(myxfer_t); ninfo = 1; PMIX_INFO_CREATE(info, ninfo); /* the 2nd info is going to carry our network allocation request * consisting of: * * PMIX_ALLOC_NETWORK_ID - caller-provided key for resulting allocation * PMIX_ALLOC_NETWORK_TYPE - type of network whose resources we want * PMIX_ALLOC_NETWORK_ENDPTS - number of endpoints from that network */ darray = (pmix_data_array_t *) malloc(sizeof(pmix_data_array_t)); darray->type = PMIX_INFO; darray->size = 4; PMIX_INFO_CREATE(darray->array, darray->size); iarray = (pmix_info_t *) darray->array; PMIX_INFO_LOAD(&iarray[0], PMIX_ALLOC_NETWORK_ID, "my.net.key", PMIX_STRING); PMIX_INFO_LOAD(&iarray[1], PMIX_ALLOC_NETWORK_TYPE, "tcp", PMIX_STRING); PMIX_INFO_LOAD(&iarray[2], PMIX_ALLOC_NETWORK_ENDPTS, &nprocs, PMIX_SIZE); PMIX_INFO_LOAD(&iarray[3], PMIX_ALLOC_NETWORK_SEC_KEY, NULL, PMIX_BOOL); /* now load the array */ PMIX_INFO_LOAD(&info[0], PMIX_ALLOC_NETWORK, darray, PMIX_DATA_ARRAY); PMIX_LOAD_NSPACE(ncache, "foobar"); rc = PMIx_server_setup_application(ncache, info, ninfo, sacbfunc, (void *) x); if (PMIX_SUCCESS != rc) { return rc; } DEBUG_WAIT_THREAD(&x->lock); DEBUG_DESTRUCT_LOCK(&x->lock); PMIX_INFO_FREE(info, ninfo); /* pass any returned data down */ DEBUG_CONSTRUCT_LOCK(&x->lock); rc = PMIx_server_setup_local_support(ncache, x->info, x->ninfo, opcbfunc, x); if (PMIX_SUCCESS != rc) { return rc; } DEBUG_WAIT_THREAD(&x->lock); PMIX_RELEASE(x); /* fork/exec the test */ pmix_strncpy(proc.nspace, "foobar", PMIX_MAX_NSLEN); for (n = 0; n < nprocs; n++) { proc.rank = n; x = PMIX_NEW(myxfer_t); if (PMIX_SUCCESS != (rc = PMIx_server_register_client(&proc, myuid, mygid, NULL, opcbfunc, x))) { fprintf(stderr, "Server register client failed with error %d\n", rc); PMIx_server_finalize(); return rc; } /* don't fork/exec the client until we know it is registered * so we avoid a potential race condition in the server */ DEBUG_WAIT_THREAD(&x->lock); PMIX_RELEASE(x); if (PMIX_SUCCESS != (rc = PMIx_server_setup_fork(&proc, &client_env))) { // n fprintf(stderr, "Server fork setup failed with error %d\n", rc); PMIx_server_finalize(); return rc; } pid = fork(); if (pid < 0) { fprintf(stderr, "Fork failed\n"); PMIx_server_finalize(); return -1; } child = PMIX_NEW(wait_tracker_t); child->pid = pid; pmix_list_append(&children, &child->super); if (pid == 0) { execve(executable, client_argv, client_env); /* Does not return */ exit(0); } } free(executable); PMIx_Argv_free(client_argv); PMIx_Argv_free(client_env); /* hang around until the client(s) finalize */ while (0 < wakeup) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } /* see if anyone exited with non-zero status */ n = 0; PMIX_LIST_FOREACH (child, &children, wait_tracker_t) { if (0 != child->exit_code) { fprintf(stderr, "Child %d exited with status %d - test FAILED\n", n, child->exit_code); goto done; } ++n; } /* deregister the nspace */ x = PMIX_NEW(myxfer_t); PMIx_server_deregister_nspace(ncache, opcbfunc, (void *) x); DEBUG_WAIT_THREAD(&x->lock); PMIX_RELEASE(x); done: /* deregister the event handlers */ PMIx_Deregister_event_handler(0, NULL, NULL); /* release any pub data */ PMIX_LIST_DESTRUCT(&pubdata); /* release the child tracker */ PMIX_LIST_DESTRUCT(&children); /* finalize the server library */ if (PMIX_SUCCESS != (rc = PMIx_server_finalize())) { fprintf(stderr, "Finalize failed with error %d\n", rc); exit_code = rc; } if (0 == exit_code) { fprintf(stderr, "Test finished OK!\n"); } else { fprintf(stderr, "TEST FAILED WITH ERROR %d\n", exit_code); } return exit_code; } static void set_namespace(int nprocs, char *ranks, char *nspace, pmix_op_cbfunc_t cbfunc, myxfer_t *x) { char *regex, *ppn; char hostname[PMIX_MAXHOSTNAMELEN]; int n; pmix_data_array_t *darray; pmix_info_t *info; pmix_rank_t rank; uint16_t lr; pmix_nspace_t ns; gethostname(hostname, sizeof(hostname)); x->ninfo = 7 + nprocs; PMIX_INFO_CREATE(x->info, x->ninfo); pmix_strncpy(x->info[0].key, PMIX_UNIV_SIZE, PMIX_MAX_KEYLEN); x->info[0].value.type = PMIX_UINT32; x->info[0].value.data.uint32 = nprocs; pmix_strncpy(x->info[1].key, PMIX_SPAWNED, PMIX_MAX_KEYLEN); x->info[1].value.type = PMIX_UINT32; x->info[1].value.data.uint32 = 0; pmix_strncpy(x->info[2].key, PMIX_LOCAL_SIZE, PMIX_MAX_KEYLEN); x->info[2].value.type = PMIX_UINT32; x->info[2].value.data.uint32 = nprocs; pmix_strncpy(x->info[3].key, PMIX_LOCAL_PEERS, PMIX_MAX_KEYLEN); x->info[3].value.type = PMIX_STRING; x->info[3].value.data.string = strdup(ranks); PMIx_generate_regex(hostname, ®ex); PMIX_INFO_LOAD(&x->info[4], PMIX_NODE_MAP, regex, PMIX_REGEX); PMIx_generate_ppn(ranks, &ppn); PMIX_INFO_LOAD(&x->info[5], PMIX_PROC_MAP, ppn, PMIX_REGEX); pmix_strncpy(x->info[6].key, PMIX_JOB_SIZE, PMIX_MAX_KEYLEN); x->info[6].value.type = PMIX_UINT32; x->info[6].value.data.uint32 = nprocs; for (n = 0; n < nprocs; n++) { pmix_strncpy(x->info[7 + n].key, PMIX_PROC_DATA, PMIX_MAX_KEYLEN); x->info[7 + n].value.type = PMIX_DATA_ARRAY; darray = (pmix_data_array_t *) malloc(sizeof(pmix_data_array_t)); darray->size = 2; darray->type = PMIX_INFO; PMIX_INFO_CREATE(darray->array, 2); info = (pmix_info_t *) darray->array; rank = n; PMIX_INFO_LOAD(&info[0], PMIX_RANK, &rank, PMIX_PROC_RANK); lr = n; PMIX_INFO_LOAD(&info[1], PMIX_LOCAL_RANK, &lr, PMIX_UINT16); x->info[7 + n].value.data.darray = darray; } PMIX_LOAD_NSPACE(ns, nspace); PMIx_server_register_nspace(ns, nprocs, x->info, x->ninfo, cbfunc, x); } static void errhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, info, ninfo, results, nresults, cbfunc, cbdata); pmix_output(0, "SERVER: ERRHANDLER CALLED WITH STATUS %d", status); } static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; pmix_output(0, "SERVER: ERRHANDLER REGISTRATION CALLBACK CALLED WITH STATUS %d, ref=%lu", status, (unsigned long) errhandler_ref); lock->status = status; DEBUG_WAKEUP_THREAD(lock); } static pmix_status_t connected(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(proc, server_object); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static pmix_status_t finalized(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(server_object); pmix_output(0, "SERVER: FINALIZED %s:%d WAKEUP %d", proc->nspace, proc->rank, wakeup); /* ensure we call the cbfunc so the proc can exit! */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static void abcbfunc(pmix_status_t status, void *cbdata) { myxfer_t *x = (myxfer_t *) cbdata; /* be sure to release the caller */ if (NULL != x->cbfunc) { x->cbfunc(status, x->cbdata); } PMIX_RELEASE(x); } static pmix_status_t abort_fn(const pmix_proc_t *proc, void *server_object, int status, const char msg[], pmix_proc_t procs[], size_t nprocs, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_status_t rc; myxfer_t *x; PMIX_HIDE_UNUSED_PARAMS(server_object, msg, nprocs); if (NULL != procs) { pmix_output(0, "SERVER: ABORT on %s:%d", procs[0].nspace, procs[0].rank); } else { pmix_output(0, "SERVER: ABORT OF ALL PROCS IN NSPACE %s", proc->nspace); } /* instead of aborting the specified procs, notify them * (if they have registered their errhandler) */ /* use the myxfer_t object to ensure we release * the caller when notification has been queued */ x = PMIX_NEW(myxfer_t); pmix_strncpy(x->caller.nspace, proc->nspace, PMIX_MAX_NSLEN); x->caller.rank = proc->rank; PMIX_INFO_CREATE(x->info, 2); pmix_strncpy(x->info[0].key, "DARTH", PMIX_MAX_KEYLEN); x->info[0].value.type = PMIX_INT8; x->info[0].value.data.int8 = 12; pmix_strncpy(x->info[1].key, "VADER", PMIX_MAX_KEYLEN); x->info[1].value.type = PMIX_DOUBLE; x->info[1].value.data.dval = 12.34; x->cbfunc = cbfunc; x->cbdata = cbdata; if (PMIX_SUCCESS != (rc = PMIx_Notify_event(status, &x->caller, PMIX_RANGE_NAMESPACE, x->info, 2, abcbfunc, x))) { pmix_output(0, "SERVER: FAILED NOTIFY ERROR %d", (int) rc); } return PMIX_SUCCESS; } static pmix_status_t fencenb_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, char *data, size_t ndata, pmix_modex_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo); pmix_output(0, "SERVER: FENCENB"); /* pass the provided data back to each participating proc */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, data, ndata, cbdata, NULL, NULL); } return PMIX_SUCCESS; } static pmix_status_t dmodex_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_modex_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(proc, info, ninfo); pmix_output(0, "SERVER: DMODEX"); /* if this is a timeout test, then do nothing */ if (istimeouttest) { return PMIX_SUCCESS; } /* we don't have any data for remote procs as this * test only runs one server - so report accordingly */ if (NULL != cbfunc) { cbfunc(PMIX_ERR_NOT_FOUND, NULL, 0, cbdata, NULL, NULL); } return PMIX_SUCCESS; } static pmix_status_t publish_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_locdat_t *p; size_t n; pmix_output(0, "SERVER: PUBLISH"); for (n = 0; n < ninfo; n++) { p = PMIX_NEW(pmix_locdat_t); pmix_strncpy(p->pdata.proc.nspace, proc->nspace, PMIX_MAX_NSLEN); p->pdata.proc.rank = proc->rank; pmix_strncpy(p->pdata.key, info[n].key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&p->pdata.value, (pmix_value_t *) &info[n].value); pmix_list_append(&pubdata, &p->super); } if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static pmix_status_t lookup_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_lookup_cbfunc_t cbfunc, void *cbdata) { pmix_locdat_t *p, *p2; pmix_list_t results; size_t i, n; pmix_pdata_t *pd = NULL; pmix_status_t ret = PMIX_ERR_NOT_FOUND; PMIX_HIDE_UNUSED_PARAMS(proc, info, ninfo); pmix_output(0, "SERVER: LOOKUP"); PMIX_CONSTRUCT(&results, pmix_list_t); for (n = 0; NULL != keys[n]; n++) { PMIX_LIST_FOREACH (p, &pubdata, pmix_locdat_t) { if (0 == strncmp(keys[n], p->pdata.key, PMIX_MAX_KEYLEN)) { p2 = PMIX_NEW(pmix_locdat_t); pmix_strncpy(p2->pdata.proc.nspace, p->pdata.proc.nspace, PMIX_MAX_NSLEN); p2->pdata.proc.rank = p->pdata.proc.rank; pmix_strncpy(p2->pdata.key, p->pdata.key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&p2->pdata.value, &p->pdata.value); pmix_list_append(&results, &p2->super); break; } } } if (0 < (n = pmix_list_get_size(&results))) { ret = PMIX_SUCCESS; PMIX_PDATA_CREATE(pd, n); for (i = 0; i < n; i++) { p = (pmix_locdat_t *) pmix_list_remove_first(&results); if (p) { pmix_strncpy(pd[i].proc.nspace, p->pdata.proc.nspace, PMIX_MAX_NSLEN); pd[i].proc.rank = p->pdata.proc.rank; pmix_strncpy(pd[i].key, p->pdata.key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&pd[i].value, &p->pdata.value); } } } PMIX_LIST_DESTRUCT(&results); if (NULL != cbfunc) { cbfunc(ret, pd, n, cbdata); } if (0 < n) { PMIX_PDATA_FREE(pd, n); } return PMIX_SUCCESS; } static pmix_status_t unpublish_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_locdat_t *p, *p2; size_t n; PMIX_HIDE_UNUSED_PARAMS(proc, info, ninfo); pmix_output(0, "SERVER: UNPUBLISH"); for (n = 0; NULL != keys[n]; n++) { PMIX_LIST_FOREACH_SAFE (p, p2, &pubdata, pmix_locdat_t) { if (0 == strncmp(keys[n], p->pdata.key, PMIX_MAX_KEYLEN)) { pmix_list_remove_item(&pubdata, &p->super); PMIX_RELEASE(p); break; } } } if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static void spcbfunc(pmix_status_t status, void *cbdata) { myxfer_t *x = (myxfer_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); if (NULL != x->spcbfunc) { x->spcbfunc(PMIX_SUCCESS, "DYNSPACE", x->cbdata); } } static pmix_status_t spawn_fn(const pmix_proc_t *proc, const pmix_info_t job_info[], size_t ninfo, const pmix_app_t apps[], size_t napps, pmix_spawn_cbfunc_t cbfunc, void *cbdata) { myxfer_t *x; size_t n; pmix_proc_t *pptr; bool spawned; PMIX_HIDE_UNUSED_PARAMS(proc, apps, napps); pmix_output(0, "SERVER: SPAWN"); /* check the job info for parent and spawned keys */ for (n = 0; n < ninfo; n++) { if (0 == strncmp(job_info[n].key, PMIX_PARENT_ID, PMIX_MAX_KEYLEN)) { pptr = job_info[n].value.data.proc; pmix_output(0, "SPAWN: Parent ID %s:%d", pptr->nspace, pptr->rank); } else if (0 == strncmp(job_info[n].key, PMIX_SPAWNED, PMIX_MAX_KEYLEN)) { spawned = PMIX_INFO_TRUE(&job_info[n]); pmix_output(0, "SPAWN: Spawned %s", spawned ? "TRUE" : "FALSE"); } } /* in practice, we would pass this request to the local * resource manager for launch, and then have that server * execute our callback function. For now, we will fake * the spawn and just pretend */ /* must register the nspace for the new procs before * we return to the caller */ x = PMIX_NEW(myxfer_t); x->spcbfunc = cbfunc; x->cbdata = cbdata; set_namespace(2, "0,1", "DYNSPACE", spcbfunc, x); return PMIX_SUCCESS; } static int numconnects = 0; static pmix_status_t connect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo); pmix_output(0, "SERVER: CONNECT"); /* in practice, we would pass this request to the local * resource manager for handling */ numconnects++; if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static pmix_status_t disconnect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo); pmix_output(0, "SERVER: DISCONNECT"); /* in practice, we would pass this request to the local * resource manager for handling */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static pmix_status_t register_event_fn(pmix_status_t *codes, size_t ncodes, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(codes, ncodes, info, ninfo); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static pmix_status_t deregister_events(pmix_status_t *codes, size_t ncodes, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(codes, ncodes, cbfunc, cbdata); return PMIX_SUCCESS; } static pmix_status_t notify_event(pmix_status_t code, const pmix_proc_t *source, pmix_data_range_t range, pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(code, source, range, info, ninfo, cbfunc, cbdata); return PMIX_SUCCESS; } typedef struct query_data_t { pmix_info_t *data; size_t ndata; } query_data_t; static pmix_status_t query_fn(pmix_proc_t *proct, pmix_query_t *queries, size_t nqueries, pmix_info_cbfunc_t cbfunc, void *cbdata) { size_t n; pmix_info_t *info; PMIX_HIDE_UNUSED_PARAMS(proct); pmix_output(0, "SERVER: QUERY"); if (NULL == cbfunc) { return PMIX_ERROR; } /* keep this simple */ PMIX_INFO_CREATE(info, nqueries); for (n = 0; n < nqueries; n++) { pmix_output(0, "\tKey: %s", queries[n].keys[0]); pmix_strncpy(info[n].key, queries[n].keys[0], PMIX_MAX_KEYLEN); info[n].value.type = PMIX_STRING; if (0 > asprintf(&info[n].value.data.string, "%d", (int) n)) { return PMIX_ERROR; } } cbfunc(PMIX_SUCCESS, info, nqueries, cbdata, NULL, NULL); return PMIX_SUCCESS; } static void tool_connect_fn(pmix_info_t *info, size_t ninfo, pmix_tool_connection_cbfunc_t cbfunc, void *cbdata) { pmix_proc_t proc; PMIX_HIDE_UNUSED_PARAMS(info, ninfo); pmix_output(0, "SERVER: TOOL CONNECT"); /* just pass back an arbitrary nspace */ pmix_strncpy(proc.nspace, "TOOL", PMIX_MAX_NSLEN); proc.rank = 0; if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, &proc, cbdata); } } static void log_fn(const pmix_proc_t *client, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(client, data, ndata, directives, ndirs); pmix_output(0, "SERVER: LOG"); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } } static void wait_signal_callback(int fd, short event, void *arg) { pmix_event_t *sig = (pmix_event_t *) arg; int status; pid_t pid; wait_tracker_t *t2; PMIX_HIDE_UNUSED_PARAMS(fd, event); if (SIGCHLD != pmix_event_get_signal(sig)) { return; } /* we can have multiple children leave but only get one * sigchild callback, so reap all the waitpids until we * don't get anything valid back */ while (1) { pid = waitpid(-1, &status, WNOHANG); if (-1 == pid && EINTR == errno) { /* try it again */ continue; } /* if we got garbage, then nothing we can do */ if (pid <= 0) { return; } /* we are already in an event, so it is safe to access the list */ PMIX_LIST_FOREACH (t2, &children, wait_tracker_t) { if (pid == t2->pid) { t2->exit_code = status; /* found it! */ if (0 != status && 0 == exit_code) { exit_code = status; } --wakeup; break; } } } } pmix-6.1.1~rc2/test/simple/simptest.c0000664000175000017500000013551015203536752017766 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2023-2024 Triad National Security, LLC. All rights reserved. * Copyright (c) 2021-2024 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include #include #include #include #include #include #include #include #include "src/class/pmix_list.h" #include "src/runtime/pmix_progress_threads.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "simptest.h" static pmix_status_t connected(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t finalized(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t abort_fn(const pmix_proc_t *proc, void *server_object, int status, const char msg[], pmix_proc_t procs[], size_t nprocs, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t fencenb_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, char *data, size_t ndata, pmix_modex_cbfunc_t cbfunc, void *cbdata); static pmix_status_t dmodex_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_modex_cbfunc_t cbfunc, void *cbdata); static pmix_status_t publish_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t lookup_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_lookup_cbfunc_t cbfunc, void *cbdata); static pmix_status_t unpublish_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t spawn_fn(const pmix_proc_t *proc, const pmix_info_t job_info[], size_t ninfo, const pmix_app_t apps[], size_t napps, pmix_spawn_cbfunc_t cbfunc, void *cbdata); static pmix_status_t connect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t disconnect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t register_event_fn(pmix_status_t *codes, size_t ncodes, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t deregister_events(pmix_status_t *codes, size_t ncodes, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t notify_event(pmix_status_t code, const pmix_proc_t *source, pmix_data_range_t range, pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t query_fn(pmix_proc_t *proct, pmix_query_t *queries, size_t nqueries, pmix_info_cbfunc_t cbfunc, void *cbdata); static void tool_connect_fn(pmix_info_t *info, size_t ninfo, pmix_tool_connection_cbfunc_t cbfunc, void *cbdata); static void log_fn(const pmix_proc_t *client, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t alloc_fn(const pmix_proc_t *client, pmix_alloc_directive_t directive, const pmix_info_t data[], size_t ndata, pmix_info_cbfunc_t cbfunc, void *cbdata); static pmix_status_t jctrl_fn(const pmix_proc_t *requestor, const pmix_proc_t targets[], size_t ntargets, const pmix_info_t directives[], size_t ndirs, pmix_info_cbfunc_t cbfunc, void *cbdata); static pmix_status_t mon_fn(const pmix_proc_t *requestor, const pmix_info_t *monitor, pmix_status_t error, const pmix_info_t directives[], size_t ndirs, pmix_info_cbfunc_t cbfunc, void *cbdata); static pmix_status_t grp_fn(pmix_group_operation_t op, char *gpid, const pmix_proc_t procs[], size_t nprocs, const pmix_info_t directives[], size_t ndirs, pmix_info_cbfunc_t cbfunc, void *cbdata); static pmix_server_module_t mymodule = { .client_connected = connected, .client_finalized = finalized, .abort = abort_fn, .fence_nb = fencenb_fn, .direct_modex = dmodex_fn, .publish = publish_fn, .lookup = lookup_fn, .unpublish = unpublish_fn, .spawn = spawn_fn, .connect = connect_fn, .disconnect = disconnect_fn, .register_events = register_event_fn, .deregister_events = deregister_events, .notify_event = notify_event, .query = query_fn, .tool_connected = tool_connect_fn, .log = log_fn, .allocate = alloc_fn, .job_control = jctrl_fn, .monitor = mon_fn, .group = grp_fn }; typedef struct { pmix_list_item_t super; pmix_pdata_t pdata; } pmix_locdat_t; PMIX_CLASS_INSTANCE(pmix_locdat_t, pmix_list_item_t, NULL, NULL); typedef struct { pmix_object_t super; mylock_t lock; pmix_event_t ev; pmix_proc_t caller; pmix_info_t *info; size_t ninfo; pmix_op_cbfunc_t cbfunc; pmix_spawn_cbfunc_t spcbfunc; pmix_release_cbfunc_t relcbfunc; pmix_info_cbfunc_t infocbfunc; void *cbdata; } myxfer_t; static void xfcon(myxfer_t *p) { DEBUG_CONSTRUCT_LOCK(&p->lock); p->info = NULL; p->ninfo = 0; p->cbfunc = NULL; p->spcbfunc = NULL; p->cbdata = NULL; } static void xfdes(myxfer_t *p) { DEBUG_DESTRUCT_LOCK(&p->lock); if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->ninfo); } } PMIX_CLASS_INSTANCE(myxfer_t, pmix_object_t, xfcon, xfdes); typedef struct { pmix_list_item_t super; int exit_code; pid_t pid; } wait_tracker_t; PMIX_CLASS_INSTANCE(wait_tracker_t, pmix_list_item_t, NULL, NULL); static volatile int wakeup; static int exit_code = 0; static pmix_list_t pubdata; static pmix_event_t handler; static pmix_list_t children; static bool istimeouttest = false; static mylock_t globallock; static bool model = false; static bool xversion = false; static pmix_event_base_t *simptest_evbase = NULL; static bool abort_has_been_called = false; static void set_namespace(int nprocs, char *nspace, pmix_op_cbfunc_t cbfunc, myxfer_t *x); static void errhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata); static void wait_signal_callback(int fd, short event, void *arg); static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata); static void opcbfunc(pmix_status_t status, void *cbdata) { myxfer_t *x = (myxfer_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); /* release the caller, if necessary */ if (NULL != x->cbfunc) { x->cbfunc(PMIX_SUCCESS, x->cbdata); } DEBUG_WAKEUP_THREAD(&x->lock); } static void dlcbfunc(int sd, short flags, void *cbdata) { myxfer_t *x = (myxfer_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, flags); PMIx_server_deliver_inventory(x->info, x->ninfo, NULL, 0, opcbfunc, (void *) x); } static void infocbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { mylock_t *lock = (mylock_t *) cbdata; myxfer_t *x; size_t n; /* we don't have any place to send this, so for test * purposes only, let's push it back down for processing. * Note: it must be thread-shifted first as we are in * the callback event thread of the underlying PMIx * server */ x = PMIX_NEW(myxfer_t); x->ninfo = ninfo; if (0 < ninfo) { PMIX_INFO_CREATE(x->info, x->ninfo); } for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&x->info[n], &info[n]); } SIMPTEST_THREADSHIFT(x, dlcbfunc); if (NULL != release_fn) { release_fn(release_cbdata); } lock->status = status; DEBUG_WAKEUP_THREAD(lock); } static void setup_cbfunc(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *provided_cbdata, pmix_op_cbfunc_t cbfunc, void *cbdata) { myxfer_t *x = (myxfer_t *) provided_cbdata; size_t n; PMIX_HIDE_UNUSED_PARAMS(status); /* transfer it to the caddy for return to the main thread */ if (0 < ninfo) { PMIX_INFO_CREATE(x->info, ninfo); x->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&x->info[n], &info[n]); } } /* let the library release the data and cleanup from * the operation */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } DEBUG_WAKEUP_THREAD(&x->lock); } /* this is an event notification function that we explicitly request * be called when the PMIX_MODEL_DECLARED notification is issued. * We could catch it in the general event notification function and test * the status to see if the status matched, but it often is simpler * to declare a use-specific notification callback point. In this case, * we are asking to know whenever a model is declared as a means * of testing server self-notification */ static void model_callback(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { size_t n; PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, results, nresults); /* just let us know it was received */ fprintf(stderr, "SIMPTEST: Model event handler called with status %d(%s)\n", status, PMIx_Error_string(status)); for (n = 0; n < ninfo; n++) { if (PMIX_STRING == info[n].value.type) { fprintf(stderr, "\t%s:\t%s\n", info[n].key, info[n].value.data.string); } } /* we must NOT tell the event handler state machine that we * are the last step as that will prevent it from notifying * anyone else that might be listening for declarations */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } DEBUG_WAKEUP_THREAD(&globallock); } static void set_handler_default(int sig) { struct sigaction act; act.sa_handler = SIG_DFL; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(sig, &act, (struct sigaction *) 0); } int main(int argc, char **argv) { char **client_env = NULL; char **client_argv = NULL; char *executable = NULL; int rc, nprocs = 1, n, k; uid_t myuid; gid_t mygid; pid_t pid; myxfer_t *x; pmix_proc_t proc; wait_tracker_t *child; pmix_info_t *info; size_t ninfo; mylock_t mylock; pmix_status_t code; sigset_t unblock; /* smoke test */ if (PMIX_SUCCESS != 0) { fprintf(stderr, "ERROR IN COMPUTING CONSTANTS: PMIX_SUCCESS = %d\n", PMIX_SUCCESS); exit(1); } /* see if we were passed the number of procs to run or * the executable to use */ for (n = 1; n < argc; n++) { if (0 == strcmp("-n", argv[n]) && NULL != argv[n + 1]) { nprocs = strtol(argv[n + 1], NULL, 10); ++n; // step over the argument } else if (0 == strcmp("-e", argv[n]) && NULL != argv[n + 1]) { executable = strdup(argv[n + 1]); /* check for timeout test */ if (NULL != strstr(executable, "simptimeout")) { istimeouttest = true; } for (k = n + 2; NULL != argv[k]; k++) { PMIx_Argv_append_nosize(&client_argv, argv[k]); } n += k; } else if (0 == strcmp("-h", argv[n])) { /* print the options and exit */ fprintf(stderr, "usage: simptest \n"); fprintf(stderr, " -n N Number of clients to run\n"); fprintf(stderr, " -e foo Name of the client executable to run (default: simpclient\n"); fprintf(stderr, " -u Enable legacy usock support\n"); fprintf(stderr, " -xversion Cross-version test - simulate single node only\n"); exit(0); } else if (0 == strcmp("-model", argv[n]) || 0 == strcmp("--model", argv[n])) { /* test network support */ model = true; } else if (0 == strcmp("-x", argv[n]) || 0 == strcmp("-xversion", argv[n]) || 0 == strcmp("--xversion", argv[n])) { xversion = true; } } if (NULL == executable) { executable = strdup("./simpclient"); } /* check for executable existence and permissions */ if (0 != access(executable, X_OK)) { fprintf(stderr, "Executable %s not found or missing executable permissions\n", executable); exit(1); } fprintf(stderr, "Testing version %s\n", PMIx_Get_version()); /* ensure that SIGCHLD is unblocked as we need to capture it */ if (0 != sigemptyset(&unblock)) { fprintf(stderr, "SIGEMPTYSET FAILED\n"); exit(1); } if (0 != sigaddset(&unblock, SIGCHLD)) { fprintf(stderr, "SIGADDSET FAILED\n"); exit(1); } if (0 != sigprocmask(SIG_UNBLOCK, &unblock, NULL)) { fprintf(stderr, "SIG_UNBLOCK FAILED\n"); exit(1); } /* setup the server library and tell it to support tool connections */ ninfo = 3; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_SERVER_TOOL_SUPPORT, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[1], PMIX_SERVER_SCHEDULER, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[2], PMIX_SERVER_SHARE_TOPOLOGY, NULL, PMIX_BOOL); if (PMIX_SUCCESS != (rc = PMIx_server_init(&mymodule, info, ninfo))) { fprintf(stderr, "Init failed with error %s\n", PMIx_Error_string(rc)); return rc; } PMIX_INFO_FREE(info, ninfo); /* get our own event base */ simptest_evbase = pmix_progress_thread_init("simptest"); pmix_progress_thread_start("simptest"); /* register the default errhandler */ DEBUG_CONSTRUCT_LOCK(&mylock); ninfo = 1; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_EVENT_HDLR_NAME, "SIMPTEST-DEFAULT", PMIX_STRING); PMIx_Register_event_handler(NULL, 0, info, ninfo, errhandler, errhandler_reg_callbk, (void *) &mylock); DEBUG_WAIT_THREAD(&mylock); PMIX_INFO_FREE(info, ninfo); if (PMIX_SUCCESS != mylock.status) { exit(mylock.status); } DEBUG_DESTRUCT_LOCK(&mylock); /* register a handler specifically for when models declare */ DEBUG_CONSTRUCT_LOCK(&mylock); ninfo = 1; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_EVENT_HDLR_NAME, "SIMPTEST-MODEL", PMIX_STRING); code = PMIX_MODEL_DECLARED; PMIx_Register_event_handler(&code, 1, info, ninfo, model_callback, NULL, NULL); PMIX_INFO_FREE(info, ninfo); if (PMIX_SUCCESS != mylock.status) { exit(mylock.status); } DEBUG_DESTRUCT_LOCK(&mylock); /* setup the pub data, in case it is used */ PMIX_CONSTRUCT(&pubdata, pmix_list_t); /* setup to see sigchld on the forked tests */ PMIX_CONSTRUCT(&children, pmix_list_t); pmix_event_assign(&handler, pmix_globals.evbase, SIGCHLD, EV_SIGNAL | EV_PERSIST, wait_signal_callback, &handler); pmix_event_add(&handler, NULL); /* we have a single namespace for all clients */ x = PMIX_NEW(myxfer_t); set_namespace(nprocs, "foobar", opcbfunc, x); /* if the nspace registration hasn't completed yet, * wait for it here */ DEBUG_WAIT_THREAD(&x->lock); PMIX_RELEASE(x); /* set common argv and env */ client_env = PMIx_Argv_copy(environ); PMIx_Argv_prepend_nosize(&client_argv, executable); wakeup = nprocs; myuid = getuid(); mygid = getgid(); /* collect our inventory */ DEBUG_CONSTRUCT_LOCK(&mylock); fprintf(stderr, "Collecting inventory\n"); if (PMIX_SUCCESS != (rc = PMIx_server_collect_inventory(NULL, 0, infocbfunc, (void *) &mylock))) { fprintf(stderr, "Collect inventory failed: %d\n", rc); DEBUG_DESTRUCT_LOCK(&mylock); goto done; } DEBUG_WAIT_THREAD(&mylock); fprintf(stderr, "Inventory collected: %d\n", mylock.status); if (PMIX_SUCCESS != mylock.status) { exit(mylock.status); } DEBUG_DESTRUCT_LOCK(&mylock); /* fork/exec the test */ pmix_strncpy(proc.nspace, "foobar", PMIX_MAX_NSLEN); for (n = 0; n < nprocs; n++) { proc.rank = n; if (PMIX_SUCCESS != (rc = PMIx_server_setup_fork(&proc, &client_env))) { fprintf(stderr, "Server fork setup failed with error %d\n", rc); PMIx_server_finalize(); return rc; } x = PMIX_NEW(myxfer_t); if (PMIX_SUCCESS != (rc = PMIx_server_register_client(&proc, myuid, mygid, NULL, opcbfunc, x))) { fprintf(stderr, "Server register client failed with error %d\n", rc); PMIx_server_finalize(); return rc; } /* don't fork/exec the client until we know it is registered * so we avoid a potential race condition in the server */ DEBUG_WAIT_THREAD(&x->lock); PMIX_RELEASE(x); pid = fork(); if (pid < 0) { fprintf(stderr, "Fork failed\n"); PMIx_server_finalize(); return -1; } if (pid == 0) { sigset_t sigs; set_handler_default(SIGTERM); set_handler_default(SIGINT); set_handler_default(SIGHUP); set_handler_default(SIGPIPE); set_handler_default(SIGCHLD); sigprocmask(0, 0, &sigs); sigprocmask(SIG_UNBLOCK, &sigs, 0); execve(executable, client_argv, client_env); /* Does not return */ exit(0); } else { child = PMIX_NEW(wait_tracker_t); child->pid = pid; pmix_list_append(&children, &child->super); } } PMIx_Argv_free(client_argv); PMIx_Argv_free(client_env); /* hang around until the client(s) finalize */ while (0 < wakeup) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } /* see if anyone exited with non-zero status unless the test * was expected to do so */ if (NULL == strstr(executable, "simpdie") || (abort_has_been_called && 248 == exit_code)) { n = 0; PMIX_LIST_FOREACH (child, &children, wait_tracker_t) { if (0 != child->exit_code && !abort_has_been_called) { fprintf(stderr, "Child %d [%d] exited with status %d - test FAILED\n", n, child->pid, child->exit_code); } ++n; } } else if (1 == exit_code) { exit_code = 0; } free(executable); /* try notifying ourselves */ ninfo = 3; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_PROGRAMMING_MODEL, "PMIX", PMIX_STRING); PMIX_INFO_LOAD(&info[1], PMIX_MODEL_LIBRARY_NAME, "test", PMIX_STRING); /* mark that it is not to go to any default handlers */ PMIX_INFO_LOAD(&info[2], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); DEBUG_CONSTRUCT_LOCK(&globallock); PMIx_Notify_event(PMIX_MODEL_DECLARED, &pmix_globals.myid, PMIX_RANGE_PROC_LOCAL, info, ninfo, NULL, NULL); DEBUG_WAIT_THREAD(&globallock); DEBUG_DESTRUCT_LOCK(&globallock); PMIX_INFO_FREE(info, ninfo); #if 0 fprintf(stderr, "TEST NONDEFAULT NOTIFICATION\n"); /* verify that notifications don't recirculate */ ninfo = 1; PMIX_INFO_CREATE(info, ninfo); /* mark that it is not to go to any default handlers */ PMIX_INFO_LOAD(&info[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); PMIx_Notify_event(PMIX_ERR_DEBUGGER_RELEASE, &pmix_globals.myid, PMIX_RANGE_LOCAL, info, ninfo, NULL, NULL); PMIX_INFO_FREE(info, ninfo); /* wait a little in case we get notified */ for (ninfo=0; ninfo < 100000; ninfo++) { struct timespec t = {0, 100}; nanosleep(&t, NULL); } #endif done: /* deregister the event handlers */ PMIx_Deregister_event_handler(0, NULL, NULL); /* release any pub data */ PMIX_LIST_DESTRUCT(&pubdata); /* release the child tracker */ PMIX_LIST_DESTRUCT(&children); /* finalize the server library */ if (PMIX_SUCCESS != (rc = PMIx_server_finalize())) { fprintf(stderr, "Finalize failed with error %d\n", rc); exit_code = rc; } if (0 == exit_code) { fprintf(stderr, "Test finished OK!\n"); } else { fprintf(stderr, "TEST FAILED WITH ERROR %d\n", exit_code); } return exit_code; } static void set_namespace(int nprocs, char *nspace, pmix_op_cbfunc_t cbfunc, myxfer_t *x) { char *regex, *ppn, *rks; int n, m, k, nnodes; pmix_data_array_t *array; pmix_info_t *info, *iptr, *ip; pmix_info_t *isv1, *isv2; myxfer_t cd, lock; pmix_status_t rc; char tmp[50], **agg = NULL; pmix_nspace_t ns; /* everything on one node */ PMIx_generate_regex(pmix_globals.hostname, ®ex); for (m = 0; m < nprocs; m++) { snprintf(tmp, 50, "%d", m); PMIx_Argv_append_nosize(&agg, tmp); memset(tmp, 0, 50); } rks = PMIx_Argv_join(agg, ','); PMIx_Argv_free(agg); PMIx_generate_ppn(rks, &ppn); free(rks); nnodes = 1; x->ninfo = 1 + nprocs + nnodes; PMIX_INFO_CREATE(x->info, x->ninfo); n = 0; pmix_strncpy(x->info[n].key, PMIX_JOB_INFO_ARRAY, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_DATA_ARRAY; if (model) { PMIX_DATA_ARRAY_CREATE(x->info[n].value.data.darray, 10, PMIX_INFO); } else { PMIX_DATA_ARRAY_CREATE(x->info[n].value.data.darray, 9, PMIX_INFO); } iptr = (pmix_info_t *) x->info[n].value.data.darray->array; PMIX_INFO_LOAD(&iptr[0], PMIX_NODE_MAP, regex, PMIX_REGEX); free(regex); isv1 = &iptr[0]; PMIX_INFO_LOAD(&iptr[1], PMIX_PROC_MAP, ppn, PMIX_REGEX); free(ppn); isv2 = &iptr[1]; PMIX_INFO_LOAD(&iptr[2], PMIX_JOB_SIZE, &nprocs, PMIX_UINT32); PMIX_INFO_LOAD(&iptr[3], PMIX_JOBID, "1234", PMIX_STRING); PMIX_INFO_LOAD(&iptr[4], PMIX_UNIV_SIZE, &nprocs, PMIX_UINT32); PMIX_INFO_LOAD(&iptr[5], PMIX_MAX_PROCS, &nprocs, PMIX_UINT32); m = 1; PMIX_INFO_LOAD(&iptr[6], PMIX_JOB_NUM_APPS, &m, PMIX_UINT32); PMIX_INFO_LOAD(&iptr[7], PMIX_NUM_NODES, &nnodes, PMIX_UINT32); PMIX_INFO_LOAD(&iptr[8], PMIX_SPAWNED, NULL, PMIX_BOOL); if (model) { PMIX_INFO_LOAD(&iptr[9], PMIX_PROGRAMMING_MODEL, "ompi", PMIX_STRING); } ++n; /* we have the required info to run setup_app, so do that now */ PMIX_INFO_CREATE(iptr, 4); PMIX_INFO_XFER(&iptr[0], isv1); PMIX_INFO_XFER(&iptr[1], isv2); PMIX_INFO_LOAD(&iptr[2], PMIX_SETUP_APP_ENVARS, NULL, PMIX_BOOL); PMIX_LOAD_KEY(iptr[3].key, PMIX_ALLOC_FABRIC); iptr[3].value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(iptr[3].value.data.darray, 2, PMIX_INFO); ip = (pmix_info_t *) iptr[3].value.data.darray->array; if (0 > asprintf(&rks, "%s.net", nspace)) { errno = ENOMEM; abort(); } PMIX_INFO_LOAD(&ip[0], PMIX_ALLOC_FABRIC_ID, rks, PMIX_STRING); free(rks); PMIX_INFO_LOAD(&ip[1], PMIX_ALLOC_FABRIC_SEC_KEY, NULL, PMIX_BOOL); PMIX_CONSTRUCT(&cd, myxfer_t); if (PMIX_SUCCESS != (rc = PMIx_server_setup_application(nspace, iptr, 4, setup_cbfunc, &cd))) { pmix_output(0, "[%s:%d] PMIx_server_setup_application failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); DEBUG_DESTRUCT_LOCK(&cd.lock); } else { DEBUG_WAIT_THREAD(&cd.lock); } PMIX_INFO_FREE(iptr, 4); /* use the results to setup the local subsystems */ PMIX_CONSTRUCT(&lock, myxfer_t); if (PMIX_SUCCESS != (rc = PMIx_server_setup_local_support(nspace, cd.info, cd.ninfo, opcbfunc, &lock))) { pmix_output(0, "[%s:%d] PMIx_server_setup_local_support failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); } else { DEBUG_WAIT_THREAD(&lock.lock); } PMIX_DESTRUCT(&lock); PMIX_DESTRUCT(&cd); /* create the node-info arrays */ for (m = 0; m < nnodes; m++) { pmix_strncpy(x->info[n].key, PMIX_NODE_INFO_ARRAY, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(x->info[n].value.data.darray, 3, PMIX_INFO); iptr = (pmix_info_t *) x->info[n].value.data.darray->array; PMIX_INFO_LOAD(&iptr[0], PMIX_HOSTNAME, pmix_globals.hostname, PMIX_STRING); PMIX_INFO_LOAD(&iptr[1], PMIX_NODEID, &m, PMIX_UINT32); PMIX_INFO_LOAD(&iptr[2], PMIX_NODE_SIZE, &nprocs, PMIX_UINT32); ++n; } /* add the proc-specific data */ for (m = 0; m < nprocs; m++) { pmix_strncpy(x->info[n].key, PMIX_PROC_DATA, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(array, 6, PMIX_INFO); x->info[n].value.data.darray = array; info = (pmix_info_t *) array->array; k = 0; pmix_strncpy(info[k].key, PMIX_RANK, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_PROC_RANK; info[k].value.data.rank = m; ++k; pmix_strncpy(info[k].key, PMIX_GLOBAL_RANK, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_PROC_RANK; info[k].value.data.rank = m; ++k; pmix_strncpy(info[k].key, PMIX_LOCAL_RANK, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_UINT16; info[k].value.data.uint16 = m; ++k; pmix_strncpy(info[k].key, PMIX_NODE_RANK, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_UINT16; info[k].value.data.uint16 = m; ++k; pmix_strncpy(info[k].key, PMIX_NODEID, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_UINT32; info[k].value.data.uint32 = m % 3; ++k; pmix_strncpy(info[k].key, PMIX_HOSTNAME, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_STRING; info[k].value.data.string = strdup(pmix_globals.hostname); ++k; /* move to next proc */ ++n; } PMIX_LOAD_NSPACE(ns, nspace); PMIx_server_register_nspace(ns, nprocs, x->info, x->ninfo, cbfunc, x); } static void errhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, info, ninfo, results, nresults); pmix_output(0, "SERVER: ERRHANDLER CALLED WITH STATUS %s", PMIx_Error_string(status)); if (PMIX_ERR_LOST_CONNECTION == status) { // give the procs a chance to do something usleep(10000); /* let the other clients know */ PMIx_Notify_event(PMIX_ERR_PROC_ABORTED, &pmix_globals.myid, PMIX_RANGE_LOCAL, NULL, 0, NULL, NULL); } /* we must NOT tell the event handler state machine that we * are the last step as that will prevent it from notifying * anyone else that might be listening for declarations */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } } static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status, errhandler_ref, cbdata); lock->status = status; DEBUG_WAKEUP_THREAD(lock); } static pmix_status_t connected(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(proc, server_object, cbfunc, cbdata); return PMIX_OPERATION_SUCCEEDED; } static pmix_status_t finalized(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(proc, server_object, cbfunc, cbdata); return PMIX_OPERATION_SUCCEEDED; } static pmix_status_t abort_fn(const pmix_proc_t *proc, void *server_object, int status, const char msg[], pmix_proc_t procs[], size_t nprocs, pmix_op_cbfunc_t cbfunc, void *cbdata) { wait_tracker_t *t2; PMIX_HIDE_UNUSED_PARAMS(server_object, status, msg, nprocs, cbfunc, cbdata); if (NULL != procs) { pmix_output(0, "SERVER: ABORT on %s:%d", procs[0].nspace, procs[0].rank); } else { pmix_output(0, "SERVER: ABORT OF ALL PROCS IN NSPACE %s", proc->nspace); } /* mark that the client called abort so we know it will simply exit */ abort_has_been_called = true; PMIX_LIST_FOREACH (t2, &children, wait_tracker_t) { kill(t2->pid, SIGKILL); } return PMIX_SUCCESS; } static void fencbfn(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); /* pass the provided data back to each participating proc */ if (NULL != scd->cbfunc.modexcbfunc) { scd->cbfunc.modexcbfunc(scd->status, scd->data, scd->ndata, scd->cbdata, NULL, NULL); } PMIX_RELEASE(scd); } static pmix_status_t fencenb_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, char *data, size_t ndata, pmix_modex_cbfunc_t cbfunc, void *cbdata) { pmix_shift_caddy_t *scd; PMIX_HIDE_UNUSED_PARAMS(procs, nprocs); scd = PMIX_NEW(pmix_shift_caddy_t); scd->status = PMIX_SUCCESS; if (NULL != info) { if (PMIX_CHECK_KEY(&info[ninfo-1], PMIX_LOCAL_COLLECTIVE_STATUS)) { scd->status = info[ninfo-1].value.data.status; } } scd->data = data; scd->ndata = ndata; scd->cbfunc.modexcbfunc = cbfunc; scd->cbdata = cbdata; SIMPTEST_THREADSHIFT(scd, fencbfn); return PMIX_SUCCESS; } static void modex_resp(pmix_status_t status, char *data, size_t sz, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t *) cbdata; scd->status = status; scd->data = (char *) malloc(sz); memcpy((char *) scd->data, data, sz); scd->ndata = sz; SIMPTEST_THREADSHIFT(scd, fencbfn); } static void dmdxfn(int sd, short args, void *cbdata) { pmix_shift_caddy_t *scd = (pmix_shift_caddy_t *) cbdata; pmix_proc_t proc; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(sd, args); /* get the data */ PMIX_LOAD_PROCID(&proc, scd->pname.nspace, scd->pname.rank); rc = PMIx_server_dmodex_request(&proc, modex_resp, scd); if (PMIX_SUCCESS != rc) { scd->status = rc; scd->data = NULL; scd->ndata = 0; SIMPTEST_THREADSHIFT(scd, fencbfn); } return; } static pmix_status_t dmodex_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_modex_cbfunc_t cbfunc, void *cbdata) { pmix_shift_caddy_t *scd; PMIX_HIDE_UNUSED_PARAMS(info, ninfo); /* if this is a timeout test, then do nothing */ if (istimeouttest) { return PMIX_SUCCESS; } scd = PMIX_NEW(pmix_shift_caddy_t); scd->pname.nspace = strdup(proc->nspace); scd->pname.rank = proc->rank; scd->cbfunc.modexcbfunc = cbfunc; scd->cbdata = cbdata; SIMPTEST_THREADSHIFT(scd, dmdxfn); return PMIX_SUCCESS; } static pmix_status_t publish_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_locdat_t *p; size_t n; PMIX_HIDE_UNUSED_PARAMS(cbfunc, cbdata); for (n = 0; n < ninfo; n++) { p = PMIX_NEW(pmix_locdat_t); pmix_strncpy(p->pdata.proc.nspace, proc->nspace, PMIX_MAX_NSLEN); p->pdata.proc.rank = proc->rank; pmix_strncpy(p->pdata.key, info[n].key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&p->pdata.value, (pmix_value_t *) &info[n].value); pmix_list_append(&pubdata, &p->super); } return PMIX_OPERATION_SUCCEEDED; } typedef struct { pmix_event_t ev; pmix_pdata_t *pd; size_t n; pmix_lookup_cbfunc_t cbfunc; void *cbdata; } lkobj_t; static void lkcbfn(int sd, short args, void *cbdata) { lkobj_t *lk = (lkobj_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); lk->cbfunc(PMIX_SUCCESS, lk->pd, lk->n, lk->cbdata); PMIX_PDATA_FREE(lk->pd, lk->n); free(lk); } static pmix_status_t lookup_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_lookup_cbfunc_t cbfunc, void *cbdata) { pmix_locdat_t *p, *p2; pmix_list_t results; size_t i, n; pmix_pdata_t *pd = NULL; pmix_status_t ret = PMIX_ERR_NOT_FOUND; lkobj_t *lk; PMIX_HIDE_UNUSED_PARAMS(proc, info, ninfo); PMIX_CONSTRUCT(&results, pmix_list_t); for (n = 0; NULL != keys[n]; n++) { PMIX_LIST_FOREACH (p, &pubdata, pmix_locdat_t) { if (0 == strncmp(keys[n], p->pdata.key, PMIX_MAX_KEYLEN)) { p2 = PMIX_NEW(pmix_locdat_t); pmix_strncpy(p2->pdata.proc.nspace, p->pdata.proc.nspace, PMIX_MAX_NSLEN); p2->pdata.proc.rank = p->pdata.proc.rank; pmix_strncpy(p2->pdata.key, p->pdata.key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&p2->pdata.value, &p->pdata.value); pmix_list_append(&results, &p2->super); break; } } } if (0 < (n = pmix_list_get_size(&results))) { ret = PMIX_SUCCESS; PMIX_PDATA_CREATE(pd, n); for (i = 0; i < n; i++) { p = (pmix_locdat_t *) pmix_list_remove_first(&results); if (p) { pmix_strncpy(pd[i].proc.nspace, p->pdata.proc.nspace, PMIX_MAX_NSLEN); pd[i].proc.rank = p->pdata.proc.rank; pmix_strncpy(pd[i].key, p->pdata.key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&pd[i].value, &p->pdata.value); } } } PMIX_LIST_DESTRUCT(&results); if (PMIX_SUCCESS == ret) { lk = (lkobj_t *) malloc(sizeof(lkobj_t)); lk->pd = pd; lk->n = n; lk->cbfunc = cbfunc; lk->cbdata = cbdata; SIMPTEST_THREADSHIFT(lk, lkcbfn); } return ret; } static pmix_status_t unpublish_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_locdat_t *p, *p2; size_t n; PMIX_HIDE_UNUSED_PARAMS(proc, info, ninfo, cbfunc, cbdata); for (n = 0; NULL != keys[n]; n++) { PMIX_LIST_FOREACH_SAFE (p, p2, &pubdata, pmix_locdat_t) { if (0 == strncmp(keys[n], p->pdata.key, PMIX_MAX_KEYLEN)) { pmix_list_remove_item(&pubdata, &p->super); PMIX_RELEASE(p); break; } } } return PMIX_OPERATION_SUCCEEDED; } static void spcbfunc(pmix_status_t status, void *cbdata) { myxfer_t *x = (myxfer_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); if (NULL != x->spcbfunc) { x->spcbfunc(PMIX_SUCCESS, "DYNSPACE", x->cbdata); } } static pmix_status_t spawn_fn(const pmix_proc_t *proc, const pmix_info_t job_info[], size_t ninfo, const pmix_app_t apps[], size_t napps, pmix_spawn_cbfunc_t cbfunc, void *cbdata) { myxfer_t *x; size_t n; pmix_proc_t *pptr; bool spawned; PMIX_HIDE_UNUSED_PARAMS(proc, apps, napps); /* check the job info for parent and spawned keys */ for (n = 0; n < ninfo; n++) { if (0 == strncmp(job_info[n].key, PMIX_PARENT_ID, PMIX_MAX_KEYLEN)) { pptr = job_info[n].value.data.proc; pmix_output(0, "SPAWN: Parent ID %s:%d", pptr->nspace, pptr->rank); } else if (0 == strncmp(job_info[n].key, PMIX_SPAWNED, PMIX_MAX_KEYLEN)) { spawned = PMIX_INFO_TRUE(&job_info[n]); pmix_output(0, "SPAWN: Spawned %s", spawned ? "TRUE" : "FALSE"); } } /* in practice, we would pass this request to the local * resource manager for launch, and then have that server * execute our callback function. For now, we will fake * the spawn and just pretend */ /* must register the nspace for the new procs before * we return to the caller */ x = PMIX_NEW(myxfer_t); x->spcbfunc = cbfunc; x->cbdata = cbdata; set_namespace(2, "DYNSPACE", spcbfunc, x); return PMIX_SUCCESS; } static int numconnects = 0; static pmix_status_t connect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo, cbfunc, cbdata); /* in practice, we would pass this request to the local * resource manager for handling */ numconnects++; return PMIX_OPERATION_SUCCEEDED; } static pmix_status_t disconnect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo, cbfunc, cbdata); return PMIX_OPERATION_SUCCEEDED; } static pmix_status_t register_event_fn(pmix_status_t *codes, size_t ncodes, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(codes, ncodes, info, ninfo, cbfunc, cbdata); return PMIX_OPERATION_SUCCEEDED; } static pmix_status_t deregister_events(pmix_status_t *codes, size_t ncodes, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(codes, ncodes, cbfunc, cbdata); return PMIX_OPERATION_SUCCEEDED; } static pmix_status_t notify_event(pmix_status_t code, const pmix_proc_t *source, pmix_data_range_t range, pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(code, source, range, info, ninfo, cbfunc, cbdata); return PMIX_OPERATION_SUCCEEDED; } static void qfn(int sd, short args, void *cbdata) { myxfer_t *qd = (myxfer_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); qd->infocbfunc(PMIX_SUCCESS, qd->info, qd->ninfo, qd->cbdata, NULL, NULL); PMIX_RELEASE(qd); } static pmix_status_t query_fn(pmix_proc_t *proct, pmix_query_t *queries, size_t nqueries, pmix_info_cbfunc_t cbfunc, void *cbdata) { size_t n; pmix_info_t *info; myxfer_t *qd; PMIX_HIDE_UNUSED_PARAMS(proct); if (NULL == cbfunc) { return PMIX_ERROR; } /* keep this simple */ PMIX_INFO_CREATE(info, nqueries); for (n = 0; n < nqueries; n++) { pmix_output(0, "\tKey: %s", queries[n].keys[0]); pmix_strncpy(info[n].key, queries[n].keys[0], PMIX_MAX_KEYLEN); info[n].value.type = PMIX_STRING; if (0 > asprintf(&info[n].value.data.string, "%d", (int) n)) { return PMIX_ERROR; } } qd = PMIX_NEW(myxfer_t); qd->info = info; qd->ninfo = nqueries; qd->infocbfunc = cbfunc; qd->cbdata = cbdata; SIMPTEST_THREADSHIFT(qd, qfn); return PMIX_SUCCESS; } static void tool_connect_fn(pmix_info_t *info, size_t ninfo, pmix_tool_connection_cbfunc_t cbfunc, void *cbdata) { pmix_proc_t proc; PMIX_HIDE_UNUSED_PARAMS(info, ninfo); /* just pass back an arbitrary nspace */ pmix_strncpy(proc.nspace, "TOOL", PMIX_MAX_NSLEN); proc.rank = 0; if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, &proc, cbdata); } } typedef struct { pmix_event_t ev; pmix_op_cbfunc_t cbfunc; pmix_info_cbfunc_t infocbfunc; pmix_info_t *info; size_t ninfo; void *cbdata; } mylog_t; static void foobar(int sd, short args, void *cbdata) { mylog_t *lg = (mylog_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); lg->cbfunc(PMIX_SUCCESS, lg->cbdata); } static void log_fn(const pmix_proc_t *client, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { mylog_t *lg = (mylog_t *) malloc(sizeof(mylog_t)); size_t n; PMIX_HIDE_UNUSED_PARAMS(client, data, ndata, directives, ndirs); for (n=0; n < ndata; n++) { if (PMIX_STRING == data[n].value.type) { fprintf(stderr, "%sLOG: %s\n", PMIX_NAME_PRINT(client), data[n].value.data.string); } } lg->cbfunc = cbfunc; lg->cbdata = cbdata; SIMPTEST_THREADSHIFT(lg, foobar); } static pmix_status_t alloc_fn(const pmix_proc_t *client, pmix_alloc_directive_t directive, const pmix_info_t data[], size_t ndata, pmix_info_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(client, directive, data, ndata, cbfunc, cbdata); return PMIX_OPERATION_SUCCEEDED; } static pmix_status_t jctrl_fn(const pmix_proc_t *requestor, const pmix_proc_t targets[], size_t ntargets, const pmix_info_t directives[], size_t ndirs, pmix_info_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(requestor, targets, ntargets, directives, ndirs, cbfunc, cbdata); return PMIX_OPERATION_SUCCEEDED; } static pmix_status_t mon_fn(const pmix_proc_t *requestor, const pmix_info_t *monitor, pmix_status_t error, const pmix_info_t directives[], size_t ndirs, pmix_info_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(requestor, monitor, error, directives, ndirs, cbfunc, cbdata); return PMIX_ERR_NOT_SUPPORTED; } static void wait_signal_callback(int sd, short args, void *arg) { pmix_event_t *sig = (pmix_event_t *) arg; int status; pid_t pid; wait_tracker_t *t2; PMIX_HIDE_UNUSED_PARAMS(sd, args); if (SIGCHLD != pmix_event_get_signal(sig)) { return; } /* we can have multiple children leave but only get one * sigchild callback, so reap all the waitpids until we * don't get anything valid back */ while (1) { pid = waitpid(-1, &status, WNOHANG); if (-1 == pid && EINTR == errno) { /* try it again */ continue; } /* if we got garbage, then nothing we can do */ if (pid <= 0) { return; } /* we are already in an event, so it is safe to access the list */ PMIX_LIST_FOREACH (t2, &children, wait_tracker_t) { if (pid == t2->pid) { /* found it! */ if (WIFEXITED(status)) { t2->exit_code = WEXITSTATUS(status); } else { if (WIFSIGNALED(status)) { t2->exit_code = WTERMSIG(status) + 128; } } if (0 == exit_code) { if (abort_has_been_called) { if (137 != t2->exit_code) { exit_code = t2->exit_code; } } else if (0 != t2->exit_code) { exit_code = t2->exit_code; } } --wakeup; break; } } } fprintf(stderr, "ENDLOOP\n"); } static void relcbfunc(void *cbdata) { mylog_t *lg = (mylog_t *) cbdata; free(lg); } static void grpbar(int sd, short args, void *cbdata) { mylog_t *lg = (mylog_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(sd, args); lg->infocbfunc(PMIX_SUCCESS, (pmix_info_t*)lg->info, lg->ninfo, lg->cbdata, relcbfunc, lg); } static pmix_status_t grp_fn(pmix_group_operation_t op, char *gpid, const pmix_proc_t procs[], size_t nprocs, const pmix_info_t directives[], size_t ndirs, pmix_info_cbfunc_t cbfunc, void *cbdata) { mylog_t *lg = (mylog_t *) malloc(sizeof(mylog_t)); size_t n; size_t ctxid = 1; pmix_data_array_t darray; PMIX_HIDE_UNUSED_PARAMS(op, gpid, procs, nprocs); memset(lg, 0, sizeof(mylog_t)); if (PMIX_GROUP_CONSTRUCT == op) { lg->ninfo = 3; PMIX_INFO_CREATE(lg->info, lg->ninfo); PMIX_INFO_LOAD(&lg->info[0], PMIX_GROUP_CONTEXT_ID, &ctxid, PMIX_SIZE); darray.array = (pmix_proc_t*)procs; darray.type = PMIX_PROC; darray.size = nprocs; PMIX_INFO_LOAD(&lg->info[1], PMIX_GROUP_MEMBERSHIP, &darray, PMIX_DATA_ARRAY); lg->ninfo = 2; for (n=0; n < ndirs; n++) { if (PMIX_CHECK_KEY(&directives[n], PMIX_GROUP_ENDPT_DATA)) { PMIX_INFO_XFER(&lg->info[2], &directives[n]); lg->ninfo = 3; break; } } } lg->infocbfunc = cbfunc; lg->cbdata = cbdata; SIMPTEST_THREADSHIFT(lg, grpbar); return PMIX_SUCCESS; } pmix-6.1.1~rc2/test/simple/netconfig.txt0000664000175000017500000000034315203536752020462 0ustar alastairalastair# Example coordinate config file for the pnet/simptest component # Written as: # nodename x y z group test000 0 0 0 0 test001 1 0 0 0 test002 2 0 0 0 test003 0 0 0 1 test004 1 0 0 1 test005 2 0 0 1 pmix-6.1.1~rc2/test/simple/stability.c0000664000175000017500000011215515203536752020122 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * Copyright (c) 2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include #include #include #include #include #include #include #include #include "src/class/pmix_list.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "simptest.h" static pmix_status_t connected(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t finalized(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t abort_fn(const pmix_proc_t *proc, void *server_object, int status, const char msg[], pmix_proc_t procs[], size_t nprocs, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t fencenb_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, char *data, size_t ndata, pmix_modex_cbfunc_t cbfunc, void *cbdata); static pmix_status_t dmodex_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_modex_cbfunc_t cbfunc, void *cbdata); static pmix_status_t publish_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t lookup_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_lookup_cbfunc_t cbfunc, void *cbdata); static pmix_status_t unpublish_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t spawn_fn(const pmix_proc_t *proc, const pmix_info_t job_info[], size_t ninfo, const pmix_app_t apps[], size_t napps, pmix_spawn_cbfunc_t cbfunc, void *cbdata); static pmix_status_t connect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t disconnect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t register_event_fn(pmix_status_t *codes, size_t ncodes, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t deregister_events(pmix_status_t *codes, size_t ncodes, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t notify_event(pmix_status_t code, const pmix_proc_t *source, pmix_data_range_t range, pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_status_t query_fn(pmix_proc_t *proct, pmix_query_t *queries, size_t nqueries, pmix_info_cbfunc_t cbfunc, void *cbdata); static void tool_connect_fn(pmix_info_t *info, size_t ninfo, pmix_tool_connection_cbfunc_t cbfunc, void *cbdata); static void log_fn(const pmix_proc_t *client, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata); static pmix_server_module_t mymodule = {.client_connected = connected, .client_finalized = finalized, .abort = abort_fn, .fence_nb = fencenb_fn, .direct_modex = dmodex_fn, .publish = publish_fn, .lookup = lookup_fn, .unpublish = unpublish_fn, .spawn = spawn_fn, .connect = connect_fn, .disconnect = disconnect_fn, .register_events = register_event_fn, .deregister_events = deregister_events, .notify_event = notify_event, .query = query_fn, .tool_connected = tool_connect_fn, .log = log_fn}; typedef struct { pmix_list_item_t super; pmix_pdata_t pdata; } pmix_locdat_t; PMIX_CLASS_INSTANCE(pmix_locdat_t, pmix_list_item_t, NULL, NULL); typedef struct { pmix_object_t super; mylock_t lock; pmix_event_t ev; pmix_proc_t caller; pmix_info_t *info; size_t ninfo; pmix_op_cbfunc_t cbfunc; pmix_spawn_cbfunc_t spcbfunc; pmix_release_cbfunc_t relcbfunc; void *cbdata; } myxfer_t; static void xfcon(myxfer_t *p) { DEBUG_CONSTRUCT_LOCK(&p->lock); p->info = NULL; p->ninfo = 0; p->cbfunc = NULL; p->spcbfunc = NULL; p->cbdata = NULL; } static void xfdes(myxfer_t *p) { DEBUG_DESTRUCT_LOCK(&p->lock); if (NULL != p->info) { PMIX_INFO_FREE(p->info, p->ninfo); } } PMIX_CLASS_INSTANCE(myxfer_t, pmix_object_t, xfcon, xfdes); typedef struct { pmix_list_item_t super; int exit_code; pid_t pid; } wait_tracker_t; PMIX_CLASS_INSTANCE(wait_tracker_t, pmix_list_item_t, NULL, NULL); static volatile int wakeup; static int exit_code = 0; static pmix_list_t pubdata; static pmix_event_t handler; static pmix_list_t children; static bool istimeouttest = false; static bool nettest = false; static bool arrays = false; static void set_namespace(int nprocs, char *ranks, char *nspace, pmix_op_cbfunc_t cbfunc, myxfer_t *x); static void errhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata); static void wait_signal_callback(int fd, short event, void *arg); static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata); static void opcbfunc(pmix_status_t status, void *cbdata) { myxfer_t *x = (myxfer_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); /* release the caller, if necessary */ if (NULL != x->cbfunc) { x->cbfunc(PMIX_SUCCESS, x->cbdata); } DEBUG_WAKEUP_THREAD(&x->lock); } static void setup_cbfunc(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *provided_cbdata, pmix_op_cbfunc_t cbfunc, void *cbdata) { myxfer_t *x = (myxfer_t *) provided_cbdata; size_t n; PMIX_HIDE_UNUSED_PARAMS(status); /* transfer it to the caddy for return to the main thread */ if (0 < ninfo) { PMIX_INFO_CREATE(x->info, ninfo); x->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&x->info[n], &info[n]); } } /* let the library release the data and cleanup from * the operation */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } DEBUG_WAKEUP_THREAD(&x->lock); } int main(int argc, char **argv) { char **client_env = NULL; char **client_argv = NULL; char *tmp, **atmp, *executable = NULL, *nspace; int rc, nprocs = 1, n, k; uid_t myuid; gid_t mygid; pid_t pid; myxfer_t *x; pmix_proc_t proc; wait_tracker_t *child; pmix_info_t *info; size_t ninfo; mylock_t mylock; int ncycles = 1, m, delay = 0; sigset_t unblock; /* smoke test */ if (PMIX_SUCCESS != 0) { fprintf(stderr, "ERROR IN COMPUTING CONSTANTS: PMIX_SUCCESS = %d\n", PMIX_SUCCESS); exit(1); } fprintf(stderr, "Testing version %s\n", PMIx_Get_version()); /* see if we were passed the number of procs to run or * the executable to use */ for (n = 1; n < argc; n++) { if (0 == strcmp("-n", argv[n]) && NULL != argv[n + 1]) { nprocs = strtol(argv[n + 1], NULL, 10); ++n; // step over the argument } else if (0 == strcmp("-e", argv[n]) && NULL != argv[n + 1]) { executable = strdup(argv[n + 1]); /* check for timeout test */ if (NULL != strstr(executable, "quietclient")) { istimeouttest = true; } for (k = n + 2; NULL != argv[k]; k++) { PMIx_Argv_append_nosize(&client_argv, argv[k]); } n += k; } else if ((0 == strcmp("-reps", argv[n]) || 0 == strcmp("--reps", argv[n])) && NULL != argv[n + 1]) { ncycles = strtol(argv[n + 1], NULL, 10); } else if ((0 == strcmp("-sleep", argv[n]) || 0 == strcmp("--sleep", argv[n])) && NULL != argv[n + 1]) { delay = strtol(argv[n + 1], NULL, 10); } else if (0 == strcmp("-h", argv[n])) { /* print the options and exit */ fprintf(stderr, "usage: simptest \n"); fprintf(stderr, " -n N Number of clients to run\n"); fprintf(stderr, " -e foo Name of the client executable to run (default: simpclient\n"); fprintf(stderr, " -reps N Cycle for N repetitions"); fprintf(stderr, " -net-test Test network endpt assignments\n"); fprintf(stderr, " -arrays Use the job session array to pass registration info\n"); exit(0); } else if (0 == strcmp("-net-test", argv[n]) || 0 == strcmp("--net-test", argv[n])) { /* test network support */ nettest = true; } else if (0 == strcmp("-arrays", argv[n]) || 0 == strcmp("--arrays", argv[n])) { /* test network support */ arrays = true; } } if (NULL == executable) { if (nettest) { executable = strdup("./simpcoord"); } else { executable = strdup("./quietclient"); } } /* check for executable existence and permissions */ if (0 != access(executable, X_OK)) { fprintf(stderr, "Executable %s not found or missing executable permissions\n", executable); exit(1); } /* ensure that SIGCHLD is unblocked as we need to capture it */ if (0 != sigemptyset(&unblock)) { fprintf(stderr, "SIGEMPTYSET FAILED\n"); exit(1); } if (0 != sigaddset(&unblock, SIGCHLD)) { fprintf(stderr, "SIGADDSET FAILED\n"); exit(1); } if (0 != sigprocmask(SIG_UNBLOCK, &unblock, NULL)) { fprintf(stderr, "SIG_UNBLOCK FAILED\n"); exit(1); } /* setup the server library and tell it to support tool connections */ ninfo = 3; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_SERVER_TOOL_SUPPORT, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[1], PMIX_USOCK_DISABLE, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[2], PMIX_SERVER_SCHEDULER, NULL, PMIX_BOOL); if (nettest) { /* set a known network configuration for the pnet/test component */ putenv("PMIX_MCA_pnet_test_nverts=nodes:5;plane:d:3;plane:s:2;plane:d:5"); putenv("PMIX_MCA_pnet=test"); } if (PMIX_SUCCESS != (rc = PMIx_server_init(&mymodule, info, ninfo))) { fprintf(stderr, "Init failed with error %d\n", rc); return rc; } PMIX_INFO_FREE(info, ninfo); if (nettest) { unsetenv("PMIX_MCA_pnet"); unsetenv("PMIX_MCA_pnet_test_nverts"); } /* register the default errhandler */ DEBUG_CONSTRUCT_LOCK(&mylock); ninfo = 1; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_EVENT_HDLR_NAME, "SIMPTEST-DEFAULT", PMIX_STRING); PMIx_Register_event_handler(NULL, 0, info, ninfo, errhandler, errhandler_reg_callbk, (void *) &mylock); DEBUG_WAIT_THREAD(&mylock); PMIX_INFO_FREE(info, ninfo); if (PMIX_SUCCESS != mylock.status) { exit(mylock.status); } DEBUG_DESTRUCT_LOCK(&mylock); /* setup the pub data, in case it is used */ PMIX_CONSTRUCT(&pubdata, pmix_list_t); /* setup to see sigchld on the forked tests */ PMIX_CONSTRUCT(&children, pmix_list_t); pmix_event_assign(&handler, pmix_globals.evbase, SIGCHLD, EV_SIGNAL | EV_PERSIST, wait_signal_callback, &handler); pmix_event_add(&handler, NULL); for (m = 0; m < ncycles; m++) { fprintf(stderr, "Running cycle %d\n", m); /* we have a single namespace for all clients */ atmp = NULL; for (n = 0; n < nprocs; n++) { if (0 > asprintf(&tmp, "%d", n)) { errno = ENOMEM; abort(); } PMIx_Argv_append_nosize(&atmp, tmp); free(tmp); } tmp = PMIx_Argv_join(atmp, ','); PMIx_Argv_free(atmp); if (0 > asprintf(&nspace, "foobar%d", m)) { errno = ENOMEM; abort(); } pmix_strncpy(proc.nspace, nspace, PMIX_MAX_NSLEN); x = PMIX_NEW(myxfer_t); set_namespace(nprocs, tmp, nspace, opcbfunc, x); /* set common argv and env */ client_env = PMIx_Argv_copy(environ); PMIx_Argv_prepend_nosize(&client_argv, executable); wakeup = nprocs; myuid = getuid(); mygid = getgid(); /* if the nspace registration hasn't completed yet, * wait for it here */ DEBUG_WAIT_THREAD(&x->lock); free(tmp); free(nspace); PMIX_RELEASE(x); /* fork/exec the test */ for (n = 0; n < nprocs; n++) { proc.rank = n; if (PMIX_SUCCESS != (rc = PMIx_server_setup_fork(&proc, &client_env))) { fprintf(stderr, "Server fork setup failed with error %d\n", rc); PMIx_server_finalize(); return rc; } x = PMIX_NEW(myxfer_t); if (PMIX_SUCCESS != (rc = PMIx_server_register_client(&proc, myuid, mygid, NULL, opcbfunc, x))) { fprintf(stderr, "Server register client failed with error %d\n", rc); PMIx_server_finalize(); return rc; } /* don't fork/exec the client until we know it is registered * so we avoid a potential race condition in the server */ DEBUG_WAIT_THREAD(&x->lock); PMIX_RELEASE(x); pid = fork(); if (pid < 0) { fprintf(stderr, "Fork failed\n"); PMIx_server_finalize(); return -1; } child = PMIX_NEW(wait_tracker_t); child->pid = pid; pmix_list_append(&children, &child->super); if (pid == 0) { execve(executable, client_argv, client_env); /* Does not return */ exit(0); } } PMIx_Argv_free(client_argv); client_argv = NULL; PMIx_Argv_free(client_env); client_env = NULL; /* hang around until the client(s) finalize */ while (0 < wakeup) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } /* see if anyone exited with non-zero status */ n = 0; PMIX_LIST_FOREACH (child, &children, wait_tracker_t) { if (0 != child->exit_code) { fprintf(stderr, "Child %d exited with status %d - test FAILED\n", n, child->exit_code); goto done; } ++n; } /* deregister the clients */ for (n = 0; n < nprocs; n++) { proc.rank = n; x = PMIX_NEW(myxfer_t); PMIx_server_deregister_client(&proc, opcbfunc, x); DEBUG_WAIT_THREAD(&x->lock); PMIX_RELEASE(x); } /* deregister the nspace */ x = PMIX_NEW(myxfer_t); PMIx_server_deregister_nspace(proc.nspace, opcbfunc, x); DEBUG_WAIT_THREAD(&x->lock); PMIX_RELEASE(x); PMIX_LIST_DESTRUCT(&children); PMIX_CONSTRUCT(&children, pmix_list_t); sleep(delay); } done: /* deregister the event handlers */ PMIx_Deregister_event_handler(0, NULL, NULL); /* release any pub data */ PMIX_LIST_DESTRUCT(&pubdata); free(executable); /* finalize the server library */ if (PMIX_SUCCESS != (rc = PMIx_server_finalize())) { fprintf(stderr, "Finalize failed with error %d\n", rc); exit_code = rc; } if (0 == exit_code) { fprintf(stderr, "Test finished OK!\n"); } else { fprintf(stderr, "TEST FAILED WITH ERROR %d\n", exit_code); } return exit_code; } static void set_namespace(int nprocs, char *ranks, char *nspace, pmix_op_cbfunc_t cbfunc, myxfer_t *x) { char *regex, *ppn, *rks; int n, m, k; pmix_data_array_t *array; pmix_info_t *info, *iptr, *ip; myxfer_t cd, lock; pmix_status_t rc; if (arrays) { x->ninfo = 15 + nprocs; } else { x->ninfo = 16 + nprocs; } PMIX_INFO_CREATE(x->info, x->ninfo); n = 0; PMIx_generate_regex("test000,test001,test002", ®ex); PMIx_generate_ppn("0;1;2", &ppn); if (arrays) { pmix_strncpy(x->info[n].key, PMIX_JOB_INFO_ARRAY, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(x->info[n].value.data.darray, 2, PMIX_INFO); iptr = (pmix_info_t *) x->info[n].value.data.darray->array; pmix_strncpy(iptr[0].key, PMIX_NODE_MAP, PMIX_MAX_KEYLEN); PMIX_INFO_LOAD(&iptr[0], PMIX_NODE_MAP, regex, PMIX_REGEX); PMIX_INFO_LOAD(&iptr[1], PMIX_PROC_MAP, ppn, PMIX_REGEX); ++n; } else { PMIX_INFO_LOAD(&x->info[n], PMIX_NODE_MAP, regex, PMIX_REGEX); ++n; PMIX_INFO_LOAD(&x->info[n], PMIX_PROC_MAP, ppn, PMIX_REGEX); ++n; } /* we have the required info to run setup_app, so do that now */ PMIX_INFO_CREATE(iptr, 4); PMIX_INFO_XFER(&iptr[0], &x->info[0]); PMIX_INFO_XFER(&iptr[1], &x->info[1]); PMIX_INFO_LOAD(&iptr[2], PMIX_SETUP_APP_ENVARS, NULL, PMIX_BOOL); PMIX_LOAD_KEY(iptr[3].key, PMIX_ALLOC_NETWORK); iptr[3].value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(iptr[3].value.data.darray, 2, PMIX_INFO); ip = (pmix_info_t *) iptr[3].value.data.darray->array; if (0 > asprintf(&rks, "%s.net", nspace)) { errno = ENOMEM; abort(); } PMIX_INFO_LOAD(&ip[0], PMIX_ALLOC_NETWORK_ID, rks, PMIX_STRING); free(rks); PMIX_INFO_LOAD(&ip[1], PMIX_ALLOC_NETWORK_SEC_KEY, NULL, PMIX_BOOL); PMIX_CONSTRUCT(&cd, myxfer_t); if (PMIX_SUCCESS != (rc = PMIx_server_setup_application(nspace, iptr, 4, setup_cbfunc, &cd))) { pmix_output(0, "[%s:%d] PMIx_server_setup_application failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); DEBUG_DESTRUCT_LOCK(&cd.lock); } else { DEBUG_WAIT_THREAD(&cd.lock); } /* use the results to setup the local subsystems */ PMIX_CONSTRUCT(&lock, myxfer_t); if (PMIX_SUCCESS != (rc = PMIx_server_setup_local_support(nspace, cd.info, cd.ninfo, opcbfunc, &lock))) { pmix_output(0, "[%s:%d] PMIx_server_setup_local_support failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); } else { DEBUG_WAIT_THREAD(&lock.lock); } PMIX_DESTRUCT(&lock); PMIX_DESTRUCT(&cd); pmix_strncpy(x->info[n].key, PMIX_UNIV_SIZE, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = nprocs; ++n; pmix_strncpy(x->info[n].key, PMIX_SPAWNED, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = 0; ++n; pmix_strncpy(x->info[n].key, PMIX_LOCAL_SIZE, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = nprocs; ++n; pmix_strncpy(x->info[n].key, PMIX_LOCAL_PEERS, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_STRING; x->info[n].value.data.string = strdup(ranks); ++n; pmix_strncpy(x->info[n].key, PMIX_JOB_SIZE, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = nprocs; ++n; pmix_strncpy(x->info[n].key, PMIX_JOBID, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_STRING; x->info[n].value.data.string = strdup("1234"); ++n; pmix_strncpy(x->info[n].key, PMIX_NPROC_OFFSET, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = 0; ++n; pmix_strncpy(x->info[n].key, PMIX_NODEID, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = 0; ++n; pmix_strncpy(x->info[n].key, PMIX_NODE_SIZE, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = nprocs; ++n; pmix_strncpy(x->info[n].key, PMIX_NUM_NODES, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = 1; ++n; pmix_strncpy(x->info[n].key, PMIX_UNIV_SIZE, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = nprocs; ++n; pmix_strncpy(x->info[n].key, PMIX_MAX_PROCS, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = nprocs; ++n; pmix_strncpy(x->info[n].key, PMIX_JOB_NUM_APPS, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_UINT32; x->info[n].value.data.uint32 = 1; ++n; pmix_strncpy(x->info[n].key, PMIX_LOCALLDR, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_PROC_RANK; x->info[n].value.data.uint32 = 0; ++n; /* add the proc-specific data */ for (m = 0; m < nprocs; m++) { pmix_strncpy(x->info[n].key, PMIX_PROC_DATA, PMIX_MAX_KEYLEN); x->info[n].value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(array, 5, PMIX_INFO); x->info[n].value.data.darray = array; info = (pmix_info_t *) array->array; k = 0; pmix_strncpy(info[k].key, PMIX_RANK, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_PROC_RANK; info[k].value.data.rank = m; ++k; pmix_strncpy(info[k].key, PMIX_GLOBAL_RANK, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_PROC_RANK; info[k].value.data.rank = m; ++k; pmix_strncpy(info[k].key, PMIX_LOCAL_RANK, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_UINT16; info[k].value.data.uint16 = m; ++k; pmix_strncpy(info[k].key, PMIX_NODE_RANK, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_UINT16; info[k].value.data.uint16 = m; ++k; pmix_strncpy(info[k].key, PMIX_NODEID, PMIX_MAX_KEYLEN); info[k].value.type = PMIX_UINT32; info[k].value.data.uint32 = 0; ++k; /* move to next proc */ ++n; } PMIx_server_register_nspace(nspace, nprocs, x->info, x->ninfo, cbfunc, x); } static void errhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, info, ninfo, results, nresults, cbfunc, cbdata); return; } static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(errhandler_ref); lock->status = status; DEBUG_WAKEUP_THREAD(lock); } static pmix_status_t connected(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(proc, server_object); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static pmix_status_t finalized(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(proc, server_object); /* ensure we call the cbfunc so the proc can exit! */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static void abcbfunc(pmix_status_t status, void *cbdata) { myxfer_t *x = (myxfer_t *) cbdata; /* be sure to release the caller */ if (NULL != x->cbfunc) { x->cbfunc(status, x->cbdata); } PMIX_RELEASE(x); } static pmix_status_t abort_fn(const pmix_proc_t *proc, void *server_object, int status, const char msg[], pmix_proc_t procs[], size_t nprocs, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_status_t rc; myxfer_t *x; PMIX_HIDE_UNUSED_PARAMS(server_object, msg, procs, nprocs); /* instead of aborting the specified procs, notify them * (if they have registered their errhandler) */ /* use the myxfer_t object to ensure we release * the caller when notification has been queued */ x = PMIX_NEW(myxfer_t); pmix_strncpy(x->caller.nspace, proc->nspace, PMIX_MAX_NSLEN); x->caller.rank = proc->rank; PMIX_INFO_CREATE(x->info, 2); pmix_strncpy(x->info[0].key, "DARTH", PMIX_MAX_KEYLEN); x->info[0].value.type = PMIX_INT8; x->info[0].value.data.int8 = 12; pmix_strncpy(x->info[1].key, "VADER", PMIX_MAX_KEYLEN); x->info[1].value.type = PMIX_DOUBLE; x->info[1].value.data.dval = 12.34; x->cbfunc = cbfunc; x->cbdata = cbdata; if (PMIX_SUCCESS != (rc = PMIx_Notify_event(status, &x->caller, PMIX_RANGE_NAMESPACE, x->info, 2, abcbfunc, x))) { pmix_output(0, "SERVER: FAILED NOTIFY ERROR %d", (int) rc); } return PMIX_SUCCESS; } static pmix_status_t fencenb_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, char *data, size_t ndata, pmix_modex_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo); /* pass the provided data back to each participating proc */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, data, ndata, cbdata, free, data); } return PMIX_SUCCESS; } static pmix_status_t dmodex_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_modex_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(proc, info, ninfo); /* if this is a timeout test, then do nothing */ if (istimeouttest) { return PMIX_SUCCESS; } /* we don't have any data for remote procs as this * test only runs one server - so report accordingly */ if (NULL != cbfunc) { cbfunc(PMIX_ERR_NOT_FOUND, NULL, 0, cbdata, NULL, NULL); } return PMIX_SUCCESS; } static pmix_status_t publish_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_locdat_t *p; size_t n; for (n = 0; n < ninfo; n++) { p = PMIX_NEW(pmix_locdat_t); pmix_strncpy(p->pdata.proc.nspace, proc->nspace, PMIX_MAX_NSLEN); p->pdata.proc.rank = proc->rank; pmix_strncpy(p->pdata.key, info[n].key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&p->pdata.value, (pmix_value_t *) &info[n].value); pmix_list_append(&pubdata, &p->super); } if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static pmix_status_t lookup_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_lookup_cbfunc_t cbfunc, void *cbdata) { pmix_locdat_t *p, *p2; pmix_list_t results; size_t i, n; pmix_pdata_t *pd = NULL; pmix_status_t ret = PMIX_ERR_NOT_FOUND; PMIX_HIDE_UNUSED_PARAMS(proc, info, ninfo); PMIX_CONSTRUCT(&results, pmix_list_t); for (n = 0; NULL != keys[n]; n++) { PMIX_LIST_FOREACH (p, &pubdata, pmix_locdat_t) { if (0 == strncmp(keys[n], p->pdata.key, PMIX_MAX_KEYLEN)) { p2 = PMIX_NEW(pmix_locdat_t); pmix_strncpy(p2->pdata.proc.nspace, p->pdata.proc.nspace, PMIX_MAX_NSLEN); p2->pdata.proc.rank = p->pdata.proc.rank; pmix_strncpy(p2->pdata.key, p->pdata.key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&p2->pdata.value, &p->pdata.value); pmix_list_append(&results, &p2->super); break; } } } if (0 < (n = pmix_list_get_size(&results))) { ret = PMIX_SUCCESS; PMIX_PDATA_CREATE(pd, n); for (i = 0; i < n; i++) { p = (pmix_locdat_t *) pmix_list_remove_first(&results); if (p) { pmix_strncpy(pd[i].proc.nspace, p->pdata.proc.nspace, PMIX_MAX_NSLEN); pd[i].proc.rank = p->pdata.proc.rank; pmix_strncpy(pd[i].key, p->pdata.key, PMIX_MAX_KEYLEN); PMIx_Value_xfer(&pd[i].value, &p->pdata.value); } } } PMIX_LIST_DESTRUCT(&results); if (NULL != cbfunc) { cbfunc(ret, pd, n, cbdata); } if (0 < n) { PMIX_PDATA_FREE(pd, n); } return PMIX_SUCCESS; } static pmix_status_t unpublish_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_locdat_t *p, *p2; size_t n; PMIX_HIDE_UNUSED_PARAMS(proc, info, ninfo); for (n = 0; NULL != keys[n]; n++) { PMIX_LIST_FOREACH_SAFE (p, p2, &pubdata, pmix_locdat_t) { if (0 == strncmp(keys[n], p->pdata.key, PMIX_MAX_KEYLEN)) { pmix_list_remove_item(&pubdata, &p->super); PMIX_RELEASE(p); break; } } } if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static void spcbfunc(pmix_status_t status, void *cbdata) { myxfer_t *x = (myxfer_t *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); if (NULL != x->spcbfunc) { x->spcbfunc(PMIX_SUCCESS, "DYNSPACE", x->cbdata); } } static pmix_status_t spawn_fn(const pmix_proc_t *proc, const pmix_info_t job_info[], size_t ninfo, const pmix_app_t apps[], size_t napps, pmix_spawn_cbfunc_t cbfunc, void *cbdata) { myxfer_t *x; PMIX_HIDE_UNUSED_PARAMS(proc, job_info, ninfo, apps, napps); /* in practice, we would pass this request to the local * resource manager for launch, and then have that server * execute our callback function. For now, we will fake * the spawn and just pretend */ /* must register the nspace for the new procs before * we return to the caller */ x = PMIX_NEW(myxfer_t); x->spcbfunc = cbfunc; x->cbdata = cbdata; set_namespace(2, "0,1", "DYNSPACE", spcbfunc, x); return PMIX_SUCCESS; } static int numconnects = 0; static pmix_status_t connect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo); /* in practice, we would pass this request to the local * resource manager for handling */ numconnects++; if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static pmix_status_t disconnect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo); /* in practice, we would pass this request to the local * resource manager for handling */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static pmix_status_t register_event_fn(pmix_status_t *codes, size_t ncodes, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(codes, ncodes, info, ninfo); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } static pmix_status_t deregister_events(pmix_status_t *codes, size_t ncodes, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(codes, ncodes, cbfunc, cbdata); return PMIX_SUCCESS; } static pmix_status_t notify_event(pmix_status_t code, const pmix_proc_t *source, pmix_data_range_t range, pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(code, source, range, info, ninfo, cbfunc, cbdata); return PMIX_SUCCESS; } typedef struct query_data_t { pmix_info_t *data; size_t ndata; } query_data_t; static pmix_status_t query_fn(pmix_proc_t *proct, pmix_query_t *queries, size_t nqueries, pmix_info_cbfunc_t cbfunc, void *cbdata) { size_t n; pmix_info_t *info; PMIX_HIDE_UNUSED_PARAMS(proct); if (NULL == cbfunc) { return PMIX_ERROR; } /* keep this simple */ PMIX_INFO_CREATE(info, nqueries); for (n = 0; n < nqueries; n++) { pmix_strncpy(info[n].key, queries[n].keys[0], PMIX_MAX_KEYLEN); info[n].value.type = PMIX_STRING; if (0 > asprintf(&info[n].value.data.string, "%d", (int) n)) { return PMIX_ERROR; } } cbfunc(PMIX_SUCCESS, info, nqueries, cbdata, NULL, NULL); return PMIX_SUCCESS; } static void tool_connect_fn(pmix_info_t *info, size_t ninfo, pmix_tool_connection_cbfunc_t cbfunc, void *cbdata) { pmix_proc_t proc; PMIX_HIDE_UNUSED_PARAMS(info, ninfo); /* just pass back an arbitrary nspace */ pmix_strncpy(proc.nspace, "TOOL", PMIX_MAX_NSLEN); proc.rank = 0; if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, &proc, cbdata); } } static void log_fn(const pmix_proc_t *client, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(client, data, ndata, directives, ndirs); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } } static void wait_signal_callback(int fd, short event, void *arg) { pmix_event_t *sig = (pmix_event_t *) arg; int status; pid_t pid; wait_tracker_t *t2; PMIX_HIDE_UNUSED_PARAMS(fd, event); if (SIGCHLD != pmix_event_get_signal(sig)) { return; } /* we can have multiple children leave but only get one * sigchild callback, so reap all the waitpids until we * don't get anything valid back */ while (1) { pid = waitpid(-1, &status, WNOHANG); if (-1 == pid && EINTR == errno) { /* try it again */ continue; } /* if we got garbage, then nothing we can do */ if (pid <= 0) { return; } /* we are already in an event, so it is safe to access the list */ PMIX_LIST_FOREACH (t2, &children, wait_tracker_t) { if (pid == t2->pid) { t2->exit_code = status; /* found it! */ if (0 != status && 0 == exit_code) { exit_code = status; } --wakeup; break; } } } } pmix-6.1.1~rc2/test/simple/quietclient.c0000664000175000017500000003555515203536752020454 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * Copyright (c) 2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ /****** FUNCTIONS TESTED ****/ /* * PMIx_Init * PMIx_Get * PMIx_Register_event_handler * PMIx_Store_internal * PMIx_Put * PMIx_Commit * PMIx_Fence * PMIx_Finalize */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #define MAXCNT 1 static volatile bool completed = false; static pmix_proc_t myproc; static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, info, ninfo, results, nresults); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } completed = true; } static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata) { volatile bool *active = (volatile bool *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status, errhandler_ref); *active = false; } /* this is an event notification function that we explicitly request * be called when the PMIX_MODEL_DECLARED notification is issued. * We could catch it in the general event notification function and test * the status to see if the status matched, but it often is simpler * to declare a use-specific notification callback point. In this case, * we are asking to know whenever a model is declared as a means * of testing server self-notification */ static void model_callback(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source, info, ninfo, results, nresults); /* we must NOT tell the event handler state machine that we * are the last step as that will prevent it from notifying * anyone else that might be listening for declarations */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } } /* event handler registration is done asynchronously */ static void model_registration_callback(pmix_status_t status, size_t evhandler_ref, void *cbdata) { volatile int *active = (volatile int *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status, evhandler_ref); *active = false; } int main(int argc, char **argv) { int rc; pmix_value_t value; pmix_value_t *val = &value; char *tmp; pmix_proc_t proc; uint32_t nprocs, n, k, nlocal; int cnt, j; volatile bool active; pmix_info_t *iptr; size_t ninfo; pmix_status_t code; char **peers; bool all_local, local; pmix_rank_t *locals = NULL; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* init us and declare we are a test programming model */ PMIX_INFO_CREATE(iptr, 2); PMIX_INFO_LOAD(&iptr[0], PMIX_PROGRAMMING_MODEL, "TEST", PMIX_STRING); PMIX_INFO_LOAD(&iptr[1], PMIX_MODEL_LIBRARY_NAME, "PMIX", PMIX_STRING); if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, iptr, 2))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } PMIX_INFO_FREE(iptr, 2); /* test something */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } PMIX_VALUE_RELEASE(val); /* register a handler specifically for when models declare */ active = true; ninfo = 1; PMIX_INFO_CREATE(iptr, ninfo); PMIX_INFO_LOAD(&iptr[0], PMIX_EVENT_HDLR_NAME, "SIMPCLIENT-MODEL", PMIX_STRING); code = PMIX_MODEL_DECLARED; PMIx_Register_event_handler(&code, 1, iptr, ninfo, model_callback, model_registration_callback, (void *) &active); while (active) { usleep(10); } PMIX_INFO_FREE(iptr, ninfo); /* register our errhandler */ active = true; PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, errhandler_reg_callbk, (void *) &active); while (active) { usleep(10); } /* get our job size */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get job size failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); /* put a few values */ if (0 > asprintf(&tmp, "%s-%d-internal", myproc.nspace, myproc.rank)) { errno = ENOMEM; abort(); } value.type = PMIX_UINT32; value.data.uint32 = 1234; if (PMIX_SUCCESS != (rc = PMIx_Store_internal(&myproc, tmp, &value))) { pmix_output(0, "Client ns %s rank %d: PMIx_Store_internal failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } /* get a list of our local peers */ if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_LOCAL_PEERS, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get local peers failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } /* split the returned string to get the rank of each local peer */ peers = PMIx_Argv_split(val->data.string, ','); PMIX_VALUE_RELEASE(val); nlocal = PMIx_Argv_count(peers); if (nprocs == nlocal) { all_local = true; } else { all_local = false; locals = (pmix_rank_t *) malloc(PMIx_Argv_count(peers) * sizeof(pmix_rank_t)); for (cnt = 0; NULL != peers[cnt]; cnt++) { locals[cnt] = strtoul(peers[cnt], NULL, 10); } } PMIx_Argv_free(peers); for (cnt = 0; cnt < MAXCNT; cnt++) { if (0 > asprintf(&tmp, "%s-%d-local-%d", myproc.nspace, myproc.rank, cnt)) { errno = ENOMEM; abort(); } value.type = PMIX_UINT64; value.data.uint64 = 1234; if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_LOCAL, tmp, &value))) { pmix_output(0, "Client ns %s rank %d: PMIx_Put internal failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } if (0 > asprintf(&tmp, "%s-%d-remote-%d", myproc.nspace, myproc.rank, cnt)) { errno = ENOMEM; abort(); } value.type = PMIX_STRING; value.data.string = "1234"; if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_REMOTE, tmp, &value))) { pmix_output(0, "Client ns %s rank %d: PMIx_Put internal failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } if (PMIX_SUCCESS != (rc = PMIx_Commit())) { pmix_output(0, "Client ns %s rank %d cnt %d: PMIx_Commit failed: %s", myproc.nspace, myproc.rank, cnt, PMIx_Error_string(rc)); goto done; } /* call fence to ensure the data is received */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d cnt %d: PMIx_Fence failed: %s", myproc.nspace, myproc.rank, cnt, PMIx_Error_string(rc)); goto done; } /* check the returned data */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); for (j = 0; j <= cnt; j++) { for (n = 0; n < nprocs; n++) { proc.rank = n; if (all_local) { local = true; } else { local = false; /* see if this proc is local to us */ for (k = 0; k < nlocal; k++) { if (proc.rank == locals[k]) { local = true; break; } } } if (local) { if (0 > asprintf(&tmp, "%s-%d-local-%d", myproc.nspace, n, j)) { errno = ENOMEM; abort(); } if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, tmp, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d cnt %d: PMIx_Get %s failed: %s", myproc.nspace, myproc.rank, j, tmp, PMIx_Error_string(rc)); continue; } if (NULL == val) { pmix_output(0, "Client ns %s rank %d: NULL value returned", myproc.nspace, myproc.rank); break; } if (PMIX_UINT64 != val->type) { pmix_output( 0, "Client ns %s rank %d cnt %d: PMIx_Get %s returned wrong type: %d", myproc.nspace, myproc.rank, j, tmp, val->type); PMIX_VALUE_RELEASE(val); free(tmp); continue; } if (1234 != val->data.uint64) { pmix_output( 0, "Client ns %s rank %d cnt %d: PMIx_Get %s returned wrong value: %d", myproc.nspace, myproc.rank, j, tmp, (int) val->data.uint64); PMIX_VALUE_RELEASE(val); free(tmp); continue; } PMIX_VALUE_RELEASE(val); free(tmp); /* now check that we don't get data for a remote proc - note that we * always can get our own remote data as we published it */ if (proc.rank != myproc.rank) { if (0 > asprintf(&tmp, "%s-%d-remote-%d", proc.nspace, n, j)) { errno = ENOMEM; abort(); } if (PMIX_SUCCESS == (rc = PMIx_Get(&proc, tmp, NULL, 0, &val))) { /* this data should _not_ be found as we are on the same node * and the data was "put" with a PMIX_REMOTE scope */ pmix_output(0, "ERROR: Client ns %s rank %d cnt %d: PMIx_Get %s returned " "remote data for a local proc", myproc.nspace, myproc.rank, j, tmp); } PMIX_VALUE_RELEASE(val); free(tmp); } } else { if (0 > asprintf(&tmp, "%s-%d-remote-%d", proc.nspace, n, j)) { errno = ENOMEM; abort(); } if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, tmp, NULL, 0, &val))) { pmix_output( 0, "Client ns %s rank %d cnt %d: PMIx_Get %s failed for remote proc", myproc.nspace, myproc.rank, j, tmp); } if (NULL != val) { PMIX_VALUE_RELEASE(val); } free(tmp); } } } } /* now get the data blob for myself */ if (PMIX_SUCCESS == (rc = PMIx_Get(&myproc, NULL, NULL, 0, &val))) { if (PMIX_DATA_ARRAY != val->type) { pmix_output(0, "Client ns %s rank %d did not return an array for its internal modex blob", myproc.nspace, myproc.rank); PMIX_VALUE_RELEASE(val); } else if (PMIX_INFO != val->data.darray->type) { pmix_output(0, "Client ns %s rank %d returned an internal modex array of type %s instead " "of PMIX_INFO", myproc.nspace, myproc.rank, PMIx_Data_type_string(val->data.darray->type)); PMIX_VALUE_RELEASE(val); } else if (0 == val->data.darray->size) { pmix_output(0, "Client ns %s rank %d returned an internal modex array of zero length", myproc.nspace, myproc.rank); PMIX_VALUE_RELEASE(val); } else { PMIX_VALUE_RELEASE(val); } } else { pmix_output(0, "Client ns %s rank %d internal modex blob FAILED with error %s(%d)", myproc.nspace, myproc.rank, PMIx_Error_string(rc), rc); } done: /* finalize us */ if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } fflush(stderr); return (rc); } pmix-6.1.1~rc2/test/simple/simppub.c0000664000175000017500000001551215203536752017574 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" int main(int argc, char **argv) { int rc; pmix_value_t value; pmix_value_t *val = &value; pmix_proc_t proc; uint32_t nprocs; pmix_info_t *info; pmix_pdata_t *pdata; pmix_proc_t myproc; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* init us */ if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %d", myproc.nspace, myproc.rank, rc); exit(0); } pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank); /* get our job size */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get job size failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "Client %s:%d job size %d", myproc.nspace, myproc.rank, nprocs); /* call fence to ensure the data is received */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc); goto done; } /* publish something */ if (0 == myproc.rank) { PMIX_INFO_CREATE(info, 2); pmix_strncpy(info[0].key, "FOOBAR", PMIX_MAX_KEYLEN); info[0].value.type = PMIX_UINT8; info[0].value.data.uint8 = 1; pmix_strncpy(info[1].key, "PANDA", PMIX_MAX_KEYLEN); info[1].value.type = PMIX_SIZE; info[1].value.data.size = 123456; if (PMIX_SUCCESS != (rc = PMIx_Publish(info, 2))) { pmix_output(0, "Client ns %s rank %d: PMIx_Publish failed: %d", myproc.nspace, myproc.rank, rc); goto done; } PMIX_INFO_FREE(info, 2); } /* call fence again so all procs know the data * has been published */ if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc); goto done; } /* lookup something */ if (0 != myproc.rank) { PMIX_PDATA_CREATE(pdata, 1); pmix_strncpy(pdata[0].key, "FOOBAR", PMIX_MAX_KEYLEN); if (PMIX_SUCCESS != (rc = PMIx_Lookup(pdata, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Lookup failed: %d", myproc.nspace, myproc.rank, rc); goto done; } /* check the return for value and source */ if (0 != strncmp(myproc.nspace, pdata[0].proc.nspace, PMIX_MAX_NSLEN)) { pmix_output(0, "Client ns %s rank %d: PMIx_Lookup returned wrong nspace: %s", myproc.nspace, myproc.rank, pdata[0].proc.nspace); goto done; } if (0 != pdata[0].proc.rank) { pmix_output(0, "Client ns %s rank %d: PMIx_Lookup returned wrong rank: %d", myproc.nspace, myproc.rank, pdata[0].proc.rank); goto done; } if (PMIX_UINT8 != pdata[0].value.type) { pmix_output(0, "Client ns %s rank %d: PMIx_Lookup returned wrong type: %d", myproc.nspace, myproc.rank, pdata[0].value.type); goto done; } if (1 != pdata[0].value.data.uint8) { pmix_output(0, "Client ns %s rank %d: PMIx_Lookup returned wrong value: %d", myproc.nspace, myproc.rank, (int) pdata[0].value.data.uint8); goto done; } PMIX_PDATA_FREE(pdata, 1); pmix_output(0, "PUBLISH-LOOKUP SUCCEEDED"); } /* call fence again so rank 0 waits before leaving */ if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc); goto done; } if (0 == myproc.rank) { char **keys = NULL; PMIx_Argv_append_nosize(&keys, "FOOBAR"); PMIx_Argv_append_nosize(&keys, "PANDA"); if (PMIX_SUCCESS != (rc = PMIx_Unpublish(keys, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Unpublish failed: %d", myproc.nspace, myproc.rank, rc); goto done; } pmix_output(0, "UNPUBLISH SUCCEEDED"); } /* call fence again so everyone waits for rank 0 before leaving */ proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc); goto done; } done: /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (0); } pmix-6.1.1~rc2/test/simple/legacy.c0000664000175000017500000000254715203536752017365 0ustar alastairalastair#include "src/include/pmix_config.h" #include #include #include #include #include "src/include/pmix_globals.h" int main(int argc, char *argv[]) { pmix_value_t *val = NULL; pmix_status_t rc = PMIX_SUCCESS; pmix_proc_t global_proc, proc; PMIX_HIDE_UNUSED_PARAMS(argc, argv); rc = PMIx_Init(&global_proc, NULL, 0); assert(PMIX_SUCCESS == rc); rc = PMIx_Get(&global_proc, PMIX_LOCAL_RANK, NULL, 0, &val); assert(PMIX_SUCCESS == rc); int local_rank = val->data.uint16; PMIX_VALUE_RELEASE(val); char key_p[32]; pmix_value_t value_p; snprintf(key_p, 32, "%s-%d", "foo", local_rank); value_p.type = PMIX_UINT32; value_p.data.uint32 = local_rank + 10; rc = PMIx_Put(PMIX_GLOBAL, key_p, &value_p); assert(PMIX_SUCCESS == rc); if (1 == global_proc.rank) { sleep(1); } rc = PMIx_Commit(); assert(PMIX_SUCCESS == rc); PMIX_PROC_CONSTRUCT(&proc); proc.rank = PMIX_RANK_UNDEF; strcpy(proc.nspace, global_proc.nspace); for (int i = 0; i < 2; i++) { char key_g[32]; pmix_value_t *value_g; snprintf(key_g, 32, "%s-%d", "foo", i); rc = PMIx_Get(&proc, key_g, NULL, 0, &value_g); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Rank %u: PMIx_Get got %d\n", global_proc.rank, rc); } else { fprintf(stderr, "Rank %u: Got %d\n", global_proc.rank, value_g->data.uint32); } } PMIx_Finalize(NULL, 0); return 0; } pmix-6.1.1~rc2/test/simple/simpdie.c0000664000175000017500000001575015203536752017553 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" static pmix_proc_t myproc; static bool completed; static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { size_t n; PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, results, nresults); pmix_output(0, "Client %s:%d NOTIFIED with status %s source %s:%d and %d info", myproc.nspace, myproc.rank, PMIx_Error_string(status), source->nspace, source->rank, (int) ninfo); for (n = 0; n < ninfo; n++) { if (0 == strncmp(info[n].key, PMIX_PROCID, PMIX_MAX_KEYLEN) && PMIX_PROC == info[n].value.type) { pmix_output(0, "[%s:%d] added proc: %s:%d", myproc.nspace, myproc.rank, info[n].value.data.proc->nspace, info[n].value.data.proc->rank); } else { pmix_output(0, "[%s:%d] key: %s", myproc.nspace, myproc.rank, info[n].key); } } if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } completed = true; } static void op_callbk(pmix_status_t status, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(cbdata); pmix_output(0, "CLIENT: OP CALLBACK CALLED WITH STATUS %d", status); } static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(cbdata); pmix_output(0, "Client: ERRHANDLER REGISTRATION CALLBACK CALLED WITH STATUS %d, ref=%lu", status, (unsigned long) errhandler_ref); } int main(int argc, char **argv) { int rc; pmix_value_t value; pmix_value_t *val = &value; pmix_proc_t proc; uint32_t nprocs; pmix_status_t code[6] = {PMIX_ERR_PROC_ABORTING, PMIX_ERR_PROC_ABORTED, PMIX_ERR_PROC_REQUESTED_ABORT, PMIX_ERR_JOB_TERMINATED, PMIX_ERR_UNREACH, PMIX_ERR_LOST_CONNECTION}; bool fail_early = false; bool fail_after_participate = false; int opt; if (1 == argc) { fail_early = true; } else if (2 == argc) { opt = strtol(argv[1], NULL, 10); switch(opt) { case 0: fail_early = true; break; case 1: fail_after_participate = true; break; default: fprintf(stderr, "Unknown case\n"); exit(1); } } /* init us */ if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %d", myproc.nspace, myproc.rank, rc); exit(0); } pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank); /* get our job size */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get job size failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "Client %s:%d job size %d", myproc.nspace, myproc.rank, nprocs); completed = false; /* register our errhandler */ PMIx_Register_event_handler(code, 6, NULL, 0, notification_fn, errhandler_reg_callbk, NULL); /* call fence to sync */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc); goto done; } if (0 == myproc.rank) { if (fail_early) { // wait a little bit to let someone else start the collective usleep(1000); pmix_output(0, "Client ns %s rank %d: bye-bye!", myproc.nspace, myproc.rank); exit(1); } else if (fail_after_participate) { usleep(500000); pmix_output(0, "Client ns %s rank %d: bye-bye!", myproc.nspace, myproc.rank); exit(1); } } else { if (fail_early) { if (1 != myproc.rank) { // wait a little bit to let the other guy start the collective usleep(2000); } pmix_output(0, "Rank %u calling Fence", myproc.rank); rc = PMIx_Fence(&proc, 1, NULL, 0); // let the user know pmix_output(0, "Rank %u: Fence returned %d(%s)", myproc.rank, rc, PMIx_Error_string(rc)); // give the server a chance to learn of the problem while (!completed) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } } } done: /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank); PMIx_Deregister_event_handler(1, op_callbk, NULL); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (0); } pmix-6.1.1~rc2/test/simple/simpdist.c0000664000175000017500000002720415203536752017752 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include #include #include #include #include #include #include #include #include #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "simptest.h" static pmix_server_module_t mymodule = {0}; typedef struct { mylock_t lock; pmix_status_t status; pmix_info_t *info; size_t ninfo; } mycaddy_t; static void output_usage(void) { fprintf(stderr, "Usage: simpdist [OPTIONS]\n"); fprintf(stderr, " --gpu Specify the GPU assigned to me,\n"); fprintf(stderr, " returns conjoined NICs\n"); fprintf(stderr, " --nic Specify the NIC assigned to me,\n"); fprintf(stderr, " returns conjoined GPUs\n"); fprintf(stderr, " --bind Specify the location where this proc is\n"); fprintf(stderr, " to be bound - defaults to detected binding if\n"); fprintf(stderr, " not provided\n"); fprintf(stderr, " --list List the NIC or GPU IDs in this topology\n"); fprintf(stderr, " --num Output the number of objects of the given type\n"); fprintf(stderr, " in this topology\n"); fprintf(stderr, "\nBinding location can be given as #:type - e.g., 3:L2 indicates\n"); fprintf(stderr, "that the proc is to be considered bound to the third L2 cache.\n"); fprintf(stderr, "Similarly, 2-3:L2 indicates that the proc is to be considered\n"); fprintf(stderr, "bound to the second-thru-third L2 caches, while 2,4,6:PU indicates\n"); fprintf(stderr, "that the proc is to be considered bound to the #2, #4, and #6\n"); fprintf(stderr, "hwthreads\n"); fprintf(stderr, "\nsimpdist will output the distances to corresponding\n"); fprintf(stderr, "devices that conjoin the specified device\n"); } static hwloc_obj_type_t convert_type(const char *name, char **strname) { if (0 == strncasecmp(name, "C", 1)) { if (NULL != strname) { *strname = "CORE"; } return HWLOC_OBJ_CORE; } else if (0 == strncasecmp(name, "HWT", 3) || 0 == strncasecmp(name, "PU", 2)) { if (NULL != strname) { *strname = "HWTHREAD"; } return HWLOC_OBJ_PU; } else if (0 == strncasecmp(name, "NU", 2)) { if (NULL != strname) { *strname = "NUMA"; } return HWLOC_OBJ_NUMANODE; } else if (0 == strncasecmp(name, "PKG", 3)) { if (NULL != strname) { *strname = "PACKAGE"; } return HWLOC_OBJ_PACKAGE; } else if (0 == strncasecmp(name, "L3", 2)) { if (NULL != strname) { *strname = "L3CACHE"; } return HWLOC_OBJ_L3CACHE; } else if (0 == strncasecmp(name, "L2", 2)) { if (NULL != strname) { *strname = "L2CACHE"; } return HWLOC_OBJ_L2CACHE; } else if (0 == strncasecmp(name, "L1", 2)) { if (NULL != strname) { *strname = "L1CACHE"; } return HWLOC_OBJ_L1CACHE; } else { fprintf(stderr, "UNRECOGNIZED HWLOC TYPE: %s\n", name); return HWLOC_OBJ_TYPE_MAX; } } static pmix_status_t construct_cpuset(hwloc_topology_t topo, hwloc_bitmap_t cpuset, const char *bind) { char **map, **rngs, **endpts; int n; unsigned m, start, stop; hwloc_obj_type_t type; hwloc_obj_t obj; map = PMIx_Argv_split(bind, ':'); if (NULL == map[1]) { fprintf(stderr, "Bad param - requires #:type\n"); return PMIX_ERR_BAD_PARAM; } // get the object type type = convert_type(map[1], NULL); if (HWLOC_OBJ_TYPE_MAX == type) { PMIx_Argv_free(map); return PMIX_ERR_BAD_PARAM; } // number could be comma-delim set of ranges rngs = PMIx_Argv_split(map[0], ','); // cycle thru the ranges for (n=0; NULL != rngs[n]; n++) { endpts = PMIx_Argv_split(rngs[n], '-'); start = strtoul(endpts[0], NULL, 10); if (NULL == endpts[1]) { // just a number obj = hwloc_get_obj_by_type(topo, type, start); hwloc_bitmap_or(cpuset, cpuset, obj->cpuset); } else { // cycle across the range stop = strtoul(endpts[1], NULL, 10); for (m=start; m <=stop; m++) { obj = hwloc_get_obj_by_type(topo, type, m); hwloc_bitmap_or(cpuset, cpuset, obj->cpuset); } } PMIx_Argv_free(endpts); } PMIx_Argv_free(rngs); PMIx_Argv_free(map); return PMIX_SUCCESS; } int main(int argc, char **argv) { pmix_info_t *info; pmix_status_t rc; size_t ninfo; int exit_code = 0; pmix_value_t *val; size_t n; int m; unsigned ui; char *gpu = NULL, *nic = NULL, *bind = NULL, *tobj, *tmp; bool list = false; pmix_topology_t *mytopo; pmix_proc_t myproc; pmix_cpuset_t mycpuset; pmix_device_distance_t *distances; size_t ndist; pmix_device_type_t type = PMIX_DEVTYPE_OPENFABRICS | PMIX_DEVTYPE_NETWORK | PMIX_DEVTYPE_COPROC | PMIX_DEVTYPE_GPU; hwloc_obj_type_t objtype = HWLOC_OBJ_TYPE_MAX; for (m=1; m < argc; m++) { if (0 == strcmp(argv[m], "-h") || 0 == strcmp(argv[m], "--help")) { output_usage(); exit(0); } else if (0 == strcmp(argv[m], "--gpu")) { if (NULL == argv[m+1]) { output_usage(); exit(1); } gpu = argv[m+1]; ++m; } else if (0 == strcmp(argv[m], "--nic")) { if (NULL == argv[m+1]) { output_usage(); exit(1); } nic = argv[m+1]; ++m; } else if (0 == strcmp(argv[m], "--bind")) { if (NULL == argv[m+1]) { output_usage(); exit(1); } bind = argv[m+1]; ++m; } else if (0 == strcmp(argv[m], "--list")) { if (NULL == argv[m+1]) { output_usage(); exit(1); } tobj = argv[m+1]; list = true; ++m; } else if (0 == strcmp(argv[m], "--num")) { if (NULL == argv[m+1]) { output_usage(); exit(1); } // convert the type objtype = convert_type(argv[m+1], &tobj); if (HWLOC_OBJ_TYPE_MAX == objtype) { exit(1); } ++m; } else { fprintf(stderr, "Unknown option: %s\n", argv[m]); output_usage(); exit(1); } } if (NULL == gpu && NULL == nic && NULL == bind && HWLOC_OBJ_TYPE_MAX == objtype) { output_usage(); exit(1); } if (PMIX_SUCCESS != (rc = PMIx_server_init(&mymodule, NULL, 0))) { fprintf(stderr, "Init failed with error %d\n", rc); return rc; } /* get my procID */ rc = PMIx_Get(NULL, PMIX_PROCID, NULL, 0, &val); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Get of my procID failed: %s\n", PMIx_Error_string(rc)); goto cleanup; } PMIX_LOAD_PROCID(&myproc, val->data.proc->nspace, val->data.proc->rank); PMIX_VALUE_FREE(val, 1); /* get my topology */ rc = PMIx_Get(&myproc, PMIX_TOPOLOGY2, NULL, 0, &val); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Get of my topology failed: %s\n", PMIx_Error_string(rc)); goto cleanup; } mytopo = val->data.topo; val->data.topo = NULL; PMIX_VALUE_FREE(val, 1); fprintf(stderr, "Got my topology: Source = %s\n", (NULL == mytopo->source) ? "NULL" : mytopo->source); // did they just want to know how many obj's of a given // type are in this topology? if (HWLOC_OBJ_TYPE_MAX != objtype) { // they asked for the number of objects ui = hwloc_get_nbobjs_by_type(mytopo->topology, objtype); fprintf(stderr, "There are %u %s in this topology\n", ui, tobj); goto cleanup; } // did they just want to get a list of NICs or GPUs? if (list) { } /* get my cpuset */ PMIX_CPUSET_CONSTRUCT(&mycpuset); if (NULL == bind) { rc = PMIx_Get_cpuset(&mycpuset, PMIX_CPUBIND_PROCESS); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Get of my cpuset failed: %s\n", PMIx_Error_string(rc)); goto cleanup; } } else { mycpuset.bitmap = hwloc_bitmap_alloc(); rc = construct_cpuset(mytopo->topology, mycpuset.bitmap, bind); if (PMIX_SUCCESS != rc) { goto cleanup; } mycpuset.source = "hwloc"; } PMIx_server_generate_cpuset_string(&mycpuset, &tmp); fprintf(stderr, "My cpuset: %s\n", tmp); free(tmp); ninfo = 1; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_DEVICE_TYPE, &type, PMIX_DEVTYPE); rc = PMIx_Compute_distances(mytopo, &mycpuset, info, ninfo, &distances, &ndist); PMIX_INFO_FREE(info, ninfo); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Compute distances failed: %s\n", PMIx_Error_string(rc)); } else { for (n = 0; n < ndist; n++) { fprintf(stderr, "Device[%d]: UUID %s OSname: %s Type %s MinDist %u MaxDist %u\n", (int) n, distances[n].uuid, distances[n].osname, PMIx_Device_type_string(distances[n].type), distances[n].mindist, distances[n].maxdist); } } cleanup: if (PMIX_SUCCESS != rc) { exit_code = rc; } /* finalize the server library */ if (PMIX_SUCCESS != (rc = PMIx_server_finalize())) { fprintf(stderr, "Finalize failed with error %s\n", PMIx_Error_string(rc)); exit_code = rc; } if (0 == exit_code) { fprintf(stderr, "Test finished OK!\n"); } else { fprintf(stderr, "TEST FAILED WITH ERROR %s\n", PMIx_Error_string(exit_code)); } return exit_code; } pmix-6.1.1~rc2/test/simple/simpqual.c0000664000175000017500000002536215203536752017754 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #define MAXCNT 1 static pmix_proc_t myproc; int main(int argc, char **argv) { int rc; pmix_value_t value; pmix_value_t *val = &value; pmix_proc_t proc; uint32_t nprocs; pmix_info_t *iptr; size_t sz; pmix_data_array_t darray; PMIX_HIDE_UNUSED_PARAMS(argc, argv); if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "%s: PMIx_Init failed: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "%s: Running on node %s", PMIX_NAME_PRINT(&myproc), pmix_globals.hostname); /* get number of procs */ PMIX_LOAD_PROCID(&proc, myproc.nspace, PMIX_RANK_WILDCARD); if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "%s: PMIx_Get job size failed: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); exit(rc); } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "%s job size %d", PMIX_NAME_PRINT(&myproc), nprocs); /* put a qualified value */ PMIX_DATA_ARRAY_CONSTRUCT(&darray, 2, PMIX_INFO); iptr = (pmix_info_t*)darray.array; /* load the primary key-value */ sz = myproc.rank * 100; PMIX_INFO_LOAD(&iptr[0], PMIX_GROUP_LOCAL_CID, &sz, PMIX_SIZE); /* provide a qualifier */ sz = 123456; PMIX_INFO_LOAD(&iptr[1], "OURQUALIFIER", &sz, PMIX_SIZE); PMIX_INFO_SET_QUALIFIER(&iptr[1]); // mark it as a qualifier /* load the value */ PMIX_VALUE_LOAD(&value, &darray, PMIX_DATA_ARRAY); PMIX_DATA_ARRAY_DESTRUCT(&darray); rc = PMIx_Put(PMIX_GLOBAL, PMIX_QUALIFIED_VALUE, &value); if (PMIX_SUCCESS != rc) { pmix_output(0, "%s failed to put qualified value: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); exit(rc); } /* put another qualified value of the same key */ PMIX_DATA_ARRAY_CONSTRUCT(&darray, 2, PMIX_INFO); iptr = (pmix_info_t*)darray.array; /* load the primary key-value */ sz = 1 + myproc.rank * 100; PMIX_INFO_LOAD(&iptr[0], PMIX_GROUP_LOCAL_CID, &sz, PMIX_SIZE); /* provide a qualifier */ sz = 891011; PMIX_INFO_LOAD(&iptr[1], "OURQUALIFIER", &sz, PMIX_SIZE); PMIX_INFO_SET_QUALIFIER(&iptr[1]); // mark it as a qualifier /* load the value */ PMIX_VALUE_LOAD(&value, &darray, PMIX_DATA_ARRAY); PMIX_DATA_ARRAY_DESTRUCT(&darray); rc = PMIx_Put(PMIX_GLOBAL, PMIX_QUALIFIED_VALUE, &value); if (PMIX_SUCCESS != rc) { pmix_output(0, "%s failed to put another qualified value: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); exit(rc); } /* put an unqualified value of the same key */ sz = 2 + (myproc.rank * 100); PMIX_VALUE_LOAD(&value, &sz, PMIX_SIZE); rc = PMIx_Put(PMIX_GLOBAL, PMIX_GROUP_LOCAL_CID, &value); if (PMIX_SUCCESS != rc) { pmix_output(0, "%s failed to put unqualified value: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); exit(rc); } if (PMIX_SUCCESS != (rc = PMIx_Commit())) { pmix_output(0, "%s: PMIx_Commit failed: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); exit(rc); } /* call fence to ensure the data is received */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "%s: PMIx_Fence failed: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); exit(rc); } /* first my own value without qualifiers */ pmix_output(0, "%s Looking for my own value w/o quals", PMIX_NAME_PRINT(&myproc)); rc = PMIx_Get(&myproc, PMIX_GROUP_LOCAL_CID, NULL, 0, &val); if (PMIX_SUCCESS != rc) { pmix_output(0, "%s UNABLE TO GET MY OWN VALUE W/O QUALS: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); } else if (val->data.size == ((100*myproc.rank)+2)) { pmix_output(0, "%s Returned my own correct value w/o quals: %s", PMIX_NAME_PRINT(&myproc), PMIx_Value_string(val)); } else { pmix_output(0, "%s Returned my own incorrect value w/o quals: %s", PMIX_NAME_PRINT(&myproc), PMIx_Value_string(val)); exit(-1); } /* now with the correct qualifier */ /* get the qualified value for a peer */ if (1 < nprocs) { proc.rank = myproc.rank + 1; if (proc.rank == nprocs) { proc.rank = 0; } /* first without qualifiers */ pmix_output(0, "%s Looking for value w/o quals", PMIX_NAME_PRINT(&myproc)); rc = PMIx_Get(&proc, PMIX_GROUP_LOCAL_CID, NULL, 0, &val); if (PMIX_SUCCESS != rc) { pmix_output(0, "%s UNABLE TO GET VALUE W/O QUALS: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); } else if (val->data.size == ((100*proc.rank)+2)) { pmix_output(0, "%s Returned correct value w/o quals: %s", PMIX_NAME_PRINT(&myproc), PMIx_Value_string(val)); } else { pmix_output(0, "%s Returned incorrect value w/o quals: %s", PMIX_NAME_PRINT(&myproc), PMIx_Value_string(val)); exit(-1); } /* now with the correct qualifier */ pmix_output(0, "%s Looking for first qualified value with correct qual", PMIX_NAME_PRINT(&myproc)); PMIX_INFO_CREATE(iptr, 1); sz = 123456; PMIX_INFO_LOAD(&iptr[0], "OURQUALIFIER", &sz, PMIX_SIZE); PMIX_INFO_SET_QUALIFIER(&iptr[0]); // mark it as a qualifier rc = PMIx_Get(&proc, PMIX_GROUP_LOCAL_CID, iptr, 1, &val); if (PMIX_SUCCESS != rc) { pmix_output(0, "%s UNABLE TO GET QUALIFIED VALUE WITH CORRECT QUAL: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); } else if (val->data.size == (100*proc.rank)) { pmix_output(0, "%s GOT CORRECT QUALIFIED VALUE WITH CORRECT QUAL: %s", PMIX_NAME_PRINT(&myproc), PMIx_Value_string(val)); } else { pmix_output(0, "%s GOT INCORRECT QUALIFIED VALUE WITH CORRECT QUAL: %s", PMIX_NAME_PRINT(&myproc), PMIx_Value_string(val)); exit(-1); } PMIX_INFO_FREE(iptr, 1); /* now second value with the correct qualifier */ pmix_output(0, "%s Looking for second qualified value with correct qual", PMIX_NAME_PRINT(&myproc)); PMIX_INFO_CREATE(iptr, 1); sz = 891011; PMIX_INFO_LOAD(&iptr[0], "OURQUALIFIER", &sz, PMIX_SIZE); PMIX_INFO_SET_QUALIFIER(&iptr[0]); // mark it as a qualifier rc = PMIx_Get(&proc, PMIX_GROUP_LOCAL_CID, iptr, 1, &val); if (PMIX_SUCCESS != rc) { pmix_output(0, "%s UNABLE TO GET SECOND QUALIFIED VALUE WITH CORRECT QUAL: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); } else if (val->data.size == (100*proc.rank)+1) { pmix_output(0, "%s GOT CORRECT SECOND QUALIFIED VALUE WITH CORRECT QUAL: %s", PMIX_NAME_PRINT(&myproc), PMIx_Value_string(val)); } else { pmix_output(0, "%s GOT INCORRECT SECOND QUALIFIED VALUE WITH CORRECT QUAL: %s", PMIX_NAME_PRINT(&myproc), PMIx_Value_string(val)); exit(-1); } PMIX_INFO_FREE(iptr, 1); /* and now with an incorrect qualifier - should not return success */ pmix_output(0, "%s Looking for qualified value with incorrect qual", PMIX_NAME_PRINT(&myproc)); PMIX_INFO_CREATE(iptr, 1); sz = 0; PMIX_INFO_LOAD(&iptr[0], "OURQUALIFIER", &sz, PMIX_SIZE); PMIX_INFO_SET_QUALIFIER(&iptr[0]); // mark it as a qualifier rc = PMIx_Get(&proc, PMIX_GROUP_LOCAL_CID, iptr, 1, &val); if (PMIX_SUCCESS == rc) { pmix_output(0, "%s GOT QUALIFIED VALUE WITH INCORRECT QUAL: %s", PMIX_NAME_PRINT(&myproc), PMIx_Value_string(val)); } else if (PMIX_ERR_NOT_FOUND == rc) { pmix_output(0, "%s DID NOT GET QUALIFIED VALUE WITH INCORRECT QUAL: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); } else { pmix_output(0, "%s GOT INCORRECT STATUS FOR QUALIFIED VALUE WITH INCORRECT QUAL: %s", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); exit(-1); } PMIX_INFO_FREE(iptr, 1); } /* finalize us */ pmix_output(0, "%s: Finalizing", PMIX_NAME_PRINT(&myproc)); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "%s:PMIx_Finalize failed: %s\n", PMIX_NAME_PRINT(&myproc), PMIx_Error_string(rc)); } else { fprintf(stderr, "%s:PMIx_Finalize successfully completed\n", PMIX_NAME_PRINT(&myproc)); } fflush(stderr); return (rc); } pmix-6.1.1~rc2/test/simple/asyncio.c0000664000175000017500000000170515203536752017561 0ustar alastairalastair#include #include #include #include #define REPS 2 char data[1024]; int main(int argc, char *argv[]) { int n, size, start, end, delay; /* write a line out that has a newline at the end */ memset(data, 0, sizeof(data)); memcpy(data, "BEGIN123456788865432356897654345678END\n", strlen("BEGIN123456788865432356897654345678END\n")); write(1, data, strlen(data)); for (n=0; n < REPS; n++) { fprintf(stdout, "REP %d\n", n); start = 0; delay = random() % 4; // sleep(delay); memset(data, 0, sizeof(data)); memset(data, 'A', 1024); end = 100; write(1, data, end); start += end; delay = random() % 4; // sleep(delay); write(1, &data[start], end); start += end; delay = random() % 4; // sleep(delay); write(1, &data[start], 1024 - start); fprintf(stdout, "\n"); } } pmix-6.1.1~rc2/test/simple/test_pmix.c0000664000175000017500000000416515203536752020133 0ustar alastairalastair #include "include/pmix.h" #include #include #include #include #include #include #include #include static void hide_unused_params(int x, ...) { va_list ap; (void)x; va_start(ap, x); va_end(ap); } int main(int argc, char **argv) { pmix_proc_t myproc; pmix_status_t rc=0; int rank; hide_unused_params(rc, argc, argv); rc = PMIx_Init(&myproc, NULL, 0); assert(PMIX_SUCCESS == rc); { pmix_value_t *value; rc = PMIx_Get(&myproc, PMIX_RANK, NULL, 0, &value); assert(PMIX_SUCCESS == rc); printf("%d\n", value->type); assert(value->type == PMIX_INT); rank = value->data.uint32; PMIX_VALUE_RELEASE(value); } if (rank == 0) { pmix_info_t *info; PMIX_INFO_CREATE(info, 1); snprintf(info[0].key, PMIX_MAX_KEYLEN, "magic-found"); info[0].value.type = PMIX_STRING; info[0].value.data.string = "yes"; rc = PMIx_Publish(info, 1); assert(PMIX_SUCCESS == rc); } printf("I am rank %d\n", rank); { bool flag; pmix_info_t *info; PMIX_INFO_CREATE(info, 1); flag = true; PMIX_INFO_LOAD(info, PMIX_COLLECT_DATA, &flag, PMIX_BOOL); rc = PMIx_Fence(&myproc, 1, info, 1); assert(PMIX_SUCCESS == rc); PMIX_INFO_FREE(info, 1); } if (rank == 1) { int i; pmix_pdata_t *pdata; PMIX_PDATA_CREATE(pdata, 2); snprintf(pdata[0].key, PMIX_MAX_KEYLEN, "magic-found"); snprintf(pdata[1].key, PMIX_MAX_KEYLEN, "magic-not-found"); rc = PMIx_Lookup(&pdata[0], 2, NULL, 0); assert((PMIX_SUCCESS == rc) || (PMIX_ERR_NOT_FOUND == rc)); for (i = 0; i < 2; i++) if (pdata[i].value.type == PMIX_STRING) printf("Found[%d] %d %s\n", i, pdata[i].value.type, pdata[i].value.data.string); else printf("Found[%d] %d\n", i, pdata[i].value.type); PMIX_PDATA_FREE(pdata, 1); } rc = PMIx_Finalize(NULL, 0); assert(PMIX_SUCCESS == rc); } pmix-6.1.1~rc2/test/simple/simpsched.c0000664000175000017500000001702115203536752020071 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include #include #include #include #include #include #include #include #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "simptest.h" static pmix_server_module_t mymodule = {0}; typedef struct { mylock_t lock; pmix_status_t status; pmix_info_t *info; size_t ninfo; } mycaddy_t; static void local_cbfunc(pmix_status_t status, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; lock->status = status; DEBUG_WAKEUP_THREAD(lock); } static void setup_cbfunc(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *provided_cbdata, pmix_op_cbfunc_t cbfunc, void *cbdata) { mycaddy_t *mq = (mycaddy_t *) provided_cbdata; size_t n; PMIX_HIDE_UNUSED_PARAMS(status); /* transfer it to the caddy for return to the main thread */ if (0 < ninfo) { PMIX_INFO_CREATE(mq->info, ninfo); mq->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&mq->info[n], &info[n]); } } /* let the library release the data and cleanup from * the operation */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } DEBUG_WAKEUP_THREAD(&mq->lock); } int main(int argc, char **argv) { pmix_info_t *info, *iptr; pmix_status_t rc; pmix_fabric_t myfabric; size_t ninfo; int exit_code = 0; size_t n; char *hosts, *procs; char *regex, *ppn; mylock_t lock; mycaddy_t cd; pmix_value_t *val; pmix_nspace_t ncache; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* smoke test */ if (PMIX_SUCCESS != 0) { fprintf(stderr, "ERROR IN COMPUTING CONSTANTS: PMIX_SUCCESS = %d\n", PMIX_SUCCESS); exit(1); } fprintf(stderr, "PID: %lu Testing version %s\n", (unsigned long) getpid(), PMIx_Get_version()); /* set a known network configuration for the pnet/test component */ putenv("PMIX_MCA_pnet_test_planes=plane:d:3:4,plane:s:2,plane:3"); putenv("PMIX_MCA_pnet_test_nodes=test000,test001,test002"); putenv("PMIX_MCA_pnet=test"); ninfo = 1; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_SERVER_SCHEDULER, NULL, PMIX_BOOL); if (PMIX_SUCCESS != (rc = PMIx_server_init(&mymodule, info, ninfo))) { fprintf(stderr, "Init failed with error %d\n", rc); return rc; } PMIX_INFO_FREE(info, ninfo); /* register a fabric */ rc = PMIx_Fabric_register(&myfabric, NULL, 0); if (PMIX_SUCCESS == rc) { /* scan the returned info array for values */ for (n = 0; n < myfabric.ninfo; n++) { if (PMIX_CHECK_KEY(&myfabric.info[n], PMIX_FABRIC_VENDOR)) { fprintf(stderr, "Fabric vendor: %s\n", myfabric.info[n].value.data.string); } else if (PMIX_CHECK_KEY(&myfabric.info[n], PMIX_FABRIC_IDENTIFIER)) { fprintf(stderr, "Fabric ID: %s\n", myfabric.info[n].value.data.string); } else if (PMIX_CHECK_KEY(&myfabric.info[n], PMIX_FABRIC_NUM_DEVICES)) { fprintf(stderr, "Number of fabric vertices: %u\n", (unsigned) myfabric.info[n].value.data.size); } } rc = PMIx_Get(NULL, PMIX_FABRIC_DEVICES, NULL, 0, &val); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Fabric get devices failed with error: %s\n", PMIx_Error_string(rc)); goto cleanup; } fprintf(stderr, "Device info:\n"); info = (pmix_info_t *) val->data.darray->array; ninfo = val->data.darray->size; for (n = 0; n < ninfo; n++) { fprintf(stderr, "\t%s:\t%s\n", info[n].key, info[n].value.data.string); } } else { fprintf(stderr, "Register fabric failed with error %s\n", PMIx_Error_string(rc)); } /* setup an application */ PMIX_INFO_CREATE(iptr, 4); hosts = "test000,test001,test002"; PMIx_generate_regex(hosts, ®ex); PMIX_INFO_LOAD(&iptr[0], PMIX_NODE_MAP, regex, PMIX_REGEX); free(regex); procs = "0,1,2;3,4,5;6,7"; PMIx_generate_ppn(procs, &ppn); PMIX_INFO_LOAD(&iptr[1], PMIX_PROC_MAP, ppn, PMIX_REGEX); free(ppn); PMIX_LOAD_KEY(iptr[2].key, PMIX_ALLOC_NETWORK); iptr[2].value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(iptr[2].value.data.darray, 2, PMIX_INFO); info = (pmix_info_t *) iptr[2].value.data.darray->array; PMIX_INFO_LOAD(&info[0], PMIX_ALLOC_NETWORK_ID, "SIMPSCHED.net", PMIX_STRING); PMIX_INFO_LOAD(&info[1], PMIX_ALLOC_NETWORK_SEC_KEY, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&iptr[3], PMIX_SETUP_APP_ENVARS, NULL, PMIX_BOOL); PMIX_LOAD_NSPACE(ncache, "SIMPSCHED"); DEBUG_CONSTRUCT_LOCK(&cd.lock); rc = PMIx_server_setup_application(ncache, iptr, 4, setup_cbfunc, &cd); if (PMIX_SUCCESS != rc) { pmix_output(0, "[%s:%d] PMIx_server_setup_application failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); DEBUG_DESTRUCT_LOCK(&cd.lock); goto cleanup; } DEBUG_WAIT_THREAD(&cd.lock); DEBUG_DESTRUCT_LOCK(&cd.lock); /* setup the local subsystem */ DEBUG_CONSTRUCT_LOCK(&lock); rc = PMIx_server_setup_local_support(ncache, cd.info, cd.ninfo, local_cbfunc, &lock); if (PMIX_SUCCESS != rc) { pmix_output(0, "[%s:%d] PMIx_server_setup_local_support failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); DEBUG_DESTRUCT_LOCK(&lock); goto cleanup; } DEBUG_WAIT_THREAD(&lock); DEBUG_DESTRUCT_LOCK(&lock); cleanup: if (PMIX_SUCCESS != rc) { exit_code = rc; } /* finalize the server library */ if (PMIX_SUCCESS != (rc = PMIx_server_finalize())) { fprintf(stderr, "Finalize failed with error %d\n", rc); exit_code = rc; } if (0 == exit_code) { fprintf(stderr, "Test finished OK!\n"); } else { fprintf(stderr, "TEST FAILED WITH ERROR %d\n", exit_code); } return exit_code; } pmix-6.1.1~rc2/test/simple/get_put_example.c0000664000175000017500000000330015203536752021267 0ustar alastairalastair#include #include #include #include #include #include #include #include static void hide_unused_params(int x, ...) { va_list ap; (void)x; va_start(ap, x); va_end(ap); } int main(int argc, char **argv) { int rc=0; pmix_value_t value; pmix_value_t *val = &value; pmix_value_t pvalue; pmix_proc_t myproc, rootproc; pmix_info_t info; hide_unused_params(rc, argc, argv); if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { fprintf(stderr, "Init failed.\n"); exit(1); } fprintf(stderr, "[%s:%u]: Running\n", myproc.nspace, myproc.rank); PMIX_VALUE_LOAD(&pvalue, "hello", PMIX_STRING); if (myproc.rank == 0) { if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_GLOBAL, "my.foo", &pvalue))) { fprintf(stderr, "Put of my.foo failed\n"); exit(1); } } PMIx_Commit(); bool tvalue = 1; strcpy(info.key, PMIX_COLLECT_DATA); PMIX_VALUE_LOAD(&(info.value), &tvalue, PMIX_BOOL); PMIx_Fence(NULL, 0, &info, 1); fprintf(stderr, "[%s:%u]: Fence complete\n", myproc.nspace, myproc.rank); rootproc = myproc; rootproc.rank = 0; if (PMIX_SUCCESS != (rc = PMIx_Get(&rootproc, "my.foo", NULL, 0, &val))) { fprintf(stderr, "Get of root's my.foo failed\n"); exit(1); } fprintf(stderr, "[%s:%u]: Get complete and successful\n", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc); exit(1); } return (rc); } pmix-6.1.1~rc2/test/simple/simptest.h0000664000175000017500000000413015203536752017764 0ustar alastairalastair/* * Copyright (c) 2018-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include #include #include #include #include typedef struct { pthread_mutex_t mutex; pthread_cond_t cond; volatile bool active; pmix_status_t status; } mylock_t; #define DEBUG_CONSTRUCT_LOCK(l) \ do { \ pthread_mutex_init(&(l)->mutex, NULL); \ pthread_cond_init(&(l)->cond, NULL); \ (l)->active = true; \ (l)->status = PMIX_SUCCESS; \ } while (0) #define DEBUG_DESTRUCT_LOCK(l) \ do { \ pthread_mutex_destroy(&(l)->mutex); \ pthread_cond_destroy(&(l)->cond); \ } while (0) #define DEBUG_WAIT_THREAD(lck) \ do { \ pthread_mutex_lock(&(lck)->mutex); \ while ((lck)->active) { \ pthread_cond_wait(&(lck)->cond, &(lck)->mutex); \ } \ pthread_mutex_unlock(&(lck)->mutex); \ } while (0) #define DEBUG_WAKEUP_THREAD(lck) \ do { \ pthread_mutex_lock(&(lck)->mutex); \ (lck)->active = false; \ pthread_cond_broadcast(&(lck)->cond); \ pthread_mutex_unlock(&(lck)->mutex); \ } while (0) #define SIMPTEST_THREADSHIFT(r, c) \ do { \ pmix_event_assign(&((r)->ev), simptest_evbase, -1, EV_WRITE, (c), (r)); \ PMIX_POST_OBJECT((r)); \ pmix_event_active(&((r)->ev), EV_WRITE, 1); \ } while (0) pmix-6.1.1~rc2/test/simple/simpcycle.c0000664000175000017500000001754715203536752020117 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * Copyright (c) 2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #define MAXCNT 1 static volatile bool completed = false; static pmix_proc_t myproc; static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, info, ninfo, results, nresults); pmix_output(0, "Client %s:%d NOTIFIED with status %s", myproc.nspace, myproc.rank, PMIx_Error_string(status)); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } completed = true; } /* this is an event notification function that we explicitly request * be called when the PMIX_MODEL_DECLARED notification is issued. * We could catch it in the general event notification function and test * the status to see if the status matched, but it often is simpler * to declare a use-specific notification callback point. In this case, * we are asking to know whenever a model is declared as a means * of testing server self-notification */ static void model_callback(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { size_t n; PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, results, nresults); /* just let us know it was received */ fprintf(stderr, "%s:%d Model event handler called with status %d(%s)\n", myproc.nspace, myproc.rank, status, PMIx_Error_string(status)); for (n = 0; n < ninfo; n++) { if (PMIX_STRING == info[n].value.type) { fprintf(stderr, "%s:%d\t%s:\t%s\n", myproc.nspace, myproc.rank, info[n].key, info[n].value.data.string); } } /* we must NOT tell the event handler state machine that we * are the last step as that will prevent it from notifying * anyone else that might be listening for declarations */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } } int main(int argc, char **argv) { int rc, nprocs; pmix_value_t value; pmix_value_t *val = &value; char *tmp; pmix_proc_t proc; pmix_info_t *iptr; size_t ninfo; pmix_status_t code; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* init us and declare we are a test programming model */ PMIX_INFO_CREATE(iptr, 2); PMIX_INFO_LOAD(&iptr[0], PMIX_PROGRAMMING_MODEL, "TEST", PMIX_STRING); PMIX_INFO_LOAD(&iptr[1], PMIX_MODEL_LIBRARY_NAME, "PMIX", PMIX_STRING); if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, iptr, 2))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } PMIX_INFO_FREE(iptr, 2); pmix_output(0, "Client ns %s rank %d: Running on node %s", myproc.nspace, myproc.rank, pmix_globals.hostname); /* test something */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get job size failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "Client %s:%d job size %d", myproc.nspace, myproc.rank, nprocs); /* register a handler specifically for when models declare */ ninfo = 1; PMIX_INFO_CREATE(iptr, ninfo); PMIX_INFO_LOAD(&iptr[0], PMIX_EVENT_HDLR_NAME, "SIMPCLIENT-MODEL", PMIX_STRING); code = PMIX_MODEL_DECLARED; PMIx_Register_event_handler(&code, 1, iptr, ninfo, model_callback, NULL, NULL); PMIX_INFO_FREE(iptr, ninfo); /* register our errhandler */ PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, NULL, NULL); /* put a few values */ if (0 > asprintf(&tmp, "%s-%d-internal", myproc.nspace, myproc.rank)) { errno = ENOMEM; abort(); } value.type = PMIX_UINT32; value.data.uint32 = 1234; if (PMIX_SUCCESS != (rc = PMIx_Store_internal(&myproc, tmp, &value))) { pmix_output(0, "Client ns %s rank %d: PMIx_Store_internal failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } /* get a list of our local peers */ if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_LOCAL_PEERS, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get local peers failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } PMIX_VALUE_RELEASE(val); /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing(1)", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } /* initialize us again */ fprintf(stderr, "Client Init(2)\n"); if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "Client ns %s rank %d: Finalizing(2)", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (rc); } pmix-6.1.1~rc2/test/simple/simpfabric.c0000664000175000017500000002022115203536752020225 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include #include #include #include #include #include #include #include #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" #include "simptest.h" static pmix_server_module_t mymodule = {0}; typedef struct { mylock_t lock; pmix_status_t status; pmix_info_t *info; size_t ninfo; } mycaddy_t; static void local_cbfunc(pmix_status_t status, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; lock->status = status; DEBUG_WAKEUP_THREAD(lock); } static void setup_cbfunc(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *provided_cbdata, pmix_op_cbfunc_t cbfunc, void *cbdata) { mycaddy_t *mq = (mycaddy_t *) provided_cbdata; size_t n; PMIX_HIDE_UNUSED_PARAMS(status); /* transfer it to the caddy for return to the main thread */ if (0 < ninfo) { PMIX_INFO_CREATE(mq->info, ninfo); mq->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&mq->info[n], &info[n]); } } /* let the library release the data and cleanup from * the operation */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } DEBUG_WAKEUP_THREAD(&mq->lock); } int main(int argc, char **argv) { pmix_info_t *info, *iptr; pmix_status_t rc; size_t ninfo; int exit_code = 0; size_t n; char *hosts, *procs; char *regex, *ppn; mylock_t lock; mycaddy_t cd; pmix_value_t *val; pmix_topology_t *mytopo; pmix_proc_t myproc; pmix_cpuset_t mycpuset; pmix_device_distance_t *distances; size_t ndist; pmix_device_type_t type = PMIX_DEVTYPE_OPENFABRICS | PMIX_DEVTYPE_NETWORK | PMIX_DEVTYPE_COPROC | PMIX_DEVTYPE_GPU; pmix_nspace_t ncache; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* smoke test */ if (PMIX_SUCCESS != 0) { fprintf(stderr, "ERROR IN COMPUTING CONSTANTS: PMIX_SUCCESS = %d\n", PMIX_SUCCESS); exit(1); } fprintf(stderr, "PID: %lu Testing version %s\n", (unsigned long) getpid(), PMIx_Get_version()); ninfo = 1; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_SERVER_SCHEDULER, NULL, PMIX_BOOL); if (PMIX_SUCCESS != (rc = PMIx_server_init(&mymodule, info, ninfo))) { fprintf(stderr, "Init failed with error %d\n", rc); return rc; } PMIX_INFO_FREE(info, ninfo); /* get my procID */ fprintf(stderr, "Getting procID\n"); rc = PMIx_Get(NULL, PMIX_PROCID, NULL, 0, &val); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Get of my procID failed: %s\n", PMIx_Error_string(rc)); goto cleanup; } PMIX_LOAD_PROCID(&myproc, val->data.proc->nspace, val->data.proc->rank); PMIX_VALUE_FREE(val, 1); /* get my topology */ fprintf(stderr, "GETTING TOPOLOGY\n"); rc = PMIx_Get(&myproc, PMIX_TOPOLOGY2, NULL, 0, &val); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Get of my topology failed: %s\n", PMIx_Error_string(rc)); goto cleanup; } mytopo = val->data.topo; val->data.topo = NULL; PMIX_VALUE_FREE(val, 1); fprintf(stderr, "Got my topology: Source = %s\n", (NULL == mytopo->source) ? "NULL" : mytopo->source); /* get my cpuset */ fprintf(stderr, "GETTING CPUSET\n"); PMIX_CPUSET_CONSTRUCT(&mycpuset); rc = PMIx_Get_cpuset(&mycpuset, PMIX_CPUBIND_PROCESS); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Get of my cpuset failed: %s\n", PMIx_Error_string(rc)); goto cleanup; } PMIx_server_generate_cpuset_string(&mycpuset, &ppn); fprintf(stderr, "Got my cpuset: %s\n", ppn); free(ppn); ninfo = 1; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_DEVICE_TYPE, &type, PMIX_DEVTYPE); rc = PMIx_Compute_distances(mytopo, &mycpuset, info, ninfo, &distances, &ndist); PMIX_INFO_FREE(info, ninfo); if (PMIX_SUCCESS != rc) { fprintf(stderr, "Compute distances failed: %s\n", PMIx_Error_string(rc)); } else { for (n = 0; n < ndist; n++) { fprintf(stderr, "Device[%d]: UUID %s OSname: %s Type %s MinDist %u MaxDist %u\n", (int) n, distances[n].uuid, distances[n].osname, PMIx_Device_type_string(distances[n].type), distances[n].mindist, distances[n].maxdist); } } /* setup an application */ PMIX_INFO_CREATE(iptr, 4); hosts = "test000,test001,test002"; PMIx_generate_regex(hosts, ®ex); PMIX_INFO_LOAD(&iptr[0], PMIX_NODE_MAP, regex, PMIX_REGEX); free(regex); procs = "0,1,2;3,4,5;6,7"; PMIx_generate_ppn(procs, &ppn); PMIX_INFO_LOAD(&iptr[1], PMIX_PROC_MAP, ppn, PMIX_REGEX); free(ppn); PMIX_LOAD_KEY(iptr[2].key, PMIX_ALLOC_NETWORK); iptr[2].value.type = PMIX_DATA_ARRAY; PMIX_DATA_ARRAY_CREATE(iptr[2].value.data.darray, 2, PMIX_INFO); info = (pmix_info_t *) iptr[2].value.data.darray->array; PMIX_INFO_LOAD(&info[0], PMIX_ALLOC_NETWORK_ID, "SIMPSCHED.net", PMIX_STRING); PMIX_INFO_LOAD(&info[1], PMIX_ALLOC_NETWORK_SEC_KEY, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&iptr[3], PMIX_SETUP_APP_ENVARS, NULL, PMIX_BOOL); PMIX_LOAD_NSPACE(ncache, "SIMPSCHED"); DEBUG_CONSTRUCT_LOCK(&cd.lock); rc = PMIx_server_setup_application(ncache, iptr, 4, setup_cbfunc, &cd); if (PMIX_SUCCESS != rc) { pmix_output(0, "[%s:%d] PMIx_server_setup_application failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); DEBUG_DESTRUCT_LOCK(&cd.lock); goto cleanup; } DEBUG_WAIT_THREAD(&cd.lock); DEBUG_DESTRUCT_LOCK(&cd.lock); /* setup the local subsystem */ DEBUG_CONSTRUCT_LOCK(&lock); rc = PMIx_server_setup_local_support(ncache, cd.info, cd.ninfo, local_cbfunc, &lock); if (PMIX_SUCCESS != rc) { pmix_output(0, "[%s:%d] PMIx_server_setup_local_support failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); DEBUG_DESTRUCT_LOCK(&lock); goto cleanup; } DEBUG_WAIT_THREAD(&lock); DEBUG_DESTRUCT_LOCK(&lock); cleanup: if (PMIX_SUCCESS != rc) { exit_code = rc; } /* finalize the server library */ if (PMIX_SUCCESS != (rc = PMIx_server_finalize())) { fprintf(stderr, "Finalize failed with error %d\n", rc); exit_code = rc; } if (0 == exit_code) { fprintf(stderr, "Test finished OK!\n"); } else { fprintf(stderr, "TEST FAILED WITH ERROR %d\n", exit_code); } return exit_code; } pmix-6.1.1~rc2/test/simple/simpdyn.c0000664000175000017500000002032615203536752017577 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" static pmix_proc_t myproc; int main(int argc, char **argv) { int rc; pmix_value_t value; pmix_value_t *val = &value; pmix_proc_t proc; uint32_t nprocs; char nsp2[PMIX_MAX_NSLEN + 1]; pmix_app_t *app; char hostname[PMIX_MAXHOSTNAMELEN]; pmix_proc_t *peers; size_t npeers, ntmp = 0; char *nodelist; PMIX_HIDE_UNUSED_PARAMS(argc, argv); gethostname(hostname, sizeof(hostname)); /* init us */ if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %d", myproc.nspace, myproc.rank, rc); exit(0); } pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank); /* get our job size */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get job size failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "Client %s:%d job size %d", myproc.nspace, myproc.rank, nprocs); /* call fence to sync */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc); goto done; } /* rank=0 calls spawn */ if (0 == myproc.rank) { PMIX_APP_CREATE(app, 1); app->cmd = strdup("./simpclient"); app->maxprocs = 2; PMIx_Argv_append_nosize(&app->argv, "simpclient"); PMIx_Argv_append_nosize(&app->argv, "-n"); PMIx_Argv_append_nosize(&app->argv, "2"); PMIx_Setenv("PMIX_ENV_VALUE", "3", true, &app->env); pmix_output(0, "Client ns %s rank %d: calling PMIx_Spawn", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Spawn(NULL, 0, app, 1, nsp2))) { pmix_output(0, "Client ns %s rank %d: PMIx_Spawn failed: %d", myproc.nspace, myproc.rank, rc); goto done; } PMIX_APP_FREE(app, 1); /* get their job size */ pmix_strncpy(proc.nspace, nsp2, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; val = NULL; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val)) || NULL == val) { pmix_output(0, "Client ns %s rank %d: PMIx_Get job %s size failed: %d", myproc.nspace, myproc.rank, nsp2, rc); goto done; } ntmp = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "Client %s:%d job %s size %d", myproc.nspace, myproc.rank, nsp2, (int) ntmp); } /* just cycle the connect/disconnect functions */ if (PMIX_SUCCESS != (rc = PMIx_Connect(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Connect failed: %d", myproc.nspace, myproc.rank, rc); goto done; } pmix_output(0, "Client ns %s rank %d: PMIx_Connect succeeded", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Disconnect(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Disonnect failed: %d", myproc.nspace, myproc.rank, rc); goto done; } pmix_output(0, "Client ns %s rank %d: PMIx_Disconnect succeeded", myproc.nspace, myproc.rank); /* finally, test the resolve functions */ if (0 == myproc.rank) { if (PMIX_SUCCESS != (rc = PMIx_Resolve_peers(hostname, NULL, &peers, &npeers))) { pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_peers failed for nspace %s: %d", myproc.nspace, myproc.rank, nsp2, rc); goto done; } if ((nprocs + ntmp) != npeers) { pmix_output( 0, "Client ns %s rank %d: PMIx_Resolve_peers returned incorrect npeers: %d vs %d", myproc.nspace, myproc.rank, (int) (nprocs + ntmp), (int) npeers); goto done; } pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_peers returned %d npeers", myproc.nspace, myproc.rank, (int) npeers); if (PMIX_SUCCESS != (rc = PMIx_Resolve_nodes(nsp2, &nodelist))) { pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_nodes failed for nspace %s: %d", myproc.nspace, myproc.rank, nsp2, rc); goto done; } pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_nodes %s", myproc.nspace, myproc.rank, nodelist); } else { if (PMIX_SUCCESS != (rc = PMIx_Resolve_peers(hostname, myproc.nspace, &peers, &npeers))) { pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_peers failed for nspace %s: %d", myproc.nspace, myproc.rank, myproc.nspace, rc); goto done; } if (nprocs != npeers) { pmix_output( 0, "Client ns %s rank %d: PMIx_Resolve_peers returned incorrect npeers: %d vs %d", myproc.nspace, myproc.rank, nprocs, (int) npeers); goto done; } pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_peers returned %d npeers", myproc.nspace, myproc.rank, (int) npeers); if (PMIX_SUCCESS != (rc = PMIx_Resolve_nodes(myproc.nspace, &nodelist))) { pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_nodes failed: %d", myproc.nspace, myproc.rank, rc); goto done; } pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_nodes %s", myproc.nspace, myproc.rank, nodelist); } PMIX_PROC_FREE(peers, npeers); free(nodelist); done: /* call fence to sync */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc); goto done; } /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (0); } pmix-6.1.1~rc2/test/simple/simpjctrl.c0000664000175000017500000002302215203536752020117 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2026 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "include/pmix.h" #include "simptest.h" static pmix_proc_t myproc; static void hide_unused_params(int x, ...) { va_list ap; (void)x; va_start(ap, x); va_end(ap); } /* this is the event notification function we pass down below * when registering for general events - i.e.,, the default * handler. We don't technically need to register one, but it * is usually good practice to catch any events that occur */ static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { int rc = 0; hide_unused_params(rc, evhdlr_registration_id, status, source, info, ninfo, results, nresults); if (NULL != cbfunc) { cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } /* event handler registration is done asynchronously because it * may involve the PMIx server registering with the host RM for * external events. So we provide a callback function that returns * the status of the request (success or an error), plus a numerical index * to the registered event. The index is used later on to deregister * an event handler - if we don't explicitly deregister it, then the * PMIx server will do so when it see us exit */ static void evhandler_reg_callbk(pmix_status_t status, size_t evhandler_ref, void *cbdata) { mylock_t *lk = (mylock_t *) cbdata; if (PMIX_SUCCESS != status) { fprintf(stderr, "Client %s:%d EVENT HANDLER REGISTRATION FAILED WITH STATUS %d, ref=%lu\n", myproc.nspace, myproc.rank, status, (unsigned long) evhandler_ref); } lk->status = status; DEBUG_WAKEUP_THREAD(lk); } static void infocbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata, pmix_release_cbfunc_t release_fn, void *release_cbdata) { mylock_t *lk = (mylock_t *) cbdata; int rc = 0; hide_unused_params(rc, info, ninfo); fprintf(stderr, "Callback recvd with status %d\n", status); /* release the caller */ if (NULL != release_fn) { release_fn(release_cbdata); } lk->status = status; DEBUG_WAKEUP_THREAD(lk); } int main(int argc, char **argv) { int rc=0; pmix_value_t value; pmix_value_t *val = &value; pmix_proc_t proc; uint32_t nprocs, n; pmix_info_t *info, *iptr; bool flag; mylock_t mylock; pmix_data_array_t *dptr; hide_unused_params(rc, argc, argv); /* init us - note that the call to "init" includes the return of * any job-related info provided by the RM. */ if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { fprintf(stderr, "Client ns %s rank %d: PMIx_Init failed: %d\n", myproc.nspace, myproc.rank, rc); exit(0); } fprintf(stderr, "Client ns %s rank %d: Running\n", myproc.nspace, myproc.rank); /* register our default event handler - again, this isn't strictly * required, but is generally good practice */ DEBUG_CONSTRUCT_LOCK(&mylock); PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, evhandler_reg_callbk, (void *) &mylock); DEBUG_WAIT_THREAD(&mylock); if (0 != mylock.status) { fprintf(stderr, "[%s:%d] Default handler registration failed\n", myproc.nspace, myproc.rank); exit(mylock.status); } DEBUG_DESTRUCT_LOCK(&mylock); /* job-related info is found in our nspace, assigned to the * wildcard rank as it doesn't relate to a specific rank. Setup * a name to retrieve such values */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; /* get our job size */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { fprintf(stderr, "Client ns %s rank %d: PMIx_Get job size failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); fprintf(stderr, "Client %s:%d job size %d\n", myproc.nspace, myproc.rank, nprocs); /* inform the RM that we are preemptible, and that our checkpoint methods are * "signal" on SIGUSR2 and event on PMIX_JCTRL_CHECKPOINT */ PMIX_INFO_CREATE(info, 2); flag = true; PMIX_INFO_LOAD(&info[0], PMIX_JOB_CTRL_PREEMPTIBLE, (void *) &flag, PMIX_BOOL); /* can't use "load" to load a pmix_data_array_t */ pmix_strncpy(info[1].key, PMIX_JOB_CTRL_CHECKPOINT_METHOD, PMIX_MAX_KEYLEN); info[1].value.type = PMIX_DATA_ARRAY; dptr = (pmix_data_array_t *) malloc(sizeof(pmix_data_array_t)); info[1].value.data.darray = dptr; dptr->type = PMIX_INFO; dptr->size = 2; PMIX_INFO_CREATE(dptr->array, dptr->size); rc = SIGUSR2; iptr = (pmix_info_t *) dptr->array; PMIX_INFO_LOAD(&iptr[0], PMIX_JOB_CTRL_CHECKPOINT_SIGNAL, &rc, PMIX_INT); rc = PMIX_JCTRL_CHECKPOINT; PMIX_INFO_LOAD(&iptr[1], PMIX_JOB_CTRL_CHECKPOINT_EVENT, &rc, PMIX_STATUS); /* since this is informational and not a requested operation, the target parameter * doesn't mean anything and can be ignored */ DEBUG_CONSTRUCT_LOCK(&mylock); if (PMIX_SUCCESS != (rc = PMIx_Job_control_nb(NULL, 0, info, 2, infocbfunc, (void *) &mylock))) { fprintf(stderr, "Client ns %s rank %d: PMIx_Job_control_nb failed: %d\n", myproc.nspace, myproc.rank, rc); goto done; } DEBUG_WAIT_THREAD(&mylock); PMIX_INFO_FREE(info, 2); if (0 != mylock.status) { fprintf(stderr, "Client ns %s rank %d: PMIx_Job_control_nb failed: %d\n", myproc.nspace, myproc.rank, mylock.status); exit(mylock.status); } DEBUG_DESTRUCT_LOCK(&mylock); /* now request that this process be monitored using heartbeats */ PMIX_INFO_CREATE(iptr, 1); PMIX_INFO_LOAD(&iptr[0], PMIX_MONITOR_HEARTBEAT, NULL, PMIX_POINTER); PMIX_INFO_CREATE(info, 3); PMIX_INFO_LOAD(&info[0], PMIX_MONITOR_ID, "MONITOR1", PMIX_STRING); n = 5; // require a heartbeat every 5 seconds PMIX_INFO_LOAD(&info[1], PMIX_MONITOR_HEARTBEAT_TIME, &n, PMIX_UINT32); n = 2; // two heartbeats can be missed before declaring us "stalled" PMIX_INFO_LOAD(&info[2], PMIX_MONITOR_HEARTBEAT_DROPS, &n, PMIX_UINT32); /* make the request */ DEBUG_CONSTRUCT_LOCK(&mylock); if (PMIX_SUCCESS != (rc = PMIx_Process_monitor_nb(iptr, PMIX_MONITOR_HEARTBEAT_ALERT, info, 3, infocbfunc, (void *) &mylock))) { fprintf(stderr, "Client ns %s rank %d: PMIx_Process_monitor_nb failed: %d\n", myproc.nspace, myproc.rank, rc); goto done; } DEBUG_WAIT_THREAD(&mylock); PMIX_INFO_FREE(iptr, 1); PMIX_INFO_FREE(info, 3); if (0 != mylock.status) { fprintf(stderr, "Client ns %s rank %d: PMIx_Process_monitor_nb failed: %d\n", myproc.nspace, myproc.rank, mylock.status); exit(mylock.status); } DEBUG_DESTRUCT_LOCK(&mylock); /* send a heartbeat */ PMIx_Heartbeat(); /* call fence to synchronize with our peers - no need to * collect any info as we didn't "put" anything */ PMIX_INFO_CREATE(info, 1); flag = false; PMIX_INFO_LOAD(info, PMIX_COLLECT_DATA, &flag, PMIX_BOOL); if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, info, 1))) { fprintf(stderr, "Client ns %s rank %d: PMIx_Fence failed: %d\n", myproc.nspace, myproc.rank, rc); goto done; } PMIX_INFO_FREE(info, 1); done: /* finalize us */ fprintf(stderr, "Client ns %s rank %d: Finalizing\n", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (0); } pmix-6.1.1~rc2/test/simple/Makefile.am0000664000175000017500000001331215203536752020001 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2006-2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_builddir)/src/include -I$(top_builddir)/include -I$(top_builddir)/include/pmix # we do NOT want picky compilers down here headers = simptest.h noinst_PROGRAMS = simptest simpclient simppub simpdyn simpft simpdmodex \ test_pmix simptool simpdie simptimeout \ gwtest gwclient stability quietclient simpjctrl simpio simpsched \ simpcoord simpcycle doubleget simpfabric get_put_example simpvni \ hybrid simpqual simpdist legacy refresh simptest_SOURCES = $(headers) \ simptest.c simptest_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simptest_LDADD = \ $(top_builddir)/src/libpmix.la simpclient_SOURCES = $(headers) \ simpclient.c simpclient_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpclient_LDADD = \ $(top_builddir)/src/libpmix.la simppub_SOURCES = $(headers) \ simppub.c simppub_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simppub_LDADD = \ $(top_builddir)/src/libpmix.la simpdmodex_SOURCES = $(headers) \ simpdmodex.c simpdmodex_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpdmodex_LDADD = \ $(top_builddir)/src/libpmix.la simpft_SOURCES = $(headers) \ simpft.c simpft_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpft_LDADD = \ $(top_builddir)/src/libpmix.la simpdyn_SOURCES = $(headers) \ simpdyn.c simpdyn_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpdyn_LDADD = \ $(top_builddir)/src/libpmix.la test_pmix_SOURCES = $(headers) \ test_pmix.c test_pmix_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) test_pmix_LDADD = \ $(top_builddir)/src/libpmix.la simptool_SOURCES = $(headers) \ simptool.c simptool_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simptool_LDADD = \ $(top_builddir)/src/libpmix.la simpdie_SOURCES = $(headers) \ simpdie.c simpdie_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpdie_LDADD = \ $(top_builddir)/src/libpmix.la simptimeout_SOURCES = $(headers) \ simptimeout.c simptimeout_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simptimeout_LDADD = \ $(top_builddir)/src/libpmix.la gwtest_SOURCES = $(headers) \ gwtest.c gwtest_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) gwtest_LDADD = \ $(top_builddir)/src/libpmix.la gwclient_SOURCES = $(headers) \ gwclient.c gwclient_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) gwclient_LDADD = \ $(top_builddir)/src/libpmix.la stability_SOURCES = $(headers) \ stability.c stability_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) stability_LDADD = \ $(top_builddir)/src/libpmix.la quietclient_SOURCES = $(headers) \ quietclient.c quietclient_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) quietclient_LDADD = \ $(top_builddir)/src/libpmix.la simpjctrl_SOURCES = $(headers) \ simpjctrl.c simpjctrl_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpjctrl_LDADD = \ $(top_builddir)/src/libpmix.la simpio_SOURCES = $(headers) \ simpio.c simpio_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpio_LDADD = \ $(top_builddir)/src/libpmix.la simpsched_SOURCES = $(headers) \ simpsched.c simpsched_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpsched_LDADD = \ $(top_builddir)/src/libpmix.la simpcoord_SOURCES = $(headers) \ simpcoord.c simpcoord_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpcoord_LDADD = \ $(top_builddir)/src/libpmix.la simpcycle_SOURCES = $(headers) \ simpcycle.c simpcycle_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpcycle_LDADD = \ $(top_builddir)/src/libpmix.la doubleget_SOURCES = $(headers) \ doubleget.c doubleget_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) doubleget_LDADD = \ $(top_builddir)/src/libpmix.la simpfabric_SOURCES = $(headers) \ simpfabric.c simpfabric_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpfabric_LDADD = \ $(top_builddir)/src/libpmix.la get_put_example_SOURCES = $(headers) \ get_put_example.c get_put_example_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) get_put_example_LDADD = \ $(top_builddir)/src/libpmix.la simpvni_SOURCES = $(headers) \ simpvni.c simpvni_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpvni_LDADD = \ $(top_builddir)/src/libpmix.la hybrid_SOURCES = $(headers) \ hybrid.c hybrid_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) hybrid_LDADD = \ $(top_builddir)/src/libpmix.la simpqual_SOURCES = $(headers) \ simpqual.c simpqual_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpqual_LDADD = \ $(top_builddir)/src/libpmix.la simpdist_SOURCES = $(headers) \ simpdist.c simpdist_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) simpdist_LDADD = \ $(top_builddir)/src/libpmix.la legacy_SOURCES = $(headers) \ legacy.c legacy_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) legacy_LDADD = \ $(top_builddir)/src/libpmix.la refresh_SOURCES = $(headers) \ refresh.c refresh_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) refresh_LDADD = \ $(top_builddir)/src/libpmix.la pmix-6.1.1~rc2/test/simple/simpcoord.c0000664000175000017500000001611115203536752020110 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * Copyright (c) 2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" static pmix_proc_t myproc; int main(int argc, char **argv) { int rc; pmix_value_t value; pmix_value_t *val = &value; char *tmp; pmix_proc_t proc; uint32_t nprocs, n; size_t ninfo, m; pmix_coord_t *coords; char *hostname; pmix_byte_object_t *bptr; PMIX_HIDE_UNUSED_PARAMS(argc, argv); if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank); /* test something */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "Client %s:%d job size %d", myproc.nspace, myproc.rank, nprocs); /* get our assumed hostname */ if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_HOSTNAME, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get hostname failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } hostname = strdup(val->data.string); PMIX_VALUE_RELEASE(val); pmix_output(0, "Client %s:%d hostname %s", myproc.nspace, myproc.rank, hostname); /* get our assigned fabric endpts */ if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_FABRIC_ENDPT, NULL, 0, &val))) { pmix_output(0, "Client ns %s rank %d: PMIx_Get fabric endpt failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto nextstep; } pmix_output(0, "Client %s:%d was assigned %lu endpts", myproc.nspace, myproc.rank, (unsigned long) val->data.darray->size); bptr = (pmix_byte_object_t *) val->data.darray->array; ninfo = val->data.darray->size; /* print them out for diagnostics - someday we can figure * out an automated way of testing the answer. We know that * the simptest pnet component returns strings */ { char **foo = NULL; for (n = 0; n < ninfo; n++) { PMIx_Argv_append_nosize(&foo, bptr[0].bytes); } tmp = PMIx_Argv_join(foo, ','); PMIx_Argv_free(foo); pmix_output(0, "Rank %u[%s]: ASSIGNED ENDPTS: %s", myproc.rank, hostname, tmp); free(tmp); } nextstep: /* get our assigned fabric coordinates */ if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_FABRIC_COORDINATES, NULL, 0, &val)) || NULL == val) { pmix_output(0, "Client ns %s rank %d: PMIx_Get fabric coordinate failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); goto done; } if (PMIX_DATA_ARRAY == val->type) { coords = (pmix_coord_t *) val->data.darray->array; ninfo = val->data.darray->size; /* print them out for diagnostics - someday we can figure * out an automated way of testing the answer */ for (m = 0; m < ninfo; m++) { char **foo = NULL; char *view; for (n = 0; n < coords[m].dims; n++) { if (0 > asprintf(&tmp, "%d", coords[m].coord[n])) { errno = ENOMEM; abort(); } PMIx_Argv_append_nosize(&foo, tmp); free(tmp); } tmp = PMIx_Argv_join(foo, ','); PMIx_Argv_free(foo); if (PMIX_COORD_LOGICAL_VIEW == coords[m].view) { view = "LOGICAL"; } else { view = "PHYSICAL"; } pmix_output(0, "Rank %u[%s]: COORD[%d] VIEW %s: %s", myproc.rank, hostname, (int) m, view, tmp); free(tmp); } } else if (PMIX_COORD == val->type) { char **foo = NULL; char *view; for (n = 0; n < val->data.coord->dims; n++) { if (0 > asprintf(&tmp, "%d", val->data.coord->coord[n])) { errno = ENOMEM; abort(); } PMIx_Argv_append_nosize(&foo, tmp); free(tmp); } tmp = PMIx_Argv_join(foo, ','); PMIx_Argv_free(foo); if (PMIX_COORD_LOGICAL_VIEW == val->data.coord->view) { view = "LOGICAL"; } else { view = "PHYSICAL"; } pmix_output(0, "Rank %u[%s]: COORD VIEW %s DIMS %lu: %s", myproc.rank, hostname, view, val->data.coord->dims, tmp); free(tmp); } else { pmix_output(0, "Client ns %s rank %d: PMIx_Get fabric coordinate returned wrong type: %s", myproc.nspace, myproc.rank, PMIx_Data_type_string(val->type)); } done: /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (rc); } pmix-6.1.1~rc2/test/simple/simpio.c0000664000175000017500000001063115203536752017412 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" #define MAXCNT 1 static volatile bool completed = false; static pmix_proc_t myproc; static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, source, info, ninfo, results, nresults); pmix_output(0, "Client %s:%d NOTIFIED with status %s", myproc.nspace, myproc.rank, PMIx_Error_string(status)); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata); } completed = true; } static void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata) { volatile bool *active = (volatile bool *) cbdata; pmix_output(0, "Client: ERRHANDLER REGISTRATION CALLBACK CALLED WITH STATUS %d, ref=%lu", status, (unsigned long) errhandler_ref); *active = false; } #define SIMPIO_MSG_MAX 8192 int main(int argc, char **argv) { pmix_status_t rc; volatile bool active; int msgsize; char msg[SIMPIO_MSG_MAX]; pmix_proc_t proc; int cnt = 0; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* init us */ if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank); /* register our errhandler */ active = true; PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, errhandler_reg_callbk, (void *) &active); while (active) { usleep(10); } /* if we are rank=0, read our stdin */ if (0 == myproc.rank) { while (0 < (msgsize = read(0, msg, SIMPIO_MSG_MAX))) { cnt += msgsize; fprintf(stderr, "Rank %d: read %d bytes\n", myproc.rank, cnt); } } /* call fence to sync */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Client ns %s rank %d PMIx_Fence failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (rc); } pmix-6.1.1~rc2/test/simple/simpdmodex.c0000664000175000017500000002713115203536752020266 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * Copyright (c) 2024 Triad National Security, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/util/pmix_argv.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" static uint32_t nprocs; static pmix_proc_t myproc; static uint32_t getcount = 0; static int msgnum = 0; #define PMIX_WAIT_FOR_COMPLETION(a) \ do { \ while ((a)) { \ usleep(10); \ } \ } while (0) static void opcbfunc(pmix_status_t status, void *cbdata) { bool *active = (bool *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); pmix_output(0, "Rank %d[msg=%d]: completed fence_nb", myproc.rank, msgnum); *active = false; } static void valcbfunc(pmix_status_t status, pmix_value_t *val, void *cbdata) { char *key = (char *) cbdata; if (PMIX_SUCCESS == status) { if (NULL != strstr(key, "local")) { if (PMIX_UINT64 != val->type) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Get_nb Key %s returned wrong type: %d", myproc.rank, msgnum, key, val->type); ++msgnum; goto done; } if (1234 != val->data.uint64) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Get_nb Key %s returned wrong value: %d", myproc.rank, msgnum, key, (int) val->data.uint64); ++msgnum; goto done; } } else if (NULL != strstr(key, "remote")) { if (PMIX_STRING != val->type) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Get_nb Key %s returned wrong type: %d", myproc.rank, msgnum, key, val->type); ++msgnum; goto done; } if (0 != strcmp(val->data.string, "1234")) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Get_nb Key %s returned wrong value: %s", myproc.rank, msgnum, key, val->data.string); ++msgnum; goto done; } } else { pmix_output(0, "Rank %d[msg=%d]: PMIx_Get_nb returned wrong key: %s", myproc.rank, msgnum, key); ++msgnum; goto done; } pmix_output(0, "Rank %d[msg=%d]: PMIx_Get_nb Key %s returned correctly", myproc.rank, msgnum, key); } else { pmix_output(0, "Rank %d[msg=%d]: PMIx_Get_nb Key %s failed: %s", myproc.rank, msgnum, key, PMIx_Error_string(status)); ++msgnum; } done: free(key); getcount++; } int main(int argc, char **argv) { int rc, i; pmix_value_t value; pmix_value_t *val = &value; char *tmp; pmix_proc_t proc; uint32_t n, num_gets, k, nlocal, sleeptime; bool active; bool dofence = true; bool local, all_local; char **peers; pmix_rank_t *locals = NULL; PMIX_HIDE_UNUSED_PARAMS(argc, argv); pmix_info_t timeout, *iptr; size_t ninfo; dofence = false; sleeptime = 2; iptr = NULL; ninfo = 0; for (i=1; i < argc; i++) { if (0 == strcmp(argv[i], "-s") || 0 == strcmp(argv[i], "--sleep")) { if (NULL == argv[i+1]) { fprintf(stderr, "Error: %s requires an integer argument\n", argv[i]); exit(1); } sleeptime = strtoul(argv[i+1], NULL, 10); } else if (0 == strcmp(argv[i], "-f") || 0 == strcmp(argv[i], "--fence")) { dofence = true; } else if (0 == strcmp(argv[i], "-t") || 0 == strcmp(argv[i], "--timeout")) { if (NULL == argv[i+1]) { fprintf(stderr, "Error: %s requires an integer argument\n", argv[i]); exit(1); } rc = strtoul(argv[i+1], NULL, 10); PMIX_INFO_LOAD(&timeout, PMIX_TIMEOUT, &rc, PMIX_INT); iptr = &timeout; ninfo = 1; } } /* init us */ if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "Rank %d: PMIx_Init failed: %d", myproc.rank, rc); exit(1); } pmix_output(0, "Rank %d[msg=%d]: Running", myproc.rank, msgnum); ++msgnum; /* get our job size */ pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_JOB_SIZE, NULL, 0, &val))) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Get job size failed: %s", myproc.rank, msgnum, PMIx_Error_string(rc)); ++msgnum; goto done; } nprocs = val->data.uint32; PMIX_VALUE_RELEASE(val); pmix_output(0, "Rank %d[msg=%d]: job size %d", myproc.rank, msgnum, nprocs); ++msgnum; /* put a few values */ if (0 > asprintf(&tmp, "%s-%d-internal", myproc.nspace, myproc.rank)) { errno = ENOMEM; abort(); } value.type = PMIX_UINT32; value.data.uint32 = 1234; if (PMIX_SUCCESS != (rc = PMIx_Store_internal(&myproc, tmp, &value))) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Store_internal failed: %d", myproc.rank, msgnum, rc); ++msgnum; goto done; } if (0 > asprintf(&tmp, "%s-%d-local", myproc.nspace, myproc.rank)) { errno = ENOMEM; abort(); } value.type = PMIX_UINT64; value.data.uint64 = 1234; if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_LOCAL, tmp, &value))) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Put internal failed: %d", myproc.rank, msgnum, rc); ++msgnum; goto done; } if (0 > asprintf(&tmp, "%s-%d-remote", myproc.nspace, myproc.rank)) { errno = ENOMEM; abort(); } value.type = PMIX_STRING; value.data.string = "1234"; if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_GLOBAL, tmp, &value))) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Put internal failed: %d", myproc.rank, msgnum, rc); ++msgnum; goto done; } /* introduce a delay by one rank so we can check what happens * if a "get" is received prior to data being provided */ if (0 == myproc.rank) { sleep(sleeptime); pmix_output(0, "Rank 0[msg=%d]: WOKE UP", msgnum); ++msgnum; } /* commit the data to the server */ if (PMIX_SUCCESS != (rc = PMIx_Commit())) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Commit failed: %d", myproc.rank, msgnum, rc); goto done; ++msgnum; } if (dofence) { /* call fence_nb, but don't return any data */ PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; active = true; if (PMIX_SUCCESS != (rc = PMIx_Fence_nb(&proc, 1, NULL, 0, opcbfunc, &active))) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Fence failed: %d", myproc.rank, msgnum, rc); ++msgnum; goto done; } } /* get a list of our local peers */ if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_LOCAL_PEERS, NULL, 0, &val))) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Get local peers failed: %s", myproc.rank, msgnum, PMIx_Error_string(rc)); ++msgnum; goto done; } /* split the returned string to get the rank of each local peer */ peers = PMIx_Argv_split(val->data.string, ','); PMIX_VALUE_RELEASE(val); nlocal = PMIx_Argv_count(peers); if (nprocs == nlocal) { all_local = true; } else { all_local = false; locals = (pmix_rank_t *) malloc(PMIx_Argv_count(peers) * sizeof(pmix_rank_t)); for (n = 0; NULL != peers[n]; n++) { locals[n] = strtoul(peers[n], NULL, 10); } } PMIx_Argv_free(peers); /* get the committed data - ask for someone who doesn't exist as well */ num_gets = 0; for (n = 0; n < nprocs; n++) { if (all_local) { local = true; } else { local = false; /* see if this proc is local to us */ for (k = 0; k < nlocal; k++) { if (proc.rank == locals[k]) { local = true; break; } } } if (local) { if (0 > asprintf(&tmp, "%s-%d-local", myproc.nspace, n)) { errno = ENOMEM; abort(); } pmix_output(0, "Rank %u[msg=%d]: retrieving %s from local proc %u", myproc.rank, msgnum, tmp, n); ++msgnum; proc.rank = n; if (PMIX_SUCCESS != (rc = PMIx_Get_nb(&proc, tmp, iptr, ninfo, valcbfunc, tmp))) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Get %s failed: %d", myproc.rank, msgnum, tmp, rc); ++msgnum; goto done; } ++num_gets; } else { if (0 > asprintf(&tmp, "%s-%d-remote", myproc.nspace, n)) { errno = ENOMEM; abort(); } pmix_output(0, "Rank %u[msg=%d]: retrieving %s from remote proc %u", myproc.rank, msgnum, tmp, n); if (PMIX_SUCCESS != (rc = PMIx_Get_nb(&proc, tmp, iptr, ninfo, valcbfunc, tmp))) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Get %s failed: %d", myproc.rank, msgnum, tmp, rc); ++msgnum; goto done; } ++num_gets; } } if (dofence) { /* wait for the first fence to finish */ PMIX_WAIT_FOR_COMPLETION(active); } /* wait for all my "get" calls to complete */ while (getcount < num_gets) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } /* call fence again so everyone waits before leaving */ proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) { pmix_output(0, "Rank %d[msg=%d]: PMIx_Fence failed: %d", myproc.rank, msgnum, rc); ++msgnum; goto done; } done: /* finalize us */ pmix_output(0, "Rank %d[msg=%d]: Finalizing", myproc.rank, msgnum); ++msgnum; if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Rank %d[msg=%d]:PMIx_Finalize failed: %d\n", myproc.rank, msgnum, rc); } else { fprintf(stderr, "Rank %d[msg=%d]: PMIx_Finalize successfully completed\n", myproc.rank, msgnum); } fflush(stderr); return (0); } pmix-6.1.1~rc2/test/simple/gwclient.c0000664000175000017500000000746415203536752017740 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" static pmix_proc_t myproc; int main(int argc, char **argv) { pmix_status_t rc; pmix_value_t value; pmix_value_t *val = &value; uint64_t seckey[2]; pmix_proc_t proc; pmix_info_t *info; size_t n, ninfo; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* init us */ if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, NULL, 0))) { pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "GWClient ns %s rank %d: Running", myproc.nspace, myproc.rank); /* look for network data */ memset(&proc, 0, sizeof(pmix_proc_t)); pmix_strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, "my.net.key", NULL, 0, &val)) || PMIX_DATA_ARRAY != val->type || NULL == val->data.darray || NULL == val->data.darray->array) { pmix_output(0, "Client ns %s rank %d: PMIx_Get my.net.key failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); exit(rc); } /* the returned value has all the network allocation info in a * pmix_data_array_t */ info = (pmix_info_t *) val->data.darray->array; ninfo = val->data.darray->size; pmix_output(0, "Client ns %s rank %d: got network assignment:", myproc.nspace, myproc.rank); for (n = 0; n < ninfo; n++) { if (PMIX_STRING == info[n].value.type) { pmix_output(0, "\tKey: %s Value: %s", info[n].key, info[n].value.data.string); } else if (PMIX_BYTE_OBJECT == info[n].value.type) { memcpy(seckey, info[n].value.data.bo.bytes, info[n].value.data.bo.size); pmix_output(0, "\tKey: %s sec key: %ld.%ld", info[n].key, (long int) seckey[0], (long int) seckey[1]); } } PMIX_VALUE_RELEASE(val); /* finalize us */ pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %s\n", myproc.nspace, myproc.rank, PMIx_Error_string(rc)); } else { fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank); } fflush(stderr); return (rc); } pmix-6.1.1~rc2/test/simple/makedata.pl0000775000175000017500000000212715203536752020056 0ustar alastairalastair#!/usr/bin/env perl # Make a simple data file of a argv[0]-specified size (understand "k", # "m", and "g" suffixes) of a repeating pattern. use strict; my $size_arg = $ARGV[0]; $size_arg =~ m/^(\d+)/; my $size = $1; $size_arg =~ m/([mkg])$/i; my $size_unit = lc($1); if ($size_unit eq "k") { $size *= 1024; } elsif ($size_unit eq "m") { $size *= 1048576; } elsif ($size_unit eq "g") { $size *= 1073741824; } print "Generating size $size\n"; my $file = "data-" . lc($size_arg); unlink($file); my $line = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+=-;"; my $line_len = length($line); $line .= $line; open(FILE, ">$file") || die "Can't open file $file"; my $count = 0; my $line_count = 0; while ($count < $size) { my $offset = $line_count % $line_len; my $num_to_print = ($size - $count < $line_len) ? $size - $count : $line_len; if ($num_to_print > 0) { my $printable = substr($line, $offset, $num_to_print - 1); print FILE $printable . "\n"; $count += $num_to_print; } ++$line_count; } close(FILE); exit(0); pmix-6.1.1~rc2/test/simple/simpvni.c0000664000175000017500000001022015203536752017571 0ustar alastairalastair#include #include #include #include #include #include #include #include static void hide_unused_params(int x, ...) { va_list ap; (void)x; va_start(ap, x); va_end(ap); } typedef struct { pthread_mutex_t mutex; pthread_cond_t cond; volatile bool active; pmix_status_t status; } mylock_t; typedef struct { mylock_t lock; pmix_info_t *info; size_t ninfo; } myxfer_t; #define DEBUG_CONSTRUCT_LOCK(l) \ do { \ pthread_mutex_init(&(l)->mutex, NULL); \ pthread_cond_init(&(l)->cond, NULL); \ (l)->active = true; \ (l)->status = PMIX_SUCCESS; \ } while (0) #define DEBUG_DESTRUCT_LOCK(l) \ do { \ pthread_mutex_destroy(&(l)->mutex); \ pthread_cond_destroy(&(l)->cond); \ } while (0) #define DEBUG_WAIT_THREAD(lck) \ do { \ pthread_mutex_lock(&(lck)->mutex); \ while ((lck)->active) { \ pthread_cond_wait(&(lck)->cond, &(lck)->mutex); \ } \ pthread_mutex_unlock(&(lck)->mutex); \ } while (0) #define DEBUG_WAKEUP_THREAD(lck) \ do { \ pthread_mutex_lock(&(lck)->mutex); \ (lck)->active = false; \ pthread_cond_broadcast(&(lck)->cond); \ pthread_mutex_unlock(&(lck)->mutex); \ } while (0) static void setup_cbfunc(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *provided_cbdata, pmix_op_cbfunc_t cbfunc, void *cbdata) { myxfer_t *x = (myxfer_t *) provided_cbdata; size_t n; /* transfer it to the caddy for return to the main thread */ x->lock.status = status; if (0 < ninfo) { PMIX_INFO_CREATE(x->info, ninfo); x->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&x->info[n], &info[n]); } } /* let the library release the data and cleanup from * the operation */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } DEBUG_WAKEUP_THREAD(&x->lock); } int main(int argc, char **argv) { pmix_status_t rc=0; myxfer_t x; pmix_proc_t myproc; pmix_info_t *info; size_t n, ninfo; char *myvni = NULL; hide_unused_params(rc, argc, argv); /* setup the PMIx tool library - don't need to connect * to a PMIx server */ ninfo = 2; PMIX_INFO_CREATE(info, ninfo); n = 0; PMIX_INFO_LOAD(&info[n], PMIX_TOOL_DO_NOT_CONNECT, NULL, PMIX_BOOL); ++n; PMIX_INFO_LOAD(&info[n], PMIX_LAUNCHER, NULL, PMIX_BOOL); if (PMIX_SUCCESS != (rc = PMIx_tool_init(&myproc, info, ninfo))) { fprintf(stderr, "Init failed with error %s\n", PMIx_Error_string(rc)); return rc; } PMIX_INFO_FREE(info, ninfo); /* ask for a security credential */ DEBUG_CONSTRUCT_LOCK(&x.lock); x.info = NULL; x.ninfo = 0; ninfo = 1; PMIX_INFO_CREATE(info, ninfo); n = 0; PMIX_INFO_LOAD(&info[n], PMIX_ALLOC_FABRIC_SEC_KEY, NULL, PMIX_BOOL); rc = PMIx_server_setup_application(myproc.nspace, info, ninfo, setup_cbfunc, &x); if (PMIX_SUCCESS != rc) { /* the thread won't be called back */ PMIX_INFO_FREE(info, ninfo); goto done; } DEBUG_WAIT_THREAD(&x.lock); PMIX_INFO_FREE(info, ninfo); if (PMIX_SUCCESS != x.lock.status) { /* couldn't allocate it */ rc = x.lock.status; goto done; } /* find the VNI in the returned data - shouldn't be anything else */ for (n = 0; n < x.ninfo; n++) { if (PMIX_CHECK_KEY(&x.info[n], PMIX_CREDENTIAL)) { myvni = strdup(x.info[n].value.data.string); break; } } fprintf(stderr, "VNI: %s\n", (NULL == myvni) ? "NULL" : myvni); done: rc = PMIx_tool_finalize(); return rc; } pmix-6.1.1~rc2/test/simple/hybrid.c0000664000175000017500000001460315203536752017376 0ustar alastairalastair#include #include #include static void hide_unused_params(int x, ...) { va_list ap; (void)x; va_start(ap, x); va_end(ap); } // static void model_declared_cb(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { printf("Entered %s\n", __func__); size_t n; hide_unused_params(evhdlr_registration_id, status, source, results, nresults); for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_PROGRAMMING_MODEL) && strcmp(info[n].value.data.string, "MPI") == 0) { /* ignore our own declaration */ break; } else { /* actions to perform when another model registers */ } } if (NULL != cbfunc) { /* tell the event handler that we are only a partial step */ cbfunc(PMIX_EVENT_PARTIAL_ACTION_TAKEN, NULL, 0, NULL, NULL, cbdata); } } // // static void parallel_region_OMP_cb(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { hide_unused_params(evhdlr_registration_id, status, source, info, ninfo, results, nresults); printf("Entered %s\n", __func__); /* do what we need OpenMP to do on entering a parallel region */ if (NULL != cbfunc) { /* tell the event handler that we are only a partial step */ cbfunc(PMIX_EVENT_PARTIAL_ACTION_TAKEN, NULL, 0, NULL, NULL, cbdata); } } // // static void parallel_region_MPI_cb(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { hide_unused_params(evhdlr_registration_id, status, source, info, ninfo, results, nresults); printf("Entered %s\n", __func__); /* do what we need MPI to do on entering a parallel region */ if (NULL != cbfunc) { /* do what we need MPI to do on entering a parallel region */ cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } } // static int openmp_handler(void) { pmix_info_t *info; int rc; printf("Entered %s\n", __func__); // bool is_true = true; pmix_status_t code = PMIX_OPENMP_PARALLEL_ENTERED; PMIX_INFO_CREATE(info, 2); PMIX_INFO_LOAD(&info[0], PMIX_EVENT_HDLR_NAME, "OpenMP-Master", PMIX_STRING); PMIX_INFO_LOAD(&info[1], PMIX_EVENT_HDLR_FIRST, &is_true, PMIX_BOOL); rc = PMIx_Register_event_handler(&code, 1, info, 2, parallel_region_OMP_cb, NULL, NULL); if (rc < 0) fprintf(stderr, "%s: Failed to register event handler for OpenMP region entrance\n", __func__); PMIX_INFO_FREE(info, 2); // printf("Registered OpenMP event handler for OpenMP parallel region entered\n"); return rc; } static int mpi_handler(void) { pmix_info_t *info; int rc; printf("Entered %s\n", __func__); // pmix_status_t code = PMIX_OPENMP_PARALLEL_ENTERED; PMIX_INFO_CREATE(info, 2); PMIX_INFO_LOAD(&info[0], PMIX_EVENT_HDLR_NAME, "MPI-Thread", PMIX_STRING); PMIX_INFO_LOAD(&info[1], PMIX_EVENT_HDLR_AFTER, "OpenMP-Master", PMIX_STRING); rc = PMIx_Register_event_handler(&code, 1, info, 2, parallel_region_MPI_cb, NULL, NULL); if (rc < 0) fprintf(stderr, "%s: Failed to register event handler for OpenMP region entrance\n", __func__); PMIX_INFO_FREE(info, 2); // printf("Registered MPI event handler for OpenMP parallel region entered\n"); return rc; } static void notify_complete(pmix_status_t status, void *cbdata) { volatile bool *flag = (volatile bool *) cbdata; hide_unused_params(status); *flag = true; } int main(int argc, char **argv) { // pmix_proc_t myproc; pmix_info_t *info; volatile bool wearedone = false; hide_unused_params(argc, argv); PMIX_INFO_CREATE(info, 4); PMIX_INFO_LOAD(&info[0], PMIX_PROGRAMMING_MODEL, "MPI", PMIX_STRING); PMIX_INFO_LOAD(&info[1], PMIX_MODEL_LIBRARY_NAME, "FooMPI", PMIX_STRING); PMIX_INFO_LOAD(&info[2], PMIX_MODEL_LIBRARY_VERSION, "1.0.0", PMIX_STRING); PMIX_INFO_LOAD(&info[3], PMIX_THREADING_MODEL, "pthread", PMIX_STRING); pmix_status_t rc = PMIx_Init(&myproc, info, 4); PMIX_INFO_FREE(info, 4); // printf("Registered MPI programming model\n"); printf("Registering event handler for model declaration\n"); // pmix_status_t code = PMIX_MODEL_DECLARED; rc = PMIx_Register_event_handler(&code, 1, NULL, 0, model_declared_cb, NULL, NULL); // if (rc < 0) { fprintf(stderr, "Failed to register event handler for model declaration\n"); goto fin; } printf("Registered event handler for model declaration\n"); openmp_handler(); mpi_handler(); printf("Notifying OpenMP parallel region about to be entered\n"); // PMIX_INFO_CREATE(info, 1); PMIX_INFO_LOAD(&info[0], PMIX_EVENT_NON_DEFAULT, NULL, PMIX_BOOL); rc = PMIx_Notify_event(PMIX_OPENMP_PARALLEL_ENTERED, &myproc, PMIX_RANGE_PROC_LOCAL, info, 1, notify_complete, (void *) &wearedone); if (rc < 0) { fprintf(stderr, "Failed to notify OpenMP region entered\n"); goto fin; } while (!wearedone) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } fprintf(stderr, "Test completed\n"); fin: PMIx_Finalize(NULL, 0); // } pmix-6.1.1~rc2/test/cli_stages.h0000664000175000017500000000440615203536752016746 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef CLI_STAGES_H #define CLI_STAGES_H #include "src/include/pmix_config.h" #include "pmix_server.h" #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/mca/ptl/base/base.h" #include #include #include #include #include #include #include #include #include #include #include "test_common.h" // In correct scenario each client has to sequentially pass all of this stages typedef enum { CLI_UNINIT, CLI_FORKED, CLI_CONNECTED, CLI_FIN, CLI_DISCONN, CLI_TERM, CLI_UNDEF } cli_state_t; typedef struct { pmix_list_t modex; pid_t pid; int sd; pmix_event_t *ev; cli_state_t state; cli_state_t next_state[CLI_TERM + 1]; pmix_rank_t rank; char *ns; int exit_code; bool alive; } cli_info_t; extern cli_info_t *cli_info; extern int cli_info_cnt; extern bool test_abort; extern bool test_complete; int cli_rank(cli_info_t *cli); void cli_init(int nprocs); void cli_connect(cli_info_t *cli, int sd, struct event_base *ebase, event_callback_fn callback); void cli_finalize(cli_info_t *cli); void cli_disconnect(cli_info_t *cli); void cli_terminate(cli_info_t *cli); void cli_cleanup(cli_info_t *cli); void cli_kill_all(void); bool test_terminated(void); void errhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata); void op_callbk(pmix_status_t status, void *cbdata); void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata); #endif // CLI_STAGES_H pmix-6.1.1~rc2/test/test_resolve_peers.c0000664000175000017500000001242015203536752020533 0ustar alastairalastair/* * Copyright (c) 2015-2019 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "test_resolve_peers.h" #include "test_cd.h" #include "src/util/pmix_output.h" static int resolve_nspace(char *nspace, test_params params, char *my_nspace, int my_rank) { int rc; pmix_proc_t *procs; size_t nprocs, nranks, i; pmix_proc_t *ranks; rc = PMIx_Resolve_peers(pmix_globals.hostname, nspace, &procs, &nprocs); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: Resolve peers test failed: rc = %s", my_nspace, my_rank, PMIx_Error_string(rc))); exit(rc); } if (NULL == procs || 0 == nprocs) { TEST_ERROR(("%s:%d: Resolve peers didn't find any process from ns %s at this node\n", my_nspace, my_rank, my_nspace)); exit(PMIX_ERROR); } rc = get_all_ranks_from_namespace(params, nspace, &ranks, &nranks); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: get_all_ranks_from_namespace function failed", my_nspace, my_rank)); PMIX_PROC_FREE(procs, nprocs); exit(rc); } if (nprocs != nranks) { TEST_ERROR( ("%s:%d: Resolve peers returned incorrect result: returned %lu processes, expected %lu", my_nspace, my_rank, nprocs, nranks)); PMIX_PROC_FREE(procs, nprocs); PMIX_PROC_FREE(ranks, nranks); exit(PMIX_ERROR); } for (i = 0; i < nprocs; i++) { if (procs[i].rank != ranks[i].rank) { TEST_ERROR(("%s:%d: Resolve peers returned incorrect result: returned value %s:%d, " "expected rank %d", my_nspace, my_rank, procs[i].nspace, procs[i].rank, ranks[i].rank)); exit(PMIX_ERROR); } } PMIX_PROC_FREE(procs, nprocs); PMIX_PROC_FREE(ranks, nranks); return rc; } int test_resolve_peers(char *my_nspace, int my_rank, test_params params) { int rc, n; int ns_num; char nspace[PMIX_MAX_NSLEN + 1]; pmix_proc_t procs[2]; /* first resolve peers from the own namespace. */ rc = resolve_nspace(my_nspace, params, my_nspace, my_rank); if (PMIX_SUCCESS == rc) { TEST_VERBOSE( ("%s:%d: Resolve peers succeeded for the own namespace\n", my_nspace, my_rank)); } else { TEST_ERROR(("%s:%d: Resolve peers failed for the own namespace\n", my_nspace, my_rank)); exit(rc); } /* then get number of namespaces and try to resolve peers from them. */ ns_num = get_total_ns_number(params); if (0 >= ns_num) { TEST_ERROR(("%s:%d: get_total_ns_number function failed", my_nspace, my_rank)); exit(PMIX_ERROR); } for (n = 0; n < ns_num; n++) { memset(nspace, 0, PMIX_MAX_NSLEN + 1); /* then connect to processes from different namespaces and resolve peers. */ (void) snprintf(nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, n); if (0 == strncmp(my_nspace, nspace, strlen(nspace) + 1)) { continue; } /* add to procs array all processes from own namespace and all processes from this * namespace. Make sure that processes are placed in the same order. */ if (0 < strncmp(nspace, my_nspace, PMIX_MAX_NSLEN)) { pmix_strncpy(procs[0].nspace, nspace, PMIX_MAX_NSLEN); pmix_strncpy(procs[1].nspace, my_nspace, PMIX_MAX_NSLEN); } else { pmix_strncpy(procs[1].nspace, nspace, PMIX_MAX_NSLEN); pmix_strncpy(procs[0].nspace, my_nspace, PMIX_MAX_NSLEN); } procs[0].rank = PMIX_RANK_WILDCARD; procs[1].rank = PMIX_RANK_WILDCARD; /* make a connection between processes from own namespace and processes from this namespace. */ rc = PMIx_Connect(procs, 2, NULL, 0); if (PMIX_SUCCESS == rc) { TEST_VERBOSE(("%s:%d: Connect to %s succeeded.", my_nspace, my_rank, nspace)); } else { TEST_ERROR(("%s:%d: Connect to %s failed.", my_nspace, my_rank, nspace)); exit(rc); } /* then resolve peers from this namespace - earlier versions cannot handle * cross-nspace peer resolution because their test servers don't provide * the info. So check for a marker of either 3.1.5 or above */ if (NULL != getenv("PMIX_VERSION")) { rc = resolve_nspace(nspace, params, my_nspace, my_rank); if (PMIX_SUCCESS == rc) { TEST_VERBOSE( ("%s:%d: Resolve peers succeeded for ns %s\n", my_nspace, my_rank, nspace)); } else { exit(rc); } } /* disconnect from the processes of this namespace. */ rc = PMIx_Disconnect(procs, 2, NULL, 0); if (PMIX_SUCCESS == rc) { TEST_VERBOSE(("%s:%d: Disconnect from %s succeeded.", my_nspace, my_rank, nspace)); } else { TEST_ERROR(("%s:%d: Disconnect from %s failed.", my_nspace, my_rank, nspace)); exit(rc); } } if (PMIX_SUCCESS == rc) { TEST_VERBOSE(("%s:%d: Resolve peers test succeeded.", my_nspace, my_rank)); } return rc; } pmix-6.1.1~rc2/test/sshot/0000775000175000017500000000000015203536752015614 5ustar alastairalastairpmix-6.1.1~rc2/test/sshot/daemon.c0000664000175000017500000000531615203536752017230 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix_server.h" #include "src/include/pmix_globals.h" #include "src/include/pmix_types.h" #include #include #include #include #include #include #include #include #include "src/class/pmix_list.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_printf.h" static pmix_server_module_t mymodule = {0}; int main(int argc, char **argv) { pmix_info_t *info; size_t ninfo; pmix_status_t rc; fprintf(stderr, "PID: %lu Testing version %s\n", (unsigned long) getpid(), PMIx_Get_version()); /* set a known network configuration for the pnet/test component */ putenv("PMIX_MCA_pnet_sshot_scheduler_pipe=./myfifo"); putenv("PMIX_MCA_pnet_sshot_config_file=./mytopo.json"); putenv("PMIX_MCA_pnet=sshot"); ninfo = 1; PMIX_INFO_CREATE(info, ninfo); PMIX_INFO_LOAD(&info[0], PMIX_SERVER_SCHEDULER, NULL, PMIX_BOOL); if (PMIX_SUCCESS != (rc = PMIx_server_init(&mymodule, info, ninfo))) { fprintf(stderr, "Init failed with error %d\n", rc); return rc; } PMIX_INFO_FREE(info, ninfo); /* finalize the server library */ if (PMIX_SUCCESS != (rc = PMIx_server_finalize())) { fprintf(stderr, "Finalize failed with error %d\n", rc); } return rc; } pmix-6.1.1~rc2/test/sshot/server.c0000664000175000017500000000215015203536752017264 0ustar alastairalastair/* * Copyright (c) 2020 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include #include #include #include #include #include #include int main(int argc, char **argv) { int mypipe; int len; char *grps; int rc; /* open a named pipe */ mypipe = open("./myfifo", O_RDONLY | O_CREAT | O_NONBLOCK, S_IRWXG | S_IRWXU); while (1) { rc = read(mypipe, &len, sizeof(int)); if (0 == rc) { continue; } if (0 > rc || sizeof(int) != rc) { /* hit an error */ continue; } if (-1 == len) { /* signal to exit */ break; } grps = (char *) malloc(len); rc = read(mypipe, grps, len); if (0 > rc || len != rc) { /* hit an error */ continue; } fprintf(stderr, "GRPS: %s\n", grps); } unlink("./myfifo"); return 0; } pmix-6.1.1~rc2/test/sshot/generate.c0000664000175000017500000002232315203536752017554 0ustar alastairalastair/* * Copyright (c) 2020 Intel, Inc. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include #include #include #include #include #include #define DEFAULT_NUM_SWITCHES 8 #define DEFAULT_NUM_FABPORTS 10 #define DEFAULT_NUM_EDGEPORTS 10 #define DEFAULT_NUM_NODES 8 #define DEFAULT_NUM_NICS 8 #define DEFAULT_NUM_GROUPS 2 static int iseven(int num) { return !(num & 1); } static int help = 0; typedef struct { int nswitches; int *members; } grptrk_t; int main(int argc, char **argv) { json_t *root, *switches, *fabricports, *edgeports; json_t *sw, *port, *cport, *links; json_t *nodes, *node, *nics; char *s; int idnum = 10; int jnum = 0; int pnum = 0; int n, nn; int nsw, nswitches = DEFAULT_NUM_SWITCHES; int numfabports = DEFAULT_NUM_FABPORTS; int numedgeports = DEFAULT_NUM_EDGEPORTS; int nnics = DEFAULT_NUM_NICS; int nnodes = DEFAULT_NUM_NODES; int ngrps = DEFAULT_NUM_GROUPS; char *tmp; int opt; grptrk_t map[100]; char *outfile = NULL; static struct option myoptions[] = {{"file", required_argument, NULL, 'f'}, {"nswitches", required_argument, NULL, 's'}, {"nfabports", required_argument, NULL, 'p'}, {"nedgeports", required_argument, NULL, 'e'}, {"nnodes", required_argument, NULL, 'c'}, {"nnics", required_argument, NULL, 'n'}, {"ngrps", required_argument, NULL, 'g'}, {"help", no_argument, &help, 1}}; int option_index; /* check for options */ while ((opt = getopt_long(argc, argv, "f:p:e:c:n", myoptions, &option_index)) != -1) { switch (opt) { case 'f': outfile = optarg; break; case 's': nswitches = strtol(optarg, NULL, 10); break; case 'p': numfabports = strtol(optarg, NULL, 10); break; case 'e': numedgeports = strtol(optarg, NULL, 10); break; case 'c': nnodes = strtol(optarg, NULL, 10); break; case 'n': nnics = strtol(optarg, NULL, 10); break; case 'g': ngrps = strtol(optarg, NULL, 10); break; default: fprintf(stderr, "Usage: %s\n Options:\n" " [-f] [output file - will add .json extension]\n" " [-s] [number of switches]\n" " [-g] [number of groups to organize the switches into (<100)\n" " [-p] [number of fabricports per switch]\n" " [-e] [number of edge ports per switch]\n" " [-c] [number of nodes]\n" " [-n] [number of NICs per node]\n", argv[0]); exit(1); } } if (help) { fprintf(stdout, "Usage: %s\n Options:\n" " [-f] [output file - will add .json extension]\n" " [-s] [number of switches]\n" " [-p] [number of fabricports per switch]\n" " [-e] [number of edge ports per switch]\n" " [-c] [number of nodes]\n" " [-n] [number of NICs per node]\n", argv[0]); exit(0); } /* create a JSON object */ root = json_object(); /* we will be defining an array of switches */ switches = json_array(); json_object_set_new(root, "switches", switches); for (n = 0; n < ngrps; n++) { map[n].nswitches = 0; map[n].members = (int *) malloc(nswitches * sizeof(int)); } for (nsw = 0; nsw < nswitches; nsw++) { /* each switch contains an object that starts with its identifiers */ sw = json_object(); (void) asprintf(&tmp, "0x30000c0r21b%d", nsw); json_object_set_new(sw, "IP", json_string(tmp)); free(tmp); nn = nsw % ngrps; json_object_set_new(sw, "grpID", json_integer(nn)); map[nn].members[map[nn].nswitches] = nsw; map[nn].nswitches++; json_object_set_new(sw, "swcNum", json_integer(nsw)); /* each switch contains an array of fabric ports */ fabricports = json_array(); for (n = 0; n < numfabports; n++) { port = json_object(); /* each fabric port has an ID */ (void) asprintf(&tmp, "0x30000c0r21a01%d", idnum); json_object_set_new(port, "id", json_string(tmp)); free(tmp); ++idnum; /* each fabric port has a "meta" object that contains the connection port */ cport = json_object(); (void) asprintf(&tmp, "0x30000c0r21j%dp%d", jnum, pnum); json_object_set_new(cport, "conn_port", json_string(tmp)); json_object_set_new(port, "meta", cport); free(tmp); if (iseven(n)) { pnum = 1; } else { pnum = 0; ++jnum; } /* add the port to the array of fabricports */ json_array_append(fabricports, port); } /* add the fabricports to the switch */ json_object_set_new(sw, "fabricports", fabricports); /* each switch also contains an array of edge ports */ edgeports = json_array(); for (n = 0; n < numedgeports; n++) { port = json_object(); /* each edge port has an ID */ (void) asprintf(&tmp, "0x30000c0r21a01%d", idnum); json_object_set_new(port, "id", json_string(tmp)); free(tmp); ++idnum; /* each edge port has a "meta" object that contains the connection port */ cport = json_object(); (void) asprintf(&tmp, "0x30000c0r21j%dp%d", jnum, pnum); json_object_set_new(cport, "conn_port", json_string(tmp)); json_object_set_new(port, "meta", cport); free(tmp); if (iseven(n)) { pnum = 1; } else { pnum = 0; ++jnum; } /* add the port to the array of edgeports */ json_array_append(edgeports, port); } /* add the edgeports to the switch */ json_object_set_new(sw, "edgeports", edgeports); /* add the switch to the array */ json_array_append(switches, sw); } /* add the nmber of groups */ json_object_set_new(root, "numGroups", json_integer(ngrps)); /* set the max number of switches in a group */ nsw = (nswitches / ngrps) + (nswitches % ngrps); json_object_set_new(root, "maxNumLocalSwitches", json_integer(nsw)); /* define an array of links */ links = json_array(); json_object_set_new(root, "links", links); /* put some arbitrary endpoint info in it */ for (n = 0; n < numfabports; n++) { port = json_object(); (void) asprintf(&tmp, "0x30000c0r21a01%d", idnum); json_object_set_new(port, "endpoint1", json_string(tmp)); free(tmp); ++idnum; (void) asprintf(&tmp, "0x30000c0r21a01%d", idnum); json_object_set_new(port, "endpoint2", json_string(tmp)); free(tmp); ++idnum; /* add the port to the array of links */ json_array_append(links, port); } /* define an array of nodes */ nodes = json_array(); json_object_set_new(root, "nodes", nodes); nsw = 0; for (nn = 0; nn < nnodes; nn++) { /* each node contains an object that starts with its name */ node = json_object(); (void) asprintf(&tmp, "node%03d", nn); json_object_set_new(node, "name", json_string(tmp)); free(tmp); /* each node contains a set of NICs */ nics = json_array(); for (n = 0; n < nnics; n++) { port = json_object(); /* each NIC has an ID */ (void) asprintf(&tmp, "0x30000c0r21a01%d", idnum); json_object_set_new(port, "id", json_string(tmp)); free(tmp); ++idnum; /* define a group for this node */ opt = nn % ngrps; /* and a connection - each NIC needs to point to a * switch in the same group */ nsw = n % map[opt].nswitches; json_object_set_new(port, "switch", json_integer(map[opt].members[nsw])); /* add the port to the NIC array */ json_array_append(nics, port); } /* add the NICs to the node */ json_object_set_new(node, "nics", nics); /* add the node to the array */ json_array_append(nodes, node); } if (NULL == outfile) { s = json_dumps(root, JSON_INDENT(4)); puts(s); } else { (void) asprintf(&tmp, "%s.json", outfile); json_dump_file(root, tmp, JSON_INDENT(4)); free(tmp); } json_decref(root); return 0; } pmix-6.1.1~rc2/test/sshot/Makefile.am0000664000175000017500000000176015203536752017654 0ustar alastairalastair# # Copyright (c) 2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_builddir)/src/include -I$(top_builddir)/include -I$(top_builddir)/include/pmix $(pmix_check_jansson_CPPFLAGS) # we do NOT want picky compilers down here CFLAGS = $(PMIX_CFLAGS_BEFORE_PICKY) if HAVE_JANSSON noinst_PROGRAMS = generate server daemon testcoord generate_SOURCES = \ generate.c generate_LDFLAGS = $(pmix_check_jansson_LDFLAGS) generate_LDADD = -ljansson server_SOURCES = \ server.c server_LDFLAGS = $(pmix_check_jansson_LDFLAGS) server_LDADD = -ljansson daemon_SOURCES = \ daemon.c daemon_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) daemon_LDADD = \ $(top_builddir)/src/libpmix.la testcoord_SOURCES = \ testcoord.c testcoord_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) testcoord_LDADD = \ $(top_builddir)/src/libpmix.la endif pmix-6.1.1~rc2/test/sshot/testcoord.c0000664000175000017500000002311115203536752017764 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2019 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include #include #include #include "src/class/pmix_object.h" #include "src/util/pmix_output.h" #include "src/util/pmix_printf.h" typedef struct { pthread_mutex_t mutex; pthread_cond_t cond; volatile bool active; pmix_status_t status; } mylock_t; #define DEBUG_CONSTRUCT_LOCK(l) \ do { \ pthread_mutex_init(&(l)->mutex, NULL); \ pthread_cond_init(&(l)->cond, NULL); \ (l)->active = true; \ (l)->status = PMIX_SUCCESS; \ } while (0) #define DEBUG_DESTRUCT_LOCK(l) \ do { \ pthread_mutex_destroy(&(l)->mutex); \ pthread_cond_destroy(&(l)->cond); \ } while (0) #define DEBUG_WAIT_THREAD(lck) \ do { \ pthread_mutex_lock(&(lck)->mutex); \ while ((lck)->active) { \ pthread_cond_wait(&(lck)->cond, &(lck)->mutex); \ } \ pthread_mutex_unlock(&(lck)->mutex); \ } while (0) #define DEBUG_WAKEUP_THREAD(lck) \ do { \ pthread_mutex_lock(&(lck)->mutex); \ (lck)->active = false; \ pthread_cond_broadcast(&(lck)->cond); \ pthread_mutex_unlock(&(lck)->mutex); \ } while (0) typedef struct { mylock_t lock; pmix_status_t status; pmix_info_t *info; size_t ninfo; } mycaddy_t; static void local_cbfunc(pmix_status_t status, void *cbdata) { mylock_t *lock = (mylock_t *) cbdata; lock->status = status; DEBUG_WAKEUP_THREAD(lock); } static void setup_cbfunc(pmix_status_t status, pmix_info_t info[], size_t ninfo, void *provided_cbdata, pmix_op_cbfunc_t cbfunc, void *cbdata) { mycaddy_t *mq = (mycaddy_t *) provided_cbdata; size_t n; /* transfer it to the caddy for return to the main thread */ if (0 < ninfo) { PMIX_INFO_CREATE(mq->info, ninfo); mq->ninfo = ninfo; for (n = 0; n < ninfo; n++) { PMIX_INFO_XFER(&mq->info[n], &info[n]); } } /* let the library release the data and cleanup from * the operation */ if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } DEBUG_WAKEUP_THREAD(&mq->lock); } static int help = 0; int main(int argc, char **argv) { pmix_status_t rc; mycaddy_t cd; mylock_t lock; pmix_proc_t proc; int tclass; pmix_value_t *val; pmix_geometry_t *geos; size_t ngeos, n, m; char *tmp; pmix_info_t info[2]; static struct option myoptions[] = {{"num_nodes", required_argument, NULL, 'n'}, {"num_devs", required_argument, NULL, 'd'}, {"ppn", required_argument, NULL, 'p'}, {"help", no_argument, &help, 1}, {0, 0, 0, 0}}; int option_index; int opt; int nnodes = 2; int ndevs = 8; int ppn = 4; while ((opt = getopt_long(argc, argv, "n:d:p:", myoptions, &option_index)) != -1) { switch (opt) { case 'n': nnodes = strtol(optarg, NULL, 10); break; case 'd': ndevs = strtol(optarg, NULL, 10); break; case 'p': ppn = strtol(optarg, NULL, 10); break; default: fprintf(stderr, "Usage: %s\n Options:\n" " [-n] [number of nodes]\n" " [-d] [number of devices/node]\n" " [-p] [number of procs/node]\n", argv[0]); exit(1); } } if (help) { fprintf(stderr, "Usage: %s\n Options:\n" " [-n] [number of nodes]\n" " [-d] [number of devices/node]\n" " [-p] [number of procs/node]\n", argv[0]); exit(0); } pmix_asprintf(&tmp, "PMIX_MCA_pnet_sshot_num_nodes=%d", nnodes); putenv(tmp); pmix_asprintf(&tmp, "PMIX_MCA_pnet_sshot_devs_per_node=%d", ndevs); putenv(tmp); pmix_asprintf(&tmp, "PMIX_MCA_pnet_sshot_ppn=%d", ppn); putenv(tmp); if (PMIX_SUCCESS != (rc = PMIx_server_init(NULL, NULL, 0))) { pmix_output(0, "Server init failed: %s", PMIx_Error_string(rc)); exit(rc); } pmix_output(0, "Server running"); DEBUG_CONSTRUCT_LOCK(&cd.lock); if (PMIX_SUCCESS != (rc = PMIx_server_setup_application("SIMPSCHED", NULL, 0, setup_cbfunc, &cd))) { pmix_output(0, "[%s:%d] PMIx_server_setup_application failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); DEBUG_DESTRUCT_LOCK(&cd.lock); goto done; } DEBUG_WAIT_THREAD(&cd.lock); DEBUG_DESTRUCT_LOCK(&cd.lock); DEBUG_CONSTRUCT_LOCK(&lock); if (PMIX_SUCCESS != (rc = PMIx_server_setup_local_support("SIMPSCHED", cd.info, cd.ninfo, local_cbfunc, &lock))) { pmix_output(0, "[%s:%d] PMIx_server_setup_local_support failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); DEBUG_DESTRUCT_LOCK(&lock); goto done; } DEBUG_WAIT_THREAD(&lock); DEBUG_DESTRUCT_LOCK(&lock); /* check a few things */ PMIX_LOAD_PROCID(&proc, "SIMPSCHED", PMIX_RANK_WILDCARD); rc = PMIx_Get(&proc, "HPE_TRAFFIC_CLASS", NULL, 0, &val); if (PMIX_SUCCESS != rc) { pmix_output(0, "[%s:%d] Get of traffic class failed: %s", __FILE__, __LINE__, PMIx_Error_string(rc)); goto done; } rc = PMIx_Value_get_number(val, &tclass, PMIX_INT); if (PMIX_SUCCESS != rc) { pmix_output(0, "[%s:%d] Get of traffic class returned non-number", __FILE__, __LINE__); goto done; } pmix_output(0, "[%s:%d] Got traffic class %d", __FILE__, __LINE__, tclass); PMIX_VALUE_RELEASE(val); /* the test nodes are "nid000000" and "nid000001" */ PMIX_INFO_LOAD(&info[0], PMIX_NODE_INFO, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[1], PMIX_HOSTNAME, "nid000000", PMIX_STRING); if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_FABRIC_COORDINATES, info, 2, &val)) || NULL == val) { pmix_output(0, "Client ns %s rank %d: PMIx_Get fabric coordinate failed: %s", proc.nspace, proc.rank, PMIx_Error_string(rc)); goto done; } if (PMIX_DATA_ARRAY == val->type) { geos = (pmix_geometry_t *) val->data.darray->array; ngeos = val->data.darray->size; /* print them out for diagnostics - someday we can figure * out an automated way of testing the answer */ for (m = 0; m < ngeos; m++) { char **foo = NULL; char *view; pmix_output(0, "Device[%d]: %s Osname: %s", (int) m, geos[m].uuid, geos[m].osname); for (n = 0; n < geos[m].coordinates[0].dims; n++) { asprintf(&tmp, "%d", geos[m].coordinates[0].coord[n]); PMIx_Argv_append_nosize(&foo, tmp); free(tmp); } tmp = PMIx_Argv_join(foo, ','); PMIx_Argv_free(foo); if (PMIX_COORD_LOGICAL_VIEW == geos[m].coordinates[0].view) { view = "LOGICAL"; } else { view = "PHYSICAL"; } pmix_output(0, "\tCOORD VIEW %s: %s", view, tmp); free(tmp); } } else { pmix_output(0, "Client ns %s rank %d: PMIx_Get fabric coordinate returned wrong type: %s", proc.nspace, proc.rank, PMIx_Data_type_string(val->type)); } done: /* finalize us */ pmix_output(0, "Server finalizing"); if (PMIX_SUCCESS != (rc = PMIx_server_finalize())) { fprintf(stderr, "Server finalize failed: %s\n", PMIx_Error_string(rc)); } else { fprintf(stderr, "Server finalize successfully completed\n"); } fflush(stderr); return (rc); } pmix-6.1.1~rc2/test/group/0000775000175000017500000000000015203536752015610 5ustar alastairalastairpmix-6.1.1~rc2/test/group/run.sh0000775000175000017500000000024015203536752016747 0ustar alastairalastair#/bin/bash echo "Test group" prterun -n 4 ../../examples/group >& /dev/null echo "Test group_lcl_cid" prterun -n 4 ../../examples/group_lcl_cid >& /dev/null pmix-6.1.1~rc2/test/pmix_client_otheruser.sh0000775000175000017500000000102115203536752021420 0ustar alastairalastair#!/bin/bash OTHERUSER=dummy # To test sec:native we run client as a different user e.g. # # ./pmix_test -e ./pmix_client_otheruser.sh # # Prerequisites: # - ensure directories leading up to source tree are o+x # - add dummy user and set OTHERUSER to its name # - give yourself passwordless sudo capability to that user # # The test should fail with message similar to # PMIX ERROR: INVALID-CREDENTIAL in file # ../src/server/pmix_server_listener.c at line 524 # sudo --user $OTHERUSER --preserve-env ./pmix_client $* pmix-6.1.1~rc2/test/run_tests00.pl.in0000777000175000017500000000000015203536752022567 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/test_internal.h0000664000175000017500000000063315203536752017502 0ustar alastairalastair/* * Copyright (c) 2017 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2020 Intel, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "test_common.h" int test_internal(char *my_nspace, pmix_rank_t my_rank, test_params params); pmix-6.1.1~rc2/test/run_tests15.pl.in0000777000175000017500000000000015203536752022575 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/run_tests02.pl.in0000777000175000017500000000000015203536752022571 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/test_spawn.c0000664000175000017500000000451615203536752017015 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "test_spawn.h" #include typedef struct { int in_progress; pmix_nspace_t nspace; } spawn_cbdata; static void spawn_cb(pmix_status_t status, char nspace[], void *cbdata) { spawn_cbdata *cb = (spawn_cbdata *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); PMIX_LOAD_NSPACE(cb->nspace, nspace); cb->in_progress = 0; } static int test_spawn_common(char *my_nspace, int my_rank, int blocking) { int rc; pmix_app_t *apps; size_t napps; pmix_nspace_t nspace; PMIX_HIDE_UNUSED_PARAMS(my_nspace, my_rank); memset(nspace, 0, PMIX_MAX_NSLEN + 1); napps = 1; PMIX_APP_CREATE(apps, napps); apps[0].cmd = strdup("foo"); // need SOMETHING we intend to spawn! if (blocking) { if (PMIX_SUCCESS != (rc = PMIx_Spawn(NULL, 0, apps, napps, nspace))) { PMIX_APP_FREE(apps, napps); exit(rc); } } else { spawn_cbdata cbdata; cbdata.in_progress = 1; memset(cbdata.nspace, 0, PMIX_MAX_NSLEN + 1); rc = PMIx_Spawn_nb(NULL, 0, apps, napps, spawn_cb, (void *) &cbdata); if (PMIX_SUCCESS != rc) { PMIX_APP_FREE(apps, napps); exit(rc); } PMIX_WAIT_FOR_COMPLETION(cbdata.in_progress); PMIX_LOAD_NSPACE(nspace, cbdata.nspace); } PMIX_APP_FREE(apps, napps); if (!PMIX_CHECK_NSPACE(nspace, "foobar")) { exit(PMIX_ERROR); } return rc; } int test_spawn(char *my_nspace, int my_rank) { int rc; rc = test_spawn_common(my_nspace, my_rank, 1); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: Spawn blocking test failed.", my_nspace, my_rank)); exit(rc); } TEST_VERBOSE(("%s:%d: Spawn blocking test succeeded.", my_nspace, my_rank)); rc = test_spawn_common(my_nspace, my_rank, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: Spawn non-blocking test failed.", my_nspace, my_rank)); exit(rc); } TEST_VERBOSE(("%s:%d: Spawn non-blocking test succeeded.", my_nspace, my_rank)); return PMIX_SUCCESS; } pmix-6.1.1~rc2/test/run_tests08.pl.in0000777000175000017500000000000015203536752022577 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/run_tests13.pl.in0000777000175000017500000000000015203536752022573 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/test_internal.c0000664000175000017500000000501315203536752017472 0ustar alastairalastair/* * Copyright (c) 2017 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2017-2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "test_internal.h" static void release_cb(pmix_status_t status, void *cbdata) { int *ptr = (int *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); *ptr = 0; } static void get_cb(pmix_status_t status, pmix_value_t *kv, void *cbdata) { get_cbdata *cb = (get_cbdata *) cbdata; if (PMIX_SUCCESS == status) { PMIx_Value_xfer(cb->kv, kv); } cb->in_progress = 0; cb->status = status; } int test_internal(char *my_nspace, pmix_rank_t my_rank, test_params params) { int idx; char sval[PMIX_MAX_NSLEN]; char key[PMIX_MAX_KEYLEN]; pmix_value_t value; pmix_proc_t proc; pmix_status_t rc; PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, my_nspace, PMIX_MAX_NSLEN); proc.rank = my_rank; for (idx = 0; idx < params.test_internal; idx++) { memset(sval, 0, PMIX_MAX_NSLEN); snprintf(sval, PMIX_MAX_NSLEN, "test_internal:%s:%d:%d", my_nspace, my_rank, idx); SET_KEY(key, 0, idx, 1); value.type = PMIX_STRING; value.data.string = sval; if (PMIX_SUCCESS != (rc = PMIx_Store_internal(&proc, key, &value))) { TEST_ERROR(("%s:%d: PMIx_Store_internal failed: %d", my_nspace, my_rank, rc)); PMIX_PROC_DESTRUCT(&proc); exit(rc); } } /* Submit the data */ if (PMIX_SUCCESS != (rc = PMIx_Commit())) { TEST_ERROR(("%s:%d: PMIx_Commit failed: %d", my_nspace, my_rank, rc)); PMIX_PROC_DESTRUCT(&proc); exit(rc); } proc.rank = PMIX_RANK_WILDCARD; FENCE(1, 1, (&proc), 1); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Fence failed: %d", my_nspace, my_rank, rc)); PMIX_PROC_DESTRUCT(&proc); exit(rc); } for (idx = 0; idx < params.test_internal; idx++) { memset(sval, 0, PMIX_MAX_NSLEN); snprintf(sval, PMIX_MAX_NSLEN, "test_internal:%s:%d:%d", my_nspace, my_rank, idx); GET(string, sval, my_nspace, my_rank, 0, idx, 1, 1, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Get of remote key on local proc", my_nspace, my_rank)); PMIX_PROC_DESTRUCT(&proc); exit(rc); } } PMIX_PROC_DESTRUCT(&proc); return PMIX_SUCCESS; } pmix-6.1.1~rc2/test/util/0000775000175000017500000000000015203536752015431 5ustar alastairalastairpmix-6.1.1~rc2/test/util/numa.c0000664000175000017500000000521415203536752016537 0ustar alastairalastair#include #include #include #include #include #include #include int main(int argc, char **argv) { hwloc_topology_t topo; int ret; int num, weight, N; hwloc_obj_t obj; unsigned width, w; hwloc_bitmap_t numas[100], result; int m; char *tmp, cpus[2048]; bool overlap = false; if (2 != argc) { fprintf(stderr, "Usage: %s xml-filename\n", argv[0]); return -1; } if (0 != hwloc_topology_init(&topo)) { return -1; } if (0 != hwloc_topology_set_xml(topo, argv[1])) { fprintf(stderr, "SETXML FAILED\n"); return -1; } /* since we are loading this from an external source, we have to * explicitly set a flag so hwloc sets things up correctly */ ret = hwloc_topology_set_io_types_filter(topo, HWLOC_TYPE_FILTER_KEEP_IMPORTANT); if (0 != ret) { fprintf(stderr, "IOTYPES FAILED\n"); hwloc_topology_destroy(topo); return ret; } if (0 != hwloc_topology_set_flags(topo, HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)) { fprintf(stderr, "SETFLAGS FAILED\n"); hwloc_topology_destroy(topo); return -1; } /* now load the topology */ if (0 != hwloc_topology_load(topo)) { fprintf(stderr, "LOAD FAILED\n"); hwloc_topology_destroy(topo); return -1; } num = hwloc_get_nbobjs_by_type(topo, HWLOC_OBJ_NUMANODE); fprintf(stderr, "NUM NUMAS: %d\n", num); if (0 > num) { return -1; } width = (unsigned)num; N = 0; for (w = 0; w < width; w++) { /* get the object at this index */ obj = hwloc_get_obj_by_type(topo, HWLOC_OBJ_NUMANODE, w); /* how many pu's are under it? */ weight = hwloc_bitmap_weight(obj->cpuset); hwloc_bitmap_list_snprintf(cpus, 2048, obj->cpuset); fprintf(stderr, "NUMA: %u OSINDX: %u NPUS: %d PUS: %s\n", w, obj->os_index, weight, cpus); /* check for overlap with all preceding numas */ for (m=0; m < N; m++) { if (hwloc_bitmap_intersects(obj->cpuset, numas[m])) { result = hwloc_bitmap_alloc(); hwloc_bitmap_and(result, obj->cpuset, numas[m]); hwloc_bitmap_asprintf(&tmp, result); fprintf(stderr, "\tINTERSECTS NUMA %d: %s\n", m, tmp); hwloc_bitmap_free(result); free(tmp); } } /* cache this bitmap */ numas[N] = hwloc_bitmap_alloc(); hwloc_bitmap_copy(numas[N], obj->cpuset); ++N; } if (!overlap) { fprintf(stderr, "NO OVERLAP\n"); } } pmix-6.1.1~rc2/test/util/Makefile.am0000664000175000017500000000252315203536752017467 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2006-2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2024 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # noinst_PROGRAMS = numa convert numa_SOURCES = \ numa.c numa_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) numa_LDADD = \ $(pmix_hwloc_LIBS) \ $(top_builddir)/src/libpmix.la convert_SOURCES = \ convert.c convert_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) convert_LDADD = \ $(pmix_hwloc_LIBS) \ $(top_builddir)/src/libpmix.la clean-local: rm -f convert numa pmix-6.1.1~rc2/test/util/convert.c0000664000175000017500000000306115203536752017255 0ustar alastairalastair#include #include #include #include #include #include #include int main(int argc, char **argv) { hwloc_topology_t topo; char *tmp; int ret; if (2 != argc) { fprintf(stderr, "Usage: %s input-xml-filename\n", argv[0]); return -1; } if (0 != hwloc_topology_init(&topo)) { return -1; } if (0 != hwloc_topology_set_xml(topo, argv[1])) { fprintf(stderr, "SETXML FAILED\n"); return -1; } /* since we are loading this from an external source, we have to * explicitly set a flag so hwloc sets things up correctly */ ret = hwloc_topology_set_io_types_filter(topo, HWLOC_TYPE_FILTER_KEEP_IMPORTANT); if (0 != ret) { fprintf(stderr, "IOTYPES FAILED\n"); hwloc_topology_destroy(topo); return ret; } if (0 != hwloc_topology_set_flags(topo, HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)) { fprintf(stderr, "SETFLAGS FAILED\n"); hwloc_topology_destroy(topo); return -1; } /* now load the topology */ if (0 != hwloc_topology_load(topo)) { fprintf(stderr, "LOAD FAILED\n"); hwloc_topology_destroy(topo); return -1; } /* output it in v1 format */ asprintf(&tmp, "%s.v1", argv[1]); if (0 != hwloc_topology_export_xml(topo, tmp, HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1)) { fprintf(stderr, "EXPORT FAILED\n"); hwloc_topology_destroy(topo); return -1; } hwloc_topology_destroy(topo); return 0; } pmix-6.1.1~rc2/test/python/0000775000175000017500000000000015203536752015775 5ustar alastairalastairpmix-6.1.1~rc2/test/python/sched.py0000775000175000017500000001106415203536752017442 0ustar alastairalastair#!/usr/bin/env python3 from pmix import * import signal, time import os import select import subprocess global killer class GracefulKiller: kill_now = False def __init__(self): signal.signal(signal.SIGINT, self.exit_gracefully) signal.signal(signal.SIGTERM, self.exit_gracefully) def exit_gracefully(self,signum, frame): self.kill_now = True def clientconnected(proc:tuple is not None): print("CLIENT CONNECTED", proc) return PMIX_SUCCESS def clientfinalized(proc:tuple is not None): print("CLIENT FINALIZED", proc) return PMIX_SUCCESS def clientfence(args:dict is not None): print("SERVER FENCE", args) return PMIX_SUCCESS def main(): try: foo = PMIxServer() except: print("FAILED TO CREATE SERVER") exit(1) print("Testing server version ", foo.get_version()) args = [{'key':PMIX_SERVER_SCHEDULER, 'value':'T', 'val_type':PMIX_BOOL}] map = {'clientconnected': clientconnected, 'clientfinalized': clientfinalized, 'fencenb': clientfence} my_result = foo.init(args, map) print("Testing PMIx_Initialized") rc = foo.initialized() print("Initialized: ", rc) vers = foo.get_version() print("Version: ", vers) # Register a fabric rc,fab = foo.fabric_register(None) print("Fabric registered: ", foo.error_string(rc)) # setup the application (rc, regex) = foo.generate_regex(["test000","test001","test002"]) print("Node regex, rc: ", regex, foo.error_string(rc)) (rc, ppn) = foo.generate_ppn(["0,1,2", "3,4,5", "6,7"]) print("PPN, rc: ", ppn, foo.error_string(rc)) darray = {'type':PMIX_INFO, 'array':[{'key':PMIX_ALLOC_FABRIC_ID, 'value':'SIMPSCHED.net', 'val_type':PMIX_STRING}, {'key':PMIX_ALLOC_FABRIC_SEC_KEY, 'value':'T', 'val_type':PMIX_BOOL}, {'key':PMIX_SETUP_APP_ENVARS, 'value':'T', 'val_type':PMIX_BOOL}]} kyvals = [{'key':PMIX_NODE_MAP, 'value':regex, 'val_type':PMIX_STRING}, {'key':PMIX_PROC_MAP, 'value':ppn, 'val_type':PMIX_STRING}, {'key':PMIX_ALLOC_FABRIC, 'value':darray, 'val_type':PMIX_DATA_ARRAY}] appinfo = [] rc, appinfo = foo.setup_application("SIMPSCHED", kyvals) print("SETUPAPP: ", appinfo) rc = foo.setup_local_support("SIMPSCHED", appinfo) print("SETUPLOCAL: ", foo.error_string(rc)) # get our environment as a base env = os.environ.copy() # register an nspace for the client app kvals = [{'key':PMIX_NODE_MAP, 'value':regex, 'val_type':PMIX_STRING}, {'key':PMIX_PROC_MAP, 'value':ppn, 'val_type':PMIX_STRING}, {'key':PMIX_UNIV_SIZE, 'value':1, 'val_type':PMIX_UINT32}, {'key':PMIX_JOB_SIZE, 'value':1, 'val_type':PMIX_UINT32}] print("REGISTERING NSPACE") rc = foo.register_nspace("testnspace", 1, kvals) print("RegNspace ", foo.error_string(rc)) # register a client uid = os.getuid() gid = os.getgid() print("REGISTERING CLIENT") rc = foo.register_client({'nspace':"testnspace", 'rank':0}, uid, gid) print("RegClient ", foo.error_string(rc)) # setup the fork rc = foo.setup_fork({'nspace':"testnspace", 'rank':0}, env) print("SetupFrk", foo.error_string(rc)) # setup the client argv args = ["./client.py"] # open a subprocess with stdout and stderr # as distinct pipes so we can capture their # output as the process runs p = subprocess.Popen(args, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # define storage to catch the output stdout = [] stderr = [] # loop until the pipes close while True: reads = [p.stdout.fileno(), p.stderr.fileno()] ret = select.select(reads, [], []) stdout_done = True stderr_done = True for fd in ret[0]: # if the data if fd == p.stdout.fileno(): read = p.stdout.readline() if read: read = read.decode('utf-8').rstrip() print('stdout: ' + read) stdout_done = False elif fd == p.stderr.fileno(): read = p.stderr.readline() if read: read = read.decode('utf-8').rstrip() print('stderr: ' + read) stderr_done = False if stdout_done and stderr_done: break print("FINALIZING") foo.finalize() if __name__ == '__main__': global killer killer = GracefulKiller() main() pmix-6.1.1~rc2/test/python/run_server.sh.in0000775000175000017500000000010315203536752021125 0ustar alastairalastair#!/bin/bash export PYTHONPATH=@PMIX_PYTHON_EGG_PATH@ ./server.py pmix-6.1.1~rc2/test/python/tool.py0000775000175000017500000000177215203536752017336 0ustar alastairalastair#!/usr/bin/env python3 from pmix import * from os import * import time def main(): foo = PMIxTool() print("Testing PMIx Tool ", foo.get_version()) # construct a session tmpdir uid = os.geteuid() gid = os.getegid() basename = os.path.basename(__file__) tmpdir = os.getenv('TMPDIR') sessiondir = os.path.join(tmpdir, basename + '.session.' + str(uid) + '.' + str(gid)) info = [{'key':PMIX_LAUNCHER, 'value':True, 'val_type':PMIX_BOOL}, {'key':PMIX_SERVER_TOOL_SUPPORT, 'value':True, 'val_type':PMIX_BOOL}, {'key':PMIX_SERVER_TMPDIR, 'value':sessiondir, 'val_type':PMIX_STRING}] (my_result, myproc) = foo.init(info) if 0 != my_result: print("FAILED TO INIT", foo.error_string(my_result)) exit(1) # construct an application to spawn app = {'cmd':'hostname', 'maxprocs':1} foo.spawn(None, [app]) time.sleep(2.0) # finalize foo.finalize() print("Tool finalize complete") if __name__ == '__main__': main() pmix-6.1.1~rc2/test/python/server.py0000775000175000017500000001010615203536752017656 0ustar alastairalastair#!/usr/bin/env python3 from pmix import * import signal, time import os import select import subprocess global killer class GracefulKiller: kill_now = False def __init__(self): signal.signal(signal.SIGINT, self.exit_gracefully) signal.signal(signal.SIGTERM, self.exit_gracefully) def exit_gracefully(self,signum, frame): self.kill_now = True def clientconnected(proc:dict is not None): print("CLIENT CONNECTED", proc) return PMIX_SUCCESS def clientfinalized(proc:dict is not None): print("CLIENT FINALIZED", proc) return PMIX_SUCCESS def clientfence(args:dict is not None): # check directives try: if args['directives'] is not None: for d in args['directives']: # these are each an info dict if "pmix" not in d['key']: # we do not support such directives - see if # it is required try: if d['flags'] & PMIX_INFO_REQD: # return an error return PMIX_ERR_NOT_SUPPORTED except: #it can be ignored pass except: pass return PMIX_SUCCESS, None def main(): try: foo = PMIxServer() except: print("FAILED TO CREATE SERVER") exit(1) print("Testing server version ", foo.get_version()) args = [{'key':'FOOBAR', 'value':'VAR', 'val_type':PMIX_STRING}, {'key':'BLAST', 'value':7, 'val_type':PMIX_INT32}] map = {'clientconnected': clientconnected, 'clientfinalized': clientfinalized, 'fencenb': clientfence} my_result = foo.init(args, map) print("Testing PMIx_Initialized") rc = foo.initialized() print("Initialized: ", rc) vers = foo.get_version() print("Version: ", vers) # get our environment as a base env = os.environ.copy() # register an nspace for the client app (rc, regex) = foo.generate_regex(["test000","test001","test002"]) (rc, ppn) = foo.generate_ppn(["0,1,2", "3,4,5", "6,7"]) kvals = [{'key':PMIX_NODE_MAP, 'value':regex, 'val_type':PMIX_STRING}, {'key':PMIX_PROC_MAP, 'value':ppn, 'val_type':PMIX_STRING}, {'key':PMIX_UNIV_SIZE, 'value':1, 'val_type':PMIX_UINT32}, {'key':PMIX_JOB_SIZE, 'value':1, 'val_type':PMIX_UINT32}] print("REGISTERING NSPACE") rc = foo.register_nspace("testnspace", 1, kvals) print("RegNspace ", foo.error_string(rc)) # register a client uid = os.getuid() gid = os.getgid() rc = foo.register_client({'nspace':"testnspace", 'rank':0}, uid, gid) print("RegClient ", foo.error_string(rc)) # setup the fork rc = foo.setup_fork({'nspace':"testnspace", 'rank':0}, env) print("SetupFrk", foo.error_string(rc)) # setup the client argv args = ["./client.py"] # open a subprocess with stdout and stderr # as distinct pipes so we can capture their # output as the process runs p = subprocess.Popen(args, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # define storage to catch the output stdout = [] stderr = [] # loop until the pipes close while True: reads = [p.stdout.fileno(), p.stderr.fileno()] ret = select.select(reads, [], []) stdout_done = True stderr_done = True for fd in ret[0]: # if the data if fd == p.stdout.fileno(): read = p.stdout.readline() if read: read = read.decode('utf-8').rstrip() print('stdout: ' + read) stdout_done = False elif fd == p.stderr.fileno(): read = p.stderr.readline() if read: read = read.decode('utf-8').rstrip() print('stderr: ' + read) stderr_done = False if stdout_done and stderr_done: break print("FINALIZING") foo.finalize() if __name__ == '__main__': global killer killer = GracefulKiller() main() pmix-6.1.1~rc2/test/python/run_sched.sh.in0000775000175000017500000000010215203536752020704 0ustar alastairalastair#!/bin/bash export PYTHONPATH=@PMIX_PYTHON_EGG_PATH@ ./sched.py pmix-6.1.1~rc2/test/python/client.py0000775000175000017500000000456015203536752017635 0ustar alastairalastair#!/usr/bin/env python3 from pmix import * import time import threading termEvent = threading.Event() def default_evhandler(evhdlr:int, status:int, source:dict, info:list, results:list): print("DEFAULT HANDLER") return PMIX_EVENT_ACTION_COMPLETE,None def model_evhandler(evhdlr:int, status:int, source:dict, info:list, results:list): global termEvent print("MODEL HANDLER") termEvent.set() return PMIX_EVENT_ACTION_COMPLETE,None def main(): global termEvent foo = PMIxClient() print("Testing PMIx ", foo.get_version()) info = [{'key':PMIX_PROGRAMMING_MODEL, 'value':'TEST', 'val_type':PMIX_STRING}, {'key':PMIX_MODEL_LIBRARY_NAME, 'value':'PMIX', 'val_type':PMIX_STRING}] my_result = foo.init(info) print("Init result ", my_result) if 0 != my_result[0]: print("FAILED TO INIT") exit(1) # register an event handler rc,myevhndlr = foo.register_event_handler(None, None, default_evhandler) print("REGISTER DEFAULT", foo.error_string(rc)) # register the model handler rc,mymodelhndlr = foo.register_event_handler([PMIX_MODEL_DECLARED], None, model_evhandler) print("REGISTER MODEL", foo.error_string(rc)) # try putting something print("PUT") rc = foo.put(PMIX_GLOBAL, "mykey", {'value':1, 'val_type':PMIX_INT32}) print("Put result ",foo.error_string(rc)); # commit it print("COMMIT") rc = foo.commit() print ("Commit result ", foo.error_string(rc)) # execute fence print("FENCE") procs = [] info = [] rc = foo.fence(procs, info) print("Fence result ", foo.error_string(rc)) print("GET") info = [] rc, get_val = foo.get({'nspace':"testnspace", 'rank': 0}, "mykey", info) print("Get result: ", foo.error_string(rc)) print("Get value returned: ", get_val) # test a fence that should return not_supported because # we pass a required attribute that doesn't exist procs = [] info = [{'key': 'ARBITRARY', 'flags': PMIX_INFO_REQD, 'value':10, 'val_type':PMIX_INT}] rc = foo.fence(procs, info) print("Fence should be not supported:", foo.error_string(rc)) # wait for model event while not termEvent.is_set(): time.sleep(0.001) # finalize info = [] foo.finalize(info) print("Client finalize complete") if __name__ == '__main__': main() pmix-6.1.1~rc2/test/python/Makefile.am0000664000175000017500000000100115203536752020021 0ustar alastairalastair# # Copyright (c) 2019 Intel, Inc. All rights reserved. # Copyright (c) 2021 Nanook Consulting. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # we do NOT want picky compilers down here CFLAGS = $(PMIX_CFLAGS_BEFORE_PICKY) noinst_SCRIPTS = \ run_server.sh.in \ run_sched.sh.in \ server.py \ sched.py \ client.py ######################### # Support for "make check" if WANT_PYTHON_BINDINGS TESTS = \ run_server.sh \ run_sched.sh endif pmix-6.1.1~rc2/test/run_tests14.pl.in0000777000175000017500000000000015203536752022574 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/test_publish.h0000664000175000017500000000060515203536752017333 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "test_common.h" int test_publish_lookup(char *my_nspace, int my_rank); pmix-6.1.1~rc2/test/run_tests07.pl.in0000777000175000017500000000000015203536752022576 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/cmd_examples0000664000175000017500000000305015203536752017036 0ustar alastairalastair# 1 blocking fence with data exchange among all processes from two namespaces: ./pmix_test -n 4 --ns-dist 3:1 --fence "[db | 0:0-2;1:3]" ./pmix_test -n 4 --ns-dist 3:1 --fence "[db | 0:;1:3]" ./pmix_test -n 4 --ns-dist 3:1 --fence "[db | 0:;1:]" # 1 non-blocking fence without data exchange among processes from the 1st namespace ./pmix_test -n 4 --ns-dist 3:1 --fence "[0:]" # blocking fence without data exchange among processes from the 1st namespace ./pmix_test -n 4 --ns-dist 3:1 --fence "[b | 0:]" # non-blocking fence with data exchange among processes from the 1st namespace. Ranks 0, 1 from ns 0 are sleeping for 2 sec before doing fence test. ./pmix_test -n 4 --ns-dist 3:1 --fence "[d | 0:]" --noise "[0:0,1]" # blocking fence with data exchange across processes from the same namespace. ./pmix_test -n 4 --job-fence -c # 3 fences: 1 - non-blocking without data exchange across processes from ns 0, # 2 - non-blocking across processes 0 and 1 from ns 0 and process 3 from ns 1, # 3 - blocking with data exchange across processes from their own namespace. # pmix currently doesn't support multiple fences, so disable this test. #./pmix_test -n 4 --job-fence -c --fence "[0:][d|0:0-1;1:]" --use-same-keys --ns-dist "3:1" # test publish/lookup/unpublish functionality. ./pmix_test -n 2 --test-publish # test spawn functionality. ./pmix_test -n 2 --test-spawn # test connect/disconnect between processes from the same namespace. ./pmix_test -n 2 --test-connect # resolve peers from different namespaces. ./pmix_test -n 5 --test-resolve-peers --ns-dist "1:2:2" pmix-6.1.1~rc2/test/test_spawn.h0000664000175000017500000000057415203536752017022 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "test_common.h" int test_spawn(char *my_nspace, int my_rank); pmix-6.1.1~rc2/test/pmix_test.c0000664000175000017500000001472515203536752016645 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2019 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. * All rights reserved. * * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include #include #include #include #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "server_callbacks.h" #include "test_common.h" #include "test_server.h" #include "utils.h" bool spawn_wait = false; int main(int argc, char **argv) { char **client_env = NULL; char **client_argv = NULL; int rc, i; struct stat stat_buf; int test_fail = 0; char *tmp; int ns_nprocs; sigset_t unblock; test_params params; INIT_TEST_PARAMS(params); /* smoke test */ if (PMIX_SUCCESS != 0) { TEST_ERROR(("ERROR IN COMPUTING CONSTANTS: PMIX_SUCCESS = %d", PMIX_SUCCESS)); exit(1); } TEST_VERBOSE(("Testing version %s", PMIx_Get_version())); parse_cmd(argc, argv, ¶ms); TEST_VERBOSE(("Start PMIx_lite smoke test (timeout is %d)", params.timeout)); /* set common argv and env */ client_env = PMIx_Argv_copy(environ); set_client_argv(¶ms, &client_argv); tmp = PMIx_Argv_join(client_argv, ' '); TEST_VERBOSE(("Executing test: %s", tmp)); free(tmp); /* verify executable */ if (0 > (rc = stat(params.binary, &stat_buf))) { TEST_ERROR( ("Cannot stat() executable \"%s\": %d: %s", params.binary, errno, strerror(errno))); FREE_TEST_PARAMS(params); return 0; } else if (!S_ISREG(stat_buf.st_mode)) { TEST_ERROR(("Client executable \"%s\": is not a regular file", params.binary)); FREE_TEST_PARAMS(params); return 0; } else if (!(stat_buf.st_mode & S_IXUSR)) { TEST_ERROR(("Client executable \"%s\": has no executable flag", params.binary)); FREE_TEST_PARAMS(params); return 0; } /* ensure that SIGCHLD is unblocked as we need to capture it */ if (0 != sigemptyset(&unblock)) { fprintf(stderr, "SIGEMPTYSET FAILED\n"); exit(1); } if (0 != sigaddset(&unblock, SIGCHLD)) { fprintf(stderr, "SIGADDSET FAILED\n"); exit(1); } if (0 != sigprocmask(SIG_UNBLOCK, &unblock, NULL)) { fprintf(stderr, "SIG_UNBLOCK FAILED\n"); exit(1); } if (PMIX_SUCCESS != (rc = server_init(¶ms))) { FREE_TEST_PARAMS(params); return rc; } cli_init(params.lsize); int launched = 0; /* set namespaces and fork clients */ if (NULL == params.ns_dist) { int base_rank = 0; /* compute my start counter */ for (i = 0; i < my_server_id; i++) { base_rank += (params.nprocs % params.nservers) > (uint32_t) i ? params.nprocs / params.nservers + 1 : params.nprocs / params.nservers; } /* we have a single namespace for all clients */ ns_nprocs = params.nprocs; launched += server_launch_clients(params.lsize, params.nprocs, base_rank, ¶ms, &client_env, &client_argv); } else { char *pch; pch = strtok(params.ns_dist, ":"); while (NULL != pch) { ns_nprocs = (int) strtol(pch, NULL, 10); if (params.nprocs < (uint32_t)(launched + ns_nprocs)) { TEST_ERROR(("srv #%d: Total number of processes doesn't correspond number " "specified by ns_dist parameter.", my_server_id)); FREE_TEST_PARAMS(params); return PMIX_ERROR; } if (0 < ns_nprocs) { launched += server_launch_clients(ns_nprocs, ns_nprocs, 0, ¶ms, &client_env, &client_argv); } pch = strtok(NULL, ":"); } } if (params.lsize != (uint32_t) launched) { TEST_ERROR(("srv #%d: Total number of processes doesn't correspond number specified by " "ns_dist parameter.", my_server_id)); cli_kill_all(); test_fail = 1; goto done; } /* hang around until the client(s) finalize */ while (!test_complete) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000; nanosleep(&ts, NULL); } if (test_abort) { TEST_ERROR(("srv #%d: Test was aborted!", my_server_id)); /* do not simply kill the clients as that generates * event notifications which these tests then print * out, flooding the log */ // cli_kill_all(); test_fail = 1; } if (0 != params.test_spawn) { PMIX_WAIT_FOR_COMPLETION(spawn_wait); } for (i = 0; i < cli_info_cnt; i++) { if (cli_info[i].exit_code != 0) { ++test_fail; } } /* deregister the errhandler */ PMIx_Deregister_event_handler(0, op_callbk, NULL); done: TEST_VERBOSE(("srv #%d: call server_finalize!", my_server_id)); test_fail += server_finalize(¶ms, test_fail); TEST_VERBOSE(("srv #%d: exit sequence!", my_server_id)); FREE_TEST_PARAMS(params); PMIx_Argv_free(client_argv); PMIx_Argv_free(client_env); if (0 == test_fail) { TEST_OUTPUT(("Test SUCCEEDED!")); } return test_fail; } pmix-6.1.1~rc2/test/test_common.c0000664000175000017500000005371715203536752017164 0ustar alastairalastair/* * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "pmix_common.h" #include "test_common.h" #include #include #include int pmix_test_verbose = 0; FILE *file; #define OUTPUT_MAX 1024 char *pmix_test_output_prepare(const char *fmt, ...) { static char output[OUTPUT_MAX]; va_list args; va_start(args, fmt); memset(output, 0, sizeof(output)); vsnprintf(output, OUTPUT_MAX - 1, fmt, args); va_end(args); return output; } void parse_cmd(int argc, char **argv, test_params *params) { int i; /* set output to stderr by default */ file = stdout; if (params->nspace != NULL) { params->nspace = NULL; } /* parse user options */ for (i = 1; i < argc; i++) { if (0 == strcmp(argv[i], "--n") || 0 == strcmp(argv[i], "-n")) { i++; if (NULL != argv[i]) { params->np = strdup(argv[i]); params->nprocs = strtol(argv[i], NULL, 10); if (-1 == params->ns_size) { params->ns_size = params->nprocs; } } } else if (0 == strcmp(argv[i], "--h") || 0 == strcmp(argv[i], "-h")) { /* print help */ fprintf(stderr, "usage: pmix_test [-h] [-e foo] [-b] [-c] [-nb]\n"); fprintf(stderr, "\t-n the job size (for checking purposes)\n"); fprintf(stderr, "\t-s number of servers to emulate\n"); fprintf(stderr, "\t-e foo use foo as test client\n"); fprintf(stderr, "\t-v verbose output\n"); fprintf(stderr, "\t-t <> set timeout\n"); fprintf(stderr, "\t-o out redirect clients logs to file out.\n"); fprintf( stderr, "\t--early-fail force client process with rank 0 to fail before PMIX_Init.\n"); fprintf(stderr, "\t--ns-dist n1:n2:n3 register n namespaces (3 in this example) each " "with ni ranks (n1, n2 or n3).\n"); fprintf(stderr, "\t--fence \"[ | ns0:ranks;ns1:ranks...][...]\" " "specify fences in different configurations.\n"); fprintf(stderr, "\t--use-same-keys relative to the --fence option: put the same keys " "in the interim between multiple fences.\n"); fprintf(stderr, "\t--job-fence test fence inside its own namespace.\n"); fprintf(stderr, "\t-c relative to the --job-fence option: fence[_nb] callback " "shall include all collected data\n"); fprintf(stderr, "\t-nb relative to the --job-fence option: use non-blocking fence\n"); fprintf(stderr, "\t--noise \"[ns0:ranks;ns1:ranks...]\" add system noise to specified " "processes.\n"); fprintf(stderr, "\t--test-publish test publish/lookup/unpublish api.\n"); fprintf(stderr, "\t--test-spawn test spawn api.\n"); fprintf(stderr, "\t--test-connect test connect/disconnect api.\n"); fprintf(stderr, "\t--test-resolve-peers test resolve_peers api.\n"); fprintf(stderr, "\t--test-error test error handling api.\n"); fprintf(stderr, "\t--test-replace N:k0,k1,...,k(N-1) test key replace for N keys, " "k0,k1,k(N-1) - key indexes to replace \n"); fprintf(stderr, "\t--test-internal N test store internal key, N - number of internal keys\n"); fprintf(stderr, "\t--gds set GDS module \"--gds " "hash|ds12\", default is hash\n"); exit(0); } else if (0 == strcmp(argv[i], "--exec") || 0 == strcmp(argv[i], "-e")) { i++; if (NULL != argv[i]) { params->binary = strdup(argv[i]); } } else if (0 == strcmp(argv[i], "--nservers") || 0 == strcmp(argv[i], "-s")) { i++; if (NULL != argv[i]) { params->nservers = atoi(argv[i]); } if (2 < params->nservers) { fprintf(stderr, "Only support up to 2 servers\n"); exit(1); } } else if (0 == strcmp(argv[i], "--verbose") || 0 == strcmp(argv[i], "-v")) { TEST_VERBOSE_ON(); params->verbose = 1; } else if (0 == strcmp(argv[i], "--timeout") || 0 == strcmp(argv[i], "-t")) { i++; if (NULL != argv[i]) { params->timeout = atoi(argv[i]); if (params->timeout == 0) { params->timeout = TEST_DEFAULT_TIMEOUT; } } } else if (0 == strcmp(argv[i], "-o")) { i++; if (NULL != argv[i]) { params->prefix = strdup(argv[i]); } } else if (0 == strcmp(argv[i], "-s")) { i++; if (NULL != argv[i]) { params->nspace = strdup(argv[i]); } } else if (0 == strcmp(argv[i], "--rank") || 0 == strcmp(argv[i], "-r")) { i++; if (NULL != argv[i]) { params->rank = strtol(argv[i], NULL, 10); } } else if (0 == strcmp(argv[i], "--early-fail")) { params->early_fail = 1; } else if (0 == strcmp(argv[i], "--fence")) { i++; if (NULL != argv[i]) { params->fences = strdup(argv[i]); if (0 != parse_fence(params->fences, 0)) { fprintf(stderr, "Incorrect --fence option format: %s\n", params->fences); exit(1); } } } else if (0 == strcmp(argv[i], "--use-same-keys")) { params->use_same_keys = 1; } else if (0 == strcmp(argv[i], "--job-fence")) { params->test_job_fence = 1; } else if (0 == strcmp(argv[i], "--collect-corrupt")) { params->collect_bad = 1; } else if (0 == strcmp(argv[i], "--collect") || 0 == strcmp(argv[i], "-c")) { params->collect = 1; } else if (0 == strcmp(argv[i], "--non-blocking") || 0 == strcmp(argv[i], "-nb")) { params->nonblocking = 1; } else if (0 == strcmp(argv[i], "--noise")) { i++; if (NULL != argv[i]) { params->noise = strdup(argv[i]); if (0 != parse_noise(params->noise, 0)) { fprintf(stderr, "Incorrect --noise option format: %s\n", params->noise); exit(1); } } } else if (0 == strcmp(argv[i], "--ns-dist")) { i++; if (NULL != argv[i]) { params->ns_dist = strdup(argv[i]); } } else if (0 == strcmp(argv[i], "--ns-size")) { i++; if (NULL != argv[i]) { params->ns_size = strtol(argv[i], NULL, 10); } } else if (0 == strcmp(argv[i], "--ns-id")) { i++; if (NULL != argv[i]) { params->ns_id = strtol(argv[i], NULL, 10); } } else if (0 == strcmp(argv[i], "--base-rank")) { i++; if (NULL != argv[i]) { params->base_rank = strtol(argv[i], NULL, 10); } } else if (0 == strcmp(argv[i], "--test-publish")) { params->test_publish = 1; } else if (0 == strcmp(argv[i], "--test-spawn")) { params->test_spawn = 1; } else if (0 == strcmp(argv[i], "--test-connect")) { params->test_connect = 1; } else if (0 == strcmp(argv[i], "--test-resolve-peers")) { params->test_resolve_peers = 1; } else if (0 == strcmp(argv[i], "--test-error")) { params->test_error = 1; } else if (0 == strcmp(argv[i], "--test-replace")) { i++; if (NULL != argv[i] && (*argv[i] != '-')) { params->key_replace = strdup(argv[i]); if (0 != parse_replace(params->key_replace, 0, NULL)) { fprintf(stderr, "Incorrect --test-replace option format: %s\n", params->key_replace); exit(1); } } else { params->key_replace = strdup(TEST_REPLACE_DEFAULT); } } else if (0 == strcmp(argv[i], "--test-internal")) { i++; if ((NULL != argv[i]) && (*argv[i] != '-')) { params->test_internal = strtol(argv[i], NULL, 10); } else { params->test_internal = 1; } } else if (0 == strcmp(argv[i], "--gds")) { i++; params->gds_mode = strdup(argv[i]); } else { fprintf(stderr, "unrecognized option: %s\n", argv[i]); exit(1); } } if (NULL == params->binary) { char *basename = NULL; basename = strrchr(argv[0], '/'); if (basename) { *basename = '\0'; /* pmix_test and pmix_clients are the shell scripts that * make sure that actual binary placed in "./.libs" directory * is properly linked. * after launch pmix_test you'll find the following process: * /test/.libs/lt-pmix_test * * To launch * /test/pmix_client * instead of * /test/.libs/pmix_client * we need to do a step back in directory tree. */ if (0 > asprintf(¶ms->binary, "%s/../pmix_client", argv[0])) { exit(1); } *basename = '/'; } else { if (0 > asprintf(¶ms->binary, "pmix_client")) { exit(1); } } } if (params->collect_bad) { params->collect = params->rank % 2; } // Fix rank if running under SLURM if (PMIX_RANK_UNDEF == params->rank) { char *ranklist = getenv("SLURM_GTIDS"); char *rankno = getenv("SLURM_LOCALID"); if (NULL != ranklist && NULL != rankno) { char **myargv = PMIx_Argv_split(ranklist, ','); int count = PMIx_Argv_count(myargv); int rankidx = strtoul(rankno, NULL, 10); if (rankidx >= count) { fprintf(stderr, "It feels like we are running under SLURM:\n\t" "SLURM_GTIDS=%s, SLURM_LOCALID=%s\nbut env vars are conflicting\n", ranklist, rankno); exit(1); } params->rank = strtoul(myargv[rankidx], NULL, 10); PMIx_Argv_free(myargv); } } // Fix namespace if running under SLURM if (NULL == params->nspace) { char *nspace = getenv("PMIX_NAMESPACE"); if (NULL != nspace) { params->nspace = strdup(nspace); } } } static void fcon(fence_desc_t *p) { p->blocking = 0; p->data_exchange = 0; p->participants = PMIX_NEW(pmix_list_t); } static void fdes(fence_desc_t *p) { PMIX_LIST_RELEASE(p->participants); } PMIX_CLASS_INSTANCE(fence_desc_t, pmix_list_item_t, fcon, fdes); PMIX_CLASS_INSTANCE(participant_t, pmix_list_item_t, NULL, NULL); PMIX_CLASS_INSTANCE(key_replace_t, pmix_list_item_t, NULL, NULL); static int ns_id = -1; static fence_desc_t *fdesc = NULL; pmix_list_t *participants = NULL; pmix_list_t test_fences; pmix_list_t *noise_range = NULL; pmix_list_t key_replace; #define CHECK_STRTOL_VAL(val, str, store) \ do { \ if (0 == val) { \ if (0 != strncmp(str, "0", 1)) { \ if (!store) { \ return 1; \ } \ } \ } \ } while (0) static int parse_token(char *str, int step, int store) { char *pch; int count = 0; int remember = -1; int i; int rank; participant_t *proc; switch (step) { case 0: if (store) { fdesc = PMIX_NEW(fence_desc_t); participants = fdesc->participants; } pch = strchr(str, '|'); if (NULL != pch) { while (pch != str) { if ('d' == *str) { if (store && NULL != fdesc) { fdesc->data_exchange = 1; } } else if ('b' == *str) { if (store && NULL != fdesc) { fdesc->blocking = 1; } } else if (' ' != *str) { if (!store) { return 1; } } str++; } if (0 < parse_token(pch + 1, 1, store)) { if (!store) { return 1; } } } else { if (0 < parse_token(str, 1, store)) { if (!store) { return 1; } } } if (store && NULL != fdesc) { pmix_list_append(&test_fences, &fdesc->super); } break; case 1: if (store && NULL == participants) { participants = PMIX_NEW(pmix_list_t); noise_range = participants; } pch = strtok(str, ";"); while (NULL != pch) { if (0 < parse_token(pch, 2, store)) { if (!store) { return 1; } } pch = strtok(NULL, ";"); } break; case 2: pch = strchr(str, ':'); if (NULL != pch) { *pch = '\0'; pch++; while (' ' == *str) { str++; } ns_id = (int) (strtol(str, NULL, 10)); CHECK_STRTOL_VAL(ns_id, str, store); if (0 < parse_token(pch, 3, store)) { if (!store) { return 1; } } } else { if (!store) { return 1; } } break; case 3: while (' ' == *str) { str++; } if ('\0' == *str) { /* all ranks from namespace participate */ if (store && NULL != participants) { proc = PMIX_NEW(participant_t); (void) snprintf(proc->proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, ns_id); proc->proc.rank = PMIX_RANK_WILDCARD; pmix_list_append(participants, &proc->super); } } while ('\0' != *str) { if (',' == *str && 0 != count) { *str = '\0'; if (-1 != remember) { rank = (int) (strtol(str - count, NULL, 10)); CHECK_STRTOL_VAL(rank, str - count, store); for (i = remember; i < rank; i++) { if (store && NULL != participants) { proc = PMIX_NEW(participant_t); (void) snprintf(proc->proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, ns_id); proc->proc.rank = i; pmix_list_append(participants, &proc->super); } } remember = -1; } rank = (int) (strtol(str - count, NULL, 10)); CHECK_STRTOL_VAL(rank, str - count, store); if (store && NULL != participants) { proc = PMIX_NEW(participant_t); (void) snprintf(proc->proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, ns_id); proc->proc.rank = rank; pmix_list_append(participants, &proc->super); } count = -1; } else if ('-' == *str && 0 != count) { *str = '\0'; remember = (int) (strtol(str - count, NULL, 10)); CHECK_STRTOL_VAL(remember, str - count, store); count = -1; } str++; count++; } if (0 != count) { if (-1 != remember) { rank = (int) (strtol(str - count, NULL, 10)); CHECK_STRTOL_VAL(rank, str - count, store); for (i = remember; i < rank; i++) { if (store && NULL != participants) { proc = PMIX_NEW(participant_t); (void) snprintf(proc->proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, ns_id); proc->proc.rank = i; pmix_list_append(participants, &proc->super); } } remember = -1; } rank = (int) (strtol(str - count, NULL, 10)); CHECK_STRTOL_VAL(rank, str - count, store); if (store && NULL != participants) { proc = PMIX_NEW(participant_t); (void) snprintf(proc->proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, ns_id); proc->proc.rank = rank; pmix_list_append(participants, &proc->super); } } break; default: fprintf(stderr, "Incorrect parsing step.\n"); return 1; } return 0; } int parse_fence(char *fence_param, int store) { int ret = 0; char *tmp = strdup(fence_param); char *pch, *ech; pch = strchr(tmp, '['); while (NULL != pch) { pch++; ech = strchr(pch, ']'); if (NULL != ech) { *ech = '\0'; ech++; ret += parse_token(pch, 0, store); pch = strchr(ech, '['); } else { ret = 1; break; } } free(tmp); return ret; } int parse_noise(char *noise_param, int store) { int ret = 0; char *tmp = strdup(noise_param); char *pch, *ech; pch = strchr(tmp, '['); if (NULL != pch) { pch++; ech = strchr(pch, ']'); if (NULL != ech) { *ech = '\0'; ech++; if ('\0' != *ech) { ret = 1; } else { ret = parse_token(pch, 1, store); } } else { ret = 1; } } free(tmp); return ret; } static int is_digit(const char *str) { if (NULL == str) return 0; while (0 != *str) { if (!isdigit(*str)) { return 0; } else { str++; } } return 1; } int parse_replace(char *replace_param, int store, int *key_num) { int ret = 0; char *tmp = strdup(replace_param); char tmp_str[32]; char *pch, *ech; key_replace_t *item; int cnt = 0; if (NULL == replace_param) { free(tmp); return 1; } pch = strchr(tmp, ':'); snprintf(tmp_str, pch - tmp + 1, "%s", tmp); cnt = atol(tmp_str); if (NULL != key_num) { *key_num = cnt; } while (NULL != pch) { pch++; ech = strchr(pch, ','); if (strlen(pch) > 0) { if (NULL != ech) { snprintf(tmp_str, ech - pch + 1, "%s", pch); } else { snprintf(tmp_str, strlen(pch) + 1, "%s", pch); } if ((0 == is_digit(tmp_str)) || ((atoi(tmp_str) + 1) > cnt)) { ret = 1; break; } pch = ech; if (store) { item = PMIX_NEW(key_replace_t); item->key_idx = atoi(tmp_str); pmix_list_append(&key_replace, &item->super); } } else { ret = 1; break; } } free(tmp); return ret; } int get_total_ns_number(test_params params) { int num = 0; if (NULL == params.ns_dist) { return 1; } else { char *tmp = strdup(params.ns_dist); char *pch = tmp; while (NULL != pch) { num++; pch = strtok((1 == num) ? tmp : NULL, ":"); } num--; free(tmp); } return num; } int get_all_ranks_from_namespace(test_params params, char *nspace, pmix_proc_t **ranks, size_t *nranks) { size_t num_ranks = 0; int num = -1; size_t j; if (NULL == params.ns_dist) { *nranks = params.ns_size; PMIX_PROC_CREATE(*ranks, params.ns_size); for (j = 0; j < (size_t) params.ns_size; j++) { pmix_strncpy((*ranks)[j].nspace, nspace, PMIX_MAX_NSLEN); (*ranks)[j].rank = j; } } else { char *tmp = strdup(params.ns_dist); char *pch = tmp; int myns_id = (int) strtol(nspace + strlen(TEST_NAMESPACE) + 1, NULL, 10); while (NULL != pch && num != myns_id) { pch = strtok((-1 == num) ? tmp : NULL, ":"); if (NULL == pch) { break; } num++; num_ranks = (size_t) strtol(pch, NULL, 10); } if (num == myns_id && 0 != num_ranks) { *nranks = num_ranks; PMIX_PROC_CREATE(*ranks, num_ranks); for (j = 0; j < num_ranks; j++) { pmix_strncpy((*ranks)[j].nspace, nspace, PMIX_MAX_NSLEN); (*ranks)[j].rank = j; } } else { free(tmp); return PMIX_ERROR; } free(tmp); } return PMIX_SUCCESS; } pmix-6.1.1~rc2/test/test_fence.c0000664000175000017500000004361315203536752016746 0ustar alastairalastair/* * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2017 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "test_fence.h" static void get_cb(pmix_status_t status, pmix_value_t *kv, void *cbdata) { get_cbdata *cb = (get_cbdata *) cbdata; PMIX_ACQUIRE_OBJECT(cb); if (PMIX_SUCCESS == status) { PMIx_Value_xfer(cb->kv, kv); } cb->status = status; PMIX_POST_OBJECT(cb); cb->in_progress = 0; } static void add_noise(char *noise_param, char *my_nspace, pmix_rank_t my_rank) { bool participate = false; participant_t *p; parse_noise(noise_param, 1); if (NULL != noise_range) { PMIX_LIST_FOREACH (p, noise_range, participant_t) { if (0 == strncmp(my_nspace, p->proc.nspace, strlen(my_nspace)) && (my_rank == p->proc.rank || PMIX_RANK_WILDCARD == p->proc.rank)) { participate = true; break; } } if (participate) { sleep(2); TEST_VERBOSE(("I'm %s:%d sleeping\n", my_nspace, my_rank)); } PMIX_LIST_RELEASE(noise_range); noise_range = NULL; } } static void release_cb(pmix_status_t status, void *cbdata) { int *ptr = (int *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); *ptr = 0; } int test_fence(test_params params, char *my_nspace, pmix_rank_t my_rank) { int rc; size_t i, npcs; fence_desc_t *desc; participant_t *p, *next; pmix_proc_t *pcs; bool participate; int fence_num = 0; char sval[500]; int put_ind; if (NULL != params.noise) { add_noise(params.noise, my_nspace, my_rank); } PMIX_CONSTRUCT(&test_fences, pmix_list_t); parse_fence(params.fences, 1); TEST_VERBOSE(("fences %s\n", params.fences)); /* cycle thru all the test fence descriptors to find * those that include my nspace/rank */ PMIX_LIST_FOREACH (desc, &test_fences, fence_desc_t) { char *tmp, *tmp2; int dumb; dumb = asprintf(&tmp, "fence %d: block = %d de = %d ", fence_num, desc->blocking, desc->data_exchange); if (-1 == dumb) { TEST_ERROR(("%s:%d: asprintf failed: %d", my_nspace, my_rank, dumb)); PMIX_LIST_DESTRUCT(&test_fences); exit(1); } participate = false; /* search the participants */ PMIX_LIST_FOREACH (p, desc->participants, participant_t) { if (0 == strncmp(my_nspace, p->proc.nspace, strlen(my_nspace)) && (my_rank == p->proc.rank || PMIX_RANK_WILDCARD == p->proc.rank)) { participate = true; } if (PMIX_RANK_WILDCARD == p->proc.rank) { dumb = asprintf(&tmp2, "%sall; ", tmp); } else { dumb = asprintf(&tmp2, "%s%d,", tmp, p->proc.rank); } if (-1 == dumb) { TEST_ERROR(("%s:%d: asprintf failed: %d", my_nspace, my_rank, dumb)); PMIX_LIST_DESTRUCT(&test_fences); exit(1); } free(tmp); tmp = tmp2; } TEST_VERBOSE(("%s\n", tmp)); if (participate) { /*run fence test on this range */ /* first put value (my_ns, my_rank) with key based on fence_num to split results of * different fences*/ put_ind = 0; (void) snprintf(sval, 500, "%d:%s:%d", fence_num, my_nspace, my_rank); PUT(string, sval, PMIX_GLOBAL, fence_num, put_ind++, params.use_same_keys); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } PUT(int, fence_num + my_rank, PMIX_GLOBAL, fence_num, put_ind++, params.use_same_keys); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } PUT(float, fence_num + 1.1, PMIX_GLOBAL, fence_num, put_ind++, params.use_same_keys); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } PUT(uint32_t, fence_num + 14, PMIX_GLOBAL, fence_num, put_ind++, params.use_same_keys); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } PUT(uint16_t, fence_num + 15, PMIX_GLOBAL, fence_num, put_ind++, params.use_same_keys); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } /* Submit the data */ if (PMIX_SUCCESS != (rc = PMIx_Commit())) { TEST_ERROR(("%s:%d: PMIx_Commit failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } /* setup the fence */ npcs = pmix_list_get_size(desc->participants); PMIX_PROC_CREATE(pcs, npcs); i = 0; PMIX_LIST_FOREACH (p, desc->participants, participant_t) { PMIX_LOAD_PROCID(&pcs[i], p->proc.nspace, p->proc.rank); i++; } /* perform fence */ FENCE(desc->blocking, desc->data_exchange, pcs, npcs); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Fence failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&test_fences); PMIX_PROC_FREE(pcs, npcs); exit(rc); } /* replace all items in the list with PMIX_RANK_WILDCARD rank by real ranks to get their * data. */ pmix_proc_t *ranks; size_t nranks; PMIX_LIST_FOREACH_SAFE (p, next, desc->participants, participant_t) { if (PMIX_RANK_WILDCARD == p->proc.rank) { rc = get_all_ranks_from_namespace(params, p->proc.nspace, &ranks, &nranks); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: Can't parse --ns-dist value in order to get ranks for " "namespace %s", my_nspace, my_rank, p->proc.nspace)); PMIX_LIST_DESTRUCT(&test_fences); exit(PMIX_ERROR); } pmix_list_remove_item(desc->participants, (pmix_list_item_t *) p); for (i = 0; i < nranks; i++) { participant_t *prt; prt = PMIX_NEW(participant_t); PMIX_LOAD_PROCID(&prt->proc, ranks[i].nspace, ranks[i].rank); pmix_list_append(desc->participants, &prt->super); } PMIX_PROC_FREE(ranks, nranks); } } /* get data from all participating in this fence clients */ PMIX_LIST_FOREACH (p, desc->participants, participant_t) { put_ind = 0; snprintf(sval, 500, "%d:%s:%d", fence_num, p->proc.nspace, p->proc.rank); GET(string, sval, p->proc.nspace, p->proc.rank, fence_num, put_ind++, params.use_same_keys, 1, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Get failed (%s) from %s:%d", my_nspace, my_rank, PMIx_Error_string(rc), p->proc.nspace, p->proc.rank)); PMIX_PROC_FREE(pcs, npcs); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } GET(int, (int) (fence_num + p->proc.rank), p->proc.nspace, p->proc.rank, fence_num, put_ind++, params.use_same_keys, 0, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Get failed (%d) from %s:%d", my_nspace, my_rank, rc, p->proc.nspace, p->proc.rank)); PMIX_PROC_FREE(pcs, npcs); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } GET(float, fence_num + 1.1, p->proc.nspace, p->proc.rank, fence_num, put_ind++, params.use_same_keys, 1, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Get failed (%d) from %s:%d", my_nspace, my_rank, rc, p->proc.nspace, p->proc.rank)); PMIX_PROC_FREE(pcs, npcs); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } GET(uint32_t, (uint32_t) fence_num + 14, p->proc.nspace, p->proc.rank, fence_num, put_ind++, params.use_same_keys, 0, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Get failed (%d) from %s:%d", my_nspace, my_rank, rc, p->proc.nspace, p->proc.rank)); PMIX_PROC_FREE(pcs, npcs); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } GET(uint16_t, fence_num + 15, p->proc.nspace, p->proc.rank, fence_num, put_ind++, params.use_same_keys, 1, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Get failed (%d) from %s:%d", my_nspace, my_rank, rc, p->proc.nspace, p->proc.rank)); PMIX_PROC_FREE(pcs, npcs); PMIX_LIST_DESTRUCT(&test_fences); exit(rc); } } /* barrier across participating processes to prevent putting new values with the same * key before finishing data exchange with other processes. */ FENCE(1, 0, pcs, npcs); PMIX_PROC_FREE(pcs, npcs); } fence_num++; } PMIX_LIST_DESTRUCT(&test_fences); return PMIX_SUCCESS; } static int get_local_peers(char *my_nspace, int my_rank, pmix_rank_t **_peers, pmix_rank_t *count) { pmix_value_t *val; pmix_rank_t *peers = NULL; char *sptr, *token, *eptr, *str; pmix_rank_t npeers; int rc; pmix_proc_t proc; pmix_strncpy(proc.nspace, my_nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; /* get number of neighbors on this node */ if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_LOCAL_SIZE, NULL, 0, &val))) { TEST_ERROR(("%s:%d: PMIx_Get local peer # failed: %d", my_nspace, my_rank, rc)); exit(rc); } if (NULL == val) { TEST_ERROR(("%s:%d: PMIx_Get local peer # returned NULL value", my_nspace, my_rank)); exit(PMIX_ERROR); } if (val->type != PMIX_UINT32) { TEST_ERROR(("%s:%d: local peer # attribute value type mismatch," " want %d get %d", my_nspace, my_rank, PMIX_UINT32, val->type)); exit(PMIX_ERROR); } npeers = val->data.uint32; peers = malloc(sizeof(pmix_rank_t) * npeers); /* get ranks of neighbors on this node */ if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_LOCAL_PEERS, NULL, 0, &val))) { TEST_ERROR(("%s:%d: PMIx_Get local peers failed: %d", my_nspace, my_rank, rc)); free(peers); exit(rc); } if (NULL == val) { TEST_ERROR(("%s:%d: PMIx_Get local peers returned NULL value", my_nspace, my_rank)); free(peers); exit(PMIX_ERROR); } if (val->type != PMIX_STRING) { TEST_ERROR(("%s:%d: local peers attribute value type mismatch," " want %d get %s(%d)", my_nspace, my_rank, PMIX_UINT32, PMIx_Data_type_string(val->type), val->type)); free(peers); exit(PMIX_ERROR); } *count = 0; sptr = NULL; str = val->data.string; do { if (*count > npeers) { TEST_ERROR(("%s:%d: Bad peer ranks number: should be %d, actual %d (%s)", my_nspace, my_rank, npeers, *count, val->data.string)); free(peers); exit(PMIX_ERROR); } token = strtok_r(str, ",", &sptr); str = NULL; if (NULL != token) { peers[(*count)++] = strtol(token, &eptr, 10); if (*eptr != '\0') { TEST_ERROR(("%s:%d: Bad peer ranks string", my_nspace, my_rank)); free(peers); exit(PMIX_ERROR); } } } while (NULL != token); if (*count != npeers) { TEST_ERROR(("%s:%d: Bad peer ranks number: should be %d, actual %d (%s)", my_nspace, my_rank, npeers, *count, val->data.string)); free(peers); exit(PMIX_ERROR); } *_peers = peers; return PMIX_SUCCESS; } int test_job_fence(test_params params, char *my_nspace, pmix_rank_t my_rank) { int rc; int i, j; char sval[50]; pmix_rank_t *peers, npeers; pmix_value_t value; pmix_value_t *val = &value; pmix_proc_t proc; pmix_info_t info; pmix_strncpy(proc.nspace, my_nspace, PMIX_MAX_NSLEN); proc.rank = my_rank; for (i = 0; i < 3; i++) { PUT(int, 12340 + i, PMIX_LOCAL, 100, i, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc)); exit(rc); } (void) snprintf(sval, 50, "%s:%d", my_nspace, my_rank); PUT(string, sval, PMIX_REMOTE, 101, i, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc)); exit(PMIX_ERROR); } PUT(float, (float) 12.15 + i, PMIX_GLOBAL, 102, i, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc)); exit(PMIX_ERROR); } } /* Submit the data */ if (PMIX_SUCCESS != (rc = PMIx_Commit())) { TEST_ERROR(("%s:%d: PMIx_Commit failed: %d", my_nspace, my_rank, rc)); exit(PMIX_ERROR); } /* Perform a fence if was requested */ FENCE(!params.nonblocking, params.collect, NULL, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Fence failed: %d", my_nspace, my_rank, rc)); exit(rc); } if (PMIX_SUCCESS != (rc = get_local_peers(my_nspace, my_rank, &peers, &npeers))) { exit(rc); } /* Check the predefined output */ for (i = 0; i < (int) params.ns_size; i++) { for (j = 0; j < 3; j++) { int local = 0; pmix_rank_t k; for (k = 0; k < npeers; k++) { if (peers[k] == i + params.base_rank) { local = 1; break; } } if (local) { GET(int, (12340 + j), my_nspace, i + params.base_rank, 100, j, 0, 0, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR( ("%s:%d: PMIx_Get failed: %s", my_nspace, my_rank, PMIx_Error_string(rc))); exit(rc); } snprintf(sval, 50, "%s:%d", my_nspace, i + params.base_rank); GET(string, sval, my_nspace, i + params.base_rank, 101, j, 0, 1, 1); if (PMIX_SUCCESS == rc && (i + params.base_rank) != my_rank) { TEST_ERROR(("%s:%d: PMIx_Get of remote key on local proc", my_nspace, my_rank)); exit(PMIX_ERROR); } } else { GET(int, (12340 + j), my_nspace, i + params.base_rank, 100, j, 0, 0, 1); if (PMIX_SUCCESS == rc && (i + params.base_rank) != my_rank) { TEST_ERROR( ("%s:%d: PMIx_Get of local key on the remote proc", my_nspace, my_rank)); exit(PMIX_ERROR); } snprintf(sval, 50, "%s:%d", my_nspace, i + params.base_rank); GET(string, sval, my_nspace, i + params.base_rank, 101, j, 0, 1, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Get failed (%d)", my_nspace, my_rank, rc)); exit(PMIX_ERROR); } } GET(float, (float) 12.15 + j, my_nspace, i + params.base_rank, 102, j, 0, 0, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Get failed (%d)", my_nspace, my_rank, rc)); exit(PMIX_ERROR); } } cleanout: TEST_VERBOSE(("%s:%d: rank %d is OK", my_nspace, my_rank, i + params.base_rank)); } /* ask for a non-existent key */ if (0 == my_rank) { proc.rank = 1 + params.base_rank; j = 1; PMIX_INFO_LOAD(&info, PMIX_TIMEOUT, &j, PMIX_INT); PMIX_INFO_REQUIRED(&info); if (PMIX_SUCCESS == (rc = PMIx_Get(&proc, "foobar", &info, 1, &val))) { TEST_ERROR(("%s:%d: PMIx_Get returned success instead of failure", my_nspace, my_rank)); exit(PMIX_ERROR); } if (PMIX_ERR_NOT_SUPPORTED == rc) { goto cleanout; } if (PMIX_ERR_NOT_FOUND != rc && PMIX_ERR_TIMEOUT != rc) { TEST_ERROR(("%s:%d [ERROR]: PMIx_Get returned %s instead of not_found or timeout", my_nspace, my_rank, PMIx_Error_string(rc))); exit(PMIX_ERROR); } if (NULL != val) { TEST_ERROR(("%s:%d [ERROR]: PMIx_Get did not return NULL value", my_nspace, my_rank)); exit(PMIX_ERROR); } } free(peers); return PMIX_SUCCESS; } pmix-6.1.1~rc2/test/cli_stages.c0000664000175000017500000001516715203536752016747 0ustar alastairalastair/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "cli_stages.h" cli_info_t *cli_info = NULL; int cli_info_cnt = 0; bool test_abort = false; bool test_complete = false; int cli_rank(cli_info_t *cli) { int i; for (i = 0; i < cli_info_cnt; i++) { if (cli == &cli_info[i]) { return cli->rank; } } return -1; } void cli_init(int nprocs) { int n, i; cli_state_t order[CLI_TERM + 1]; cli_info = malloc(sizeof(cli_info_t) * nprocs); cli_info_cnt = nprocs; order[CLI_UNINIT] = CLI_FORKED; order[CLI_FORKED] = CLI_FIN; order[CLI_CONNECTED] = CLI_UNDEF; order[CLI_FIN] = CLI_TERM; order[CLI_DISCONN] = CLI_UNDEF; order[CLI_TERM] = CLI_UNDEF; for (n = 0; n < nprocs; n++) { cli_info[n].sd = -1; cli_info[n].ev = NULL; cli_info[n].pid = -1; cli_info[n].state = CLI_UNINIT; PMIX_CONSTRUCT(&(cli_info[n].modex), pmix_list_t); for (i = 0; i < CLI_TERM + 1; i++) { cli_info[n].next_state[i] = order[i]; } cli_info[n].rank = -1; cli_info[n].ns = NULL; } } void cli_connect(cli_info_t *cli, int sd, pmix_event_base_t *ebase, event_callback_fn callback) { if (CLI_CONNECTED != cli->next_state[cli->state]) { TEST_ERROR(("Rank %d has bad next state: expect %d have %d!", cli_rank(cli), CLI_CONNECTED, cli->next_state[cli->state])); test_abort = true; return; } cli->sd = sd; cli->ev = pmix_event_new(ebase, sd, EV_READ | EV_PERSIST, callback, cli); pmix_event_add(cli->ev, NULL); pmix_ptl_base_set_nonblocking(sd); TEST_VERBOSE(("Connection accepted from rank %d", cli_rank(cli))); cli->state = CLI_CONNECTED; } void cli_finalize(cli_info_t *cli) { if (CLI_FIN != cli->next_state[cli->state]) { TEST_ERROR(("rank %d: bad client next state: expect %d have %d!", cli_rank(cli), CLI_FIN, cli->next_state[cli->state])); test_abort = true; } cli->state = CLI_FIN; } void cli_disconnect(cli_info_t *cli) { if (CLI_DISCONN != cli->next_state[cli->state]) { TEST_ERROR(("rank %d: bad client next state: expect %d have %d!", cli_rank(cli), CLI_DISCONN, cli->next_state[cli->state])); test_abort = true; } if (0 > cli->sd) { TEST_ERROR(("Bad sd = %d of rank = %d ", cli->sd, cli_rank(cli))); test_abort = true; } else { TEST_VERBOSE(("close sd = %d for rank = %d", cli->sd, cli_rank(cli))); close(cli->sd); cli->sd = -1; } if (NULL == cli->ev) { TEST_ERROR(("Bad ev = NULL of rank = %d ", cli_rank(cli))); test_abort = true; } else { TEST_VERBOSE(("remove event of rank %d from event queue", cli_rank(cli))); pmix_event_del(cli->ev); pmix_event_free(cli->ev); cli->ev = NULL; } TEST_VERBOSE(("Destruct modex list for the rank %d", cli_rank(cli))); PMIX_LIST_DESTRUCT(&(cli->modex)); cli->state = CLI_DISCONN; } void cli_terminate(cli_info_t *cli) { if (CLI_TERM != cli->next_state[cli->state]) { TEST_ERROR(("rank %d: bad client next state: expect %d have %d!", cli_rank(cli), CLI_TERM, cli->next_state[cli->state])); test_abort = true; } cli->pid = -1; TEST_VERBOSE(("Client rank = %d terminated", cli_rank(cli))); cli->state = CLI_TERM; if (NULL != cli->ns) { free(cli->ns); } } void cli_cleanup(cli_info_t *cli) { if (CLI_TERM < cli->state) { TEST_ERROR(("Bad rank %d state %d", cli_rank(cli), cli->state)); test_abort = true; return; } switch (cli->next_state[cli->state]) { case CLI_FORKED: break; case CLI_CONNECTED: /* error - means that process terminated w/o calling finalize */ if (!test_abort) { TEST_ERROR( ("rank %d with state %d unexpectedly terminated.", cli_rank(cli), cli->state)); } cli->state = CLI_TERM; test_abort = true; break; case CLI_FIN: /* error - means that process terminated w/o calling finalize */ if (!test_abort) { TEST_ERROR( ("rank %d with state %d unexpectedly terminated.", cli_rank(cli), cli->state)); } cli_finalize(cli); cli_cleanup(cli); test_abort = true; break; case CLI_DISCONN: cli_disconnect(cli); cli_cleanup(cli); break; case CLI_TERM: cli_terminate(cli); break; default: TEST_ERROR(("Bad rank %d next state %d", cli_rank(cli), cli->next_state[cli->state])); test_abort = true; return; } } void cli_kill_all(void) { int i; for (i = 0; i < cli_info_cnt; i++) { if (CLI_UNINIT == cli_info[i].state) { TEST_ERROR(("Skip rank %d as it wasn't ever initialized (shouldn't happe)", i)); continue; } else if (CLI_TERM <= cli_info[i].state) { TEST_VERBOSE(("Skip rank %d as it was already terminated.", i)); continue; } TEST_VERBOSE(("Kill rank %d (pid = %d).", i, cli_info[i].pid)); kill(cli_info[i].pid, SIGKILL); cli_cleanup(&cli_info[i]); } } void errhandler(size_t evhdlr_registration_id, pmix_status_t status, const pmix_proc_t *source, pmix_info_t info[], size_t ninfo, pmix_info_t results[], size_t nresults, pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(evhdlr_registration_id, info, ninfo, results, nresults); TEST_ERROR((" PMIX server event handler for %s:%d with status = %d", source->nspace, source->rank, status)); cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata); } void op_callbk(pmix_status_t status, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(cbdata); TEST_VERBOSE(("OP CALLBACK CALLED WITH STATUS %d", status)); } void errhandler_reg_callbk(pmix_status_t status, size_t errhandler_ref, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(cbdata); TEST_VERBOSE(("ERRHANDLER REGISTRATION CALLBACK CALLED WITH STATUS %d, ref=%lu", status, (unsigned long) errhandler_ref)); } pmix-6.1.1~rc2/test/run_tests12.pl.in0000777000175000017500000000000015203536752022572 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/run_tests01.pl.in0000777000175000017500000000000015203536752022570 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/run_tests09.pl.in0000777000175000017500000000000015203536752022600 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/run_tests04.pl.in0000777000175000017500000000000015203536752022573 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/run_tests.pl.in0000775000175000017500000000575715203536752017465 0ustar alastairalastair#!/usr/bin/env perl # # Copyright (c) 2019-2020 Intel, Inc. All rights reserved. # # Copyright (c) 2019 Cisco Systems, Inc. All rights reserved # $COPYRIGHT$ # # Additional copyrights may follow use strict; my @tests = ("-n 4 --ns-dist 3:1 --fence \"[db | 0:0-2;1:0]\"", "-n 4 --ns-dist 3:1 --fence \"[db | 0:;1:0]\"", "-n 4 --ns-dist 3:1 --fence \"[db | 0:;1:]\"", "-n 4 --ns-dist 3:1 --fence \"[0:]\"", "-n 4 --ns-dist 3:1 --fence \"[b | 0:]\"", "-n 4 --ns-dist 3:1 --fence \"[d | 0:]\" --noise \"[0:0,1]\"", "-n 4 --job-fence -c", "-n 4 --job-fence", "-n 2 --test-publish", "-n 2 --test-spawn", "-n 2 --test-connect", "-n 5 --test-resolve-peers --ns-dist \"1:2:2\"", "-n 5 --test-replace 100:0,1,10,50,99", "-n 5 --test-internal 10", "-s 1 -n 2 --job-fence", "-s 1 -n 2 --job-fence -c"); # "-s 2 -n 2 --job-fence", # "-s 2 -n 2 --job-fence -c"); my $test; my $cmd; my $output; my $status = 0; my $testnum; my $timeout_cmd = ""; # We are running tests against the build tree (vs. the installation # tree). Autogen gives us a full list of all possible component # directories in PMIX_COMPONENT_LIBRARY_PATHS. Iterate through each # of those directories: 1) to see if there is actually a component # built in there, and 2) to turn it into an absolute path name. Then # put the new list in the "mca_bast_component_path" MCA parameter env # variable so that the MCA base knows where to find all the # components. my @myfullpaths; my $mybuilddir = "@PMIX_BUILT_TEST_PREFIX@"; my $mypathstr = "@PMIX_COMPONENT_LIBRARY_PATHS@"; my @splitstr = split(':', $mypathstr); foreach my $path (@splitstr) { # Note that the component is actually built in the ".libs" # subdirectory. If the component wasn't built, that subdirectory # will not exist, so don't save it. my $fullpath = $mybuilddir . "/" . $path . "/.libs"; push(@myfullpaths, $fullpath) if (-d $fullpath); } my $mymcapaths = join(":", @myfullpaths); $ENV{'PMIX_MCA_mca_base_component_path'} = $mymcapaths; my $wdir = $mybuilddir . "/test"; chdir $wdir; $testnum = $0; $testnum =~ s/.pl//; $testnum = substr($testnum, -2); $test = @tests[$testnum]; # find the timeout or gtimeout cmd so we can timeout the # test if it hangs my @paths = split(/:/, $ENV{PATH}); foreach my $p (@paths) { my $fullpath = $p . "/" . "gtimeout"; if ((-e $fullpath) && (-f $fullpath)) { $timeout_cmd = $fullpath . " --preserve-status -k 500 450 "; last; } else { my $fullpath = $p . "/" . "timeout"; if ((-e $fullpath) && (-f $fullpath)) { $timeout_cmd = $fullpath . " --preserve-status -k 500 450 "; last; } } } $cmd = $timeout_cmd . " ./pmix_test " . $test . " 2>&1"; print $cmd . "\n"; $output = `$cmd`; print $output . "\n"; print "CODE $?\n"; $status = "$?"; exit($status >> 8); pmix-6.1.1~rc2/test/utils.h0000664000175000017500000000101615203536752015763 0ustar alastairalastair/* * Copyright (c) 2015 Intel, Inc. All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/util/pmix_argv.h" #include "test_common.h" #include #include #include #include #include void set_client_argv(test_params *params, char ***argv); pmix-6.1.1~rc2/test/test_resolve_peers.h0000664000175000017500000000063015203536752020540 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "test_common.h" int test_resolve_peers(char *my_nspace, int my_rank, test_params params); pmix-6.1.1~rc2/test/test_publish.c0000664000175000017500000001446615203536752017340 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "test_publish.h" #include "src/include/pmix_globals.h" #include typedef struct { int in_progress; size_t npdata; pmix_pdata_t *pdata; } lookup_cbdata; static void release_cb(pmix_status_t status, void *cbdata) { int *ptr = (int *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); *ptr = 0; } static void lookup_cb(pmix_status_t status, pmix_pdata_t pdata[], size_t npdata, void *cbdata) { size_t i, j; lookup_cbdata *cb = (lookup_cbdata *) cbdata; pmix_pdata_t *tgt = cb->pdata; PMIX_HIDE_UNUSED_PARAMS(status); /* find the matching key in the provided info array - error if not found */ for (i = 0; i < npdata; i++) { for (j = 0; j < cb->npdata; j++) { if (0 == strcmp(pdata[i].key, tgt[j].key)) { /* transfer the value to the pmix_pdata_t */ pmix_strncpy(tgt[j].proc.nspace, pdata[i].proc.nspace, PMIX_MAX_NSLEN); tgt[j].proc.rank = pdata[i].proc.rank; PMIx_Value_xfer(&tgt[j].value, &pdata[i].value); break; } } } cb->in_progress = 0; } static int test_publish(char *my_nspace, int my_rank, int blocking) { int rc; pmix_info_t info; char data[512]; PMIX_INFO_CONSTRUCT(&info); (void) snprintf(info.key, PMIX_MAX_KEYLEN, "%s:%d", my_nspace, my_rank); (void) snprintf(data, 512, "data from proc %s:%d", my_nspace, my_rank); info.value.type = PMIX_STRING; info.value.data.string = strdup(data); if (blocking) { rc = PMIx_Publish(&info, 1); } else { int in_progress = 1; rc = PMIx_Publish_nb(&info, 1, release_cb, &in_progress); if (PMIX_SUCCESS == rc) { PMIX_WAIT_FOR_COMPLETION(in_progress); } } PMIX_INFO_DESTRUCT(&info); return rc; } static int test_lookup(char *my_nspace, int my_rank, int blocking) { int rc; pmix_pdata_t pdata; char data[512]; char *keys[2]; PMIX_PDATA_CONSTRUCT(&pdata); (void) snprintf(pdata.key, PMIX_MAX_KEYLEN, "%s:%d", my_nspace, my_rank); (void) snprintf(data, 512, "data from proc %s:%d", my_nspace, my_rank); if (blocking) { if (PMIX_SUCCESS != (rc = PMIx_Lookup(&pdata, 1, NULL, 0))) { PMIX_PDATA_DESTRUCT(&pdata); return rc; } } else { keys[0] = (char *) malloc(PMIX_MAX_KEYLEN * sizeof(char)); (void) snprintf(keys[0], PMIX_MAX_KEYLEN, "%s:%d", my_nspace, my_rank); keys[1] = NULL; lookup_cbdata cbdata; cbdata.in_progress = 1; cbdata.npdata = 1; cbdata.pdata = &pdata; /* copy the key across */ pmix_strncpy(pdata.key, keys[0], PMIX_MAX_KEYLEN); rc = PMIx_Lookup_nb(keys, NULL, 0, lookup_cb, (void *) &cbdata); if (PMIX_SUCCESS != rc) { PMIX_PDATA_DESTRUCT(&pdata); return rc; } PMIX_WAIT_FOR_COMPLETION(cbdata.in_progress); } if (PMIX_STRING != pdata.value.type || NULL == pdata.value.data.string) { PMIX_PDATA_DESTRUCT(&pdata); return PMIX_ERR_NOT_FOUND; } if (strncmp(data, pdata.value.data.string, strlen(data))) { PMIX_PDATA_DESTRUCT(&pdata); return PMIX_ERR_NOT_FOUND; } PMIX_PDATA_DESTRUCT(&pdata); return rc; } static int test_unpublish(char *my_nspace, int my_rank, int blocking) { int rc; char *keys[2]; keys[0] = (char *) malloc(PMIX_MAX_KEYLEN * sizeof(char)); (void) snprintf(keys[0], PMIX_MAX_KEYLEN, "%s:%d", my_nspace, my_rank); keys[1] = NULL; if (blocking) { rc = PMIx_Unpublish(keys, NULL, 0); } else { int in_progress = 1; rc = PMIx_Unpublish_nb(keys, NULL, 0, release_cb, &in_progress); if (PMIX_SUCCESS == rc) { PMIX_WAIT_FOR_COMPLETION(in_progress); } } free(keys[0]); return rc; } static int test_publish_lookup_common(char *my_nspace, int my_rank, int blocking) { int rc; rc = test_publish(my_nspace, my_rank, blocking); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: %s failed.", my_nspace, my_rank, blocking ? "PMIX_Publish" : "PMIX_Publish_nb")); exit(rc); } TEST_VERBOSE(("%s:%d: %s succeeded.", my_nspace, my_rank, blocking ? "PMIX_Publish" : "PMIX_Publish_nb")); rc = test_lookup(my_nspace, my_rank, blocking); if (PMIX_SUCCESS != rc) { TEST_ERROR( ("%s:%d: %s failed.", my_nspace, my_rank, blocking ? "PMIX_Lookup" : "PMIX_Lookup_nb")); exit(rc); } TEST_VERBOSE(("%s:%d: %s succeeded.\n", my_nspace, my_rank, blocking ? "PMIX_Lookup" : "PMIX_Lookup_nb")); rc = test_unpublish(my_nspace, my_rank, blocking); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: %s failed.", my_nspace, my_rank, blocking ? "PMIX_Unpublish" : "PMIX_Unpublish_nb")); exit(rc); } TEST_VERBOSE(("%s:%d: %s succeeded.", my_nspace, my_rank, blocking ? "PMIX_Unpublish" : "PMIX_Unpublish_nb")); rc = test_lookup(my_nspace, my_rank, blocking); if (PMIX_ERR_NOT_FOUND != rc) { TEST_ERROR(("%s:%d: %s function returned %d instead of PMIX_ERR_NOT_FOUND.", my_nspace, my_rank, blocking ? "PMIX_Lookup" : "PMIX_Lookup_nb", rc)); exit(rc); } TEST_VERBOSE( ("%s:%d: %s succeeded.", my_nspace, my_rank, blocking ? "PMIX_Lookup of non-existent key" : "PMIX_Lookup_nb of non-existent key")); return PMIX_SUCCESS; } int test_publish_lookup(char *my_nspace, int my_rank) { int rc; /* test blocking */ rc = test_publish_lookup_common(my_nspace, my_rank, 1); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: Publish/Lookup blocking test failed.", my_nspace, my_rank)); exit(rc); } /* test non-blocking */ rc = test_publish_lookup_common(my_nspace, my_rank, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: Publish/Lookup non-blocking test failed.", my_nspace, my_rank)); exit(rc); } return PMIX_SUCCESS; } pmix-6.1.1~rc2/test/pmix_client.c0000664000175000017500000002301115203536752017130 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include #include #include #include #include "src/class/pmix_object.h" #include "test_cd.h" #include "test_common.h" #include "test_error.h" #include "test_fence.h" #include "test_internal.h" #include "test_publish.h" #include "test_replace.h" #include "test_resolve_peers.h" #include "test_spawn.h" int main(int argc, char **argv) { int rc; pmix_value_t value; pmix_value_t *val = &value; test_params params; INIT_TEST_PARAMS(params); pmix_proc_t myproc, proc; parse_cmd(argc, argv, ¶ms); // We don't know rank at this place! TEST_VERBOSE(("Client %s:%d started PID:%d", params.nspace, params.rank, getpid())); /* handle early-fail test case */ if (1 == params.early_fail && 0 == params.rank) { exit(1); } /* init us */ pmix_info_t info[1]; size_t ninfo = 0; if (NULL != params.gds_mode) { pmix_strncpy(info[0].key, PMIX_GDS_MODULE, PMIX_MAX_KEYLEN); info[0].value.type = PMIX_STRING; info[0].value.data.string = strdup(params.gds_mode); ninfo = 1; } if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, info, ninfo))) { TEST_ERROR(("Client ns %s rank %d: PMIx_Init failed: %s", params.nspace, params.rank, PMIx_Error_string(rc))); FREE_TEST_PARAMS(params); exit(rc); } if (myproc.rank != params.rank) { TEST_ERROR(("Client ns %s Rank returned in PMIx_Init %d does not match to rank from " "command line %d.", myproc.nspace, myproc.rank, params.rank)); FREE_TEST_PARAMS(params); exit(1); } if (NULL != params.prefix && -1 != params.ns_id) { TEST_SET_FILE(params.prefix, params.ns_id, params.rank); } TEST_VERBOSE((" Client ns %s rank %d: PMIx_Init success", myproc.nspace, myproc.rank)); PMIX_LOAD_PROCID(&proc, myproc.nspace, PMIX_RANK_WILDCARD); if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_UNIV_SIZE, NULL, 0, &val))) { TEST_ERROR( ("rank %d: PMIx_Get universe size failed: %s", myproc.rank, PMIx_Error_string(rc))); FREE_TEST_PARAMS(params); exit(rc); } if (NULL == val) { TEST_ERROR(("rank %d: PMIx_Get universe size returned NULL value", myproc.rank)); FREE_TEST_PARAMS(params); exit(1); } if (val->type != PMIX_UINT32 || val->data.uint32 != (uint32_t) params.ns_size) { TEST_ERROR(("rank %d: Universe size value or type mismatch," " want %d(%d) get %d(%d)", myproc.rank, params.ns_size, PMIX_UINT32, val->data.integer, val->type)); FREE_TEST_PARAMS(params); exit(1); } TEST_VERBOSE(("rank %d: Universe size check: PASSED", myproc.rank)); if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_HOSTNAME, NULL, 0, &val))) { TEST_ERROR(("rank %d: PMIx_Get hostname failed: %s", myproc.rank, PMIx_Error_string(rc))); FREE_TEST_PARAMS(params); exit(rc); } if (NULL == val) { TEST_ERROR(("rank %d: PMIx_Get hostname returned NULL value", myproc.rank)); FREE_TEST_PARAMS(params); exit(1); } if (val->type != PMIX_STRING) { TEST_ERROR( ("rank %d: Hostname type mismatch: %s", myproc.rank, PMIx_Data_type_string(val->type))); FREE_TEST_PARAMS(params); exit(1); } TEST_VERBOSE(("rank %d: Hostname check: PASSED", myproc.rank)); if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_NODEID, NULL, 0, &val))) { TEST_ERROR(("rank %d: PMIx_Get nodeid failed: %s", myproc.rank, PMIx_Error_string(rc))); FREE_TEST_PARAMS(params); exit(rc); } if (NULL == val) { TEST_ERROR(("rank %d: PMIx_Get nodeid returned NULL value", myproc.rank)); FREE_TEST_PARAMS(params); exit(1); } if (val->type != PMIX_UINT32) { TEST_ERROR( ("rank %d: NodeID type mismatch: %s", myproc.rank, PMIx_Data_type_string(val->type))); FREE_TEST_PARAMS(params); exit(1); } TEST_VERBOSE(("rank %d: NodeID check: PASSED", myproc.rank)); if (NULL != params.nspace && 0 != strcmp(myproc.nspace, params.nspace)) { TEST_ERROR(("rank %d: Bad nspace!", myproc.rank)); FREE_TEST_PARAMS(params); exit(1); } if (NULL != params.fences) { rc = test_fence(params, myproc.nspace, myproc.rank); if (PMIX_SUCCESS != rc) { FREE_TEST_PARAMS(params); TEST_ERROR( ("%s:%d Fence test failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc))); exit(rc); } } if (0 != params.test_job_fence) { rc = test_job_fence(params, myproc.nspace, myproc.rank); if (PMIX_SUCCESS != rc) { FREE_TEST_PARAMS(params); TEST_ERROR(("%s:%d Job fence test failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc))); exit(rc); } } if (0 != params.test_publish) { rc = test_publish_lookup(myproc.nspace, myproc.rank); if (PMIX_SUCCESS != rc) { FREE_TEST_PARAMS(params); TEST_ERROR(("%s:%d Publish/Lookup test failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc))); exit(rc); } } if (0 != params.test_spawn) { rc = test_spawn(myproc.nspace, myproc.rank); if (PMIX_SUCCESS != rc) { FREE_TEST_PARAMS(params); TEST_ERROR( ("%s:%d Spawn test failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc))); exit(rc); } } if (0 != params.test_connect) { rc = test_connect_disconnect(myproc.nspace, myproc.rank); if (PMIX_SUCCESS != rc) { FREE_TEST_PARAMS(params); TEST_ERROR(("%s:%d Connect/Disconnect test failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc))); exit(rc); } } if (0 != params.test_resolve_peers) { rc = test_resolve_peers(myproc.nspace, myproc.rank, params); if (PMIX_SUCCESS != rc) { FREE_TEST_PARAMS(params); TEST_ERROR(("%s:%d Resolve peers test failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc))); exit(rc); } } if (0 != params.test_error) { rc = test_error(myproc.nspace, myproc.rank, params); if (PMIX_SUCCESS != rc) { FREE_TEST_PARAMS(params); TEST_ERROR(("%s:%d error registration and event handling test failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc))); exit(rc); } } if (NULL != params.key_replace) { rc = test_replace(myproc.nspace, myproc.rank, params); if (PMIX_SUCCESS != rc) { FREE_TEST_PARAMS(params); TEST_ERROR(("%s:%d error key replace test failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc))); exit(rc); } } if (params.test_internal) { rc = test_internal(myproc.nspace, myproc.rank, params); if (PMIX_SUCCESS != rc) { FREE_TEST_PARAMS(params); TEST_ERROR(("%s:%d error key store internal test failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc))); exit(rc); } } TEST_VERBOSE(("Client ns %s rank %d: PASSED", myproc.nspace, myproc.rank)); /* In case of direct modex we want to delay Finalize until everybody has finished. Otherwise some processes will fail to get data from others who already exited */ PMIx_Fence(NULL, 0, NULL, 0); /* finalize us */ TEST_VERBOSE(("Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank)); if (PMIX_SUCCESS != (rc = PMIx_Finalize(NULL, 0))) { TEST_ERROR(("Client ns %s rank %d:PMIx_Finalize failed: %s", myproc.nspace, myproc.rank, PMIx_Error_string(rc))); exit(rc); } else { TEST_VERBOSE(("Client ns %s rank %d:PMIx_Finalize successfully completed", myproc.nspace, myproc.rank)); } TEST_VERBOSE(("Client %s:%d finished PID:%d", params.nspace, params.rank, getpid())); TEST_OUTPUT_CLEAR(("OK\n")); TEST_CLOSE_FILE(); FREE_TEST_PARAMS(params); exit(0); } pmix-6.1.1~rc2/test/pmix_environ.c0000664000175000017500000001635515203536752017347 0ustar alastairalastair/* * Copyright (c) 2022 Amazon.com, Inc. or its affiliates. * All Rights reserved. * Copyright (c) 2022-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include #include #include "src/include/pmix_globals.h" #include "src/util/pmix_environ.h" #include "src/util/pmix_argv.h" int main(int argc, char *argv[]) { char **test_array; char **new_array; const char *tmp; pmix_status_t ret; int ret_int; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* * mess with environ */ /* first test: does overwrite work? */ ret = PMIx_Setenv("pmix_environ_test_string_3", "three", true, &environ); if (ret != PMIX_SUCCESS) { printf("PMIx_Setenv returned %d\n", ret); return 1; } ret = PMIx_Setenv("pmix_environ_test_string_3", "four", false, &environ); if (ret != PMIX_SUCCESS) { printf("PMIx_Setenv returned %d\n", ret); return 1; } tmp = getenv("pmix_environ_test_string_3"); if (NULL == tmp) { printf("could not getenv(\"pmix_environ_test_string_3\")\n"); return 1; } if (strcmp(tmp, "three") != 0) { printf("PMIx_Setenv overwrote. Found %s expected %s\n", tmp, "three"); return 1; } ret = PMIx_Setenv("pmix_environ_test_string_3", "four", true, &environ); if (ret != PMIX_SUCCESS) { printf("PMIx_Setenv returned %d\n", ret); return 1; } tmp = getenv("pmix_environ_test_string_3"); if (NULL == tmp) { printf("could not getenv(\"pmix_environ_test_string_3\")\n"); return 1; } if (strcmp(tmp, "four") != 0) { printf("PMIx_Setenv overwrote. Found %s expected %s\n", tmp, "four"); return 1; } /* second test: do we handle environ properly in unsetenv */ ret_int = putenv("pmix_environ_test_string_1=one"); if (ret_int != 0) { printf("putenv() returned %d\n", ret_int); return 1; } ret_int = setenv("pmix_environ_test_string_2", "two", true); if (ret_int != 0) { printf("setenv() returned %d\n", ret_int); return 1; } ret = PMIx_Setenv("pmix_environ_test_string_3", "three", true, &environ); if (ret != PMIX_SUCCESS) { printf("PMIx_Setenv returned %d\n", ret); return 1; } ret = pmix_unsetenv("pmix_environ_test_string_1", &environ); if (ret != PMIX_SUCCESS) { printf("pmix_unsetenv returned %d\n", ret); return 1; } ret = pmix_unsetenv("pmix_environ_test_string_2", &environ); if (ret != PMIX_SUCCESS) { printf("pmix_unsetenv returned %d\n", ret); return 1; } ret = pmix_unsetenv("pmix_environ_test_string_3", &environ); if (ret != PMIX_SUCCESS) { printf("pmix_unsetenv returned %d\n", ret); return 1; } /* third test: can we merge environ into a new env. Note that the * new env is empty, so we can compare environ and newenv later * and they should match. We'll test the actual merging later * without environ as the additions, so we have more control over * the situation */ ret_int = putenv("pmix_environ_test_string_1=one"); if (ret_int != 0) { printf("putenv() returned %d\n", ret_int); return 1; } ret_int = setenv("pmix_environ_test_string_2", "two", true); if (ret_int != 0) { printf("setenv() returned %d\n", ret_int); return 1; } ret = PMIx_Setenv("pmix_environ_test_string_3", "three", true, &environ); if (ret != PMIX_SUCCESS) { printf("PMIx_Setenv returned %d\n", ret); return 1; } test_array = NULL; ret = pmix_environ_merge_inplace(&test_array, environ); if (ret != PMIX_SUCCESS) { printf("pmix_environ_merge returned %d\n", ret); return 1; } PMIx_Argv_free(test_array); /* fourth test: make sure environ_merge_inplace does. */ test_array = NULL; PMIx_Argv_append_nosize(&test_array, "pmix_environ_test_string_1=old_one"); PMIx_Argv_append_nosize(&test_array, "pmix_environ_test_string_2=old_two"); PMIx_Argv_append_nosize(&test_array, "pmix_environ_test_string_3=old_three"); PMIx_Argv_append_nosize(&test_array, "pmix_environ_test_string_4=old_four"); new_array = NULL; PMIx_Argv_append_nosize(&new_array, "pmix_environ_test_string_1=new_one"); PMIx_Argv_append_nosize(&new_array, "pmix_environ_test_string_5=new_five"); ret = pmix_environ_merge_inplace(&test_array, new_array); if (ret != PMIX_SUCCESS) { printf("pmix_environ_merge returned %d\n", ret); return 1; } if (NULL == pmix_getenv("pmix_environ_test_string_1", test_array)) { printf("new env missing string 1\n"); return 1; } if (NULL == pmix_getenv("pmix_environ_test_string_2", test_array)) { printf("new env missing string 2\n"); return 1; } if (NULL == pmix_getenv("pmix_environ_test_string_3", test_array)) { printf("new env missing string 3\n"); return 1; } if (NULL == pmix_getenv("pmix_environ_test_string_4", test_array)) { printf("new env missing string 4\n"); return 1; } if (NULL == pmix_getenv("pmix_environ_test_string_5", test_array)) { printf("new env missing string 5\n"); return 1; } tmp = pmix_getenv("pmix_environ_test_string_1", test_array); if (NULL == tmp) { printf("could not getenv(\"pmix_environ_test_string_1\")\n"); return 1; } if (strcmp("old_one", tmp) != 0) { printf("wrong value. expected %s, found %s\n", "old_one", tmp); return 1; } tmp = pmix_getenv("pmix_environ_test_string_2", test_array); if (NULL == tmp) { printf("could not getenv(\"pmix_environ_test_string_2\")\n"); return 1; } if (strcmp("old_two", tmp) != 0) { printf("wrong value. expected %s, found %s\n", "old_two", tmp); return 1; } tmp = pmix_getenv("pmix_environ_test_string_3", test_array); if (NULL == tmp) { printf("could not getenv(\"pmix_environ_test_string_3\")\n"); return 1; } if (strcmp("old_three", tmp) != 0) { printf("wrong value. expected %s, found %s\n", "old_three", tmp); return 1; } tmp = pmix_getenv("pmix_environ_test_string_4", test_array); if (NULL == tmp) { printf("could not getenv(\"pmix_environ_test_string_4\")\n"); return 1; } if (strcmp("old_four", tmp) != 0) { printf("wrong value. expected %s, found %s\n", "old_four", tmp); return 1; } tmp = pmix_getenv("pmix_environ_test_string_5", test_array); if (NULL == tmp) { printf("could not getenv(\"pmix_environ_test_string_5\")\n"); return 1; } if (strcmp("new_five", tmp) != 0) { printf("wrong value. expected %s, found %s\n", "new_five", tmp); return 1; } if (5 != PMIx_Argv_count(test_array)) { printf("test array has wrong length. found %d, expected %d\n", PMIx_Argv_count(test_array), 5); return 1; } PMIx_Argv_free(test_array); return 0; } pmix-6.1.1~rc2/test/Makefile.am0000664000175000017500000000677215203536752016524 0ustar alastairalastair# # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2009 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2006-2010 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. # Copyright (c) 2013-2020 Intel, Inc. All rights reserved. # Copyright (c) 2018 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # if !WANT_HIDDEN # these tests use internal symbols # use --disable-visibility SUBDIRS = simple sshot util if WANT_PYTHON_BINDINGS SUBDIRS += python endif endif headers = test_common.h cli_stages.h server_callbacks.h utils.h test_fence.h \ test_publish.h test_spawn.h test_cd.h test_resolve_peers.h test_error.h \ test_replace.h test_internal.h test_server.h AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_builddir)/src/include -I$(top_builddir)/src/api # we do NOT want picky compilers down here noinst_SCRIPTS = pmix_client_otheruser.sh \ run_tests00.pl \ run_tests01.pl \ run_tests02.pl \ run_tests03.pl \ run_tests04.pl \ run_tests05.pl \ run_tests06.pl \ run_tests07.pl \ run_tests08.pl \ run_tests09.pl \ run_tests10.pl \ run_tests11.pl \ run_tests12.pl \ run_tests13.pl # run_tests14.pl \ # run_tests15.pl noinst_PROGRAMS = ######################### # Support for "make check" check_PROGRAMS = \ pmix_test \ pmix_client \ pmix_regex \ pmix_environ TESTS = \ run_tests00.pl \ run_tests01.pl \ run_tests02.pl \ run_tests03.pl \ run_tests04.pl \ run_tests05.pl \ run_tests06.pl \ run_tests07.pl \ run_tests08.pl \ run_tests09.pl \ run_tests10.pl \ run_tests11.pl \ run_tests12.pl \ run_tests13.pl \ pmix_environ # run_tests14.pl \ # run_tests15.pl ########################## noinst_PROGRAMS += pmix_test pmix_client pmix_regex pmix_environ pmix_test_SOURCES = $(headers) \ pmix_test.c test_common.c cli_stages.c server_callbacks.c test_server.c utils.c pmix_test_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) pmix_test_LDADD = \ $(top_builddir)/src/libpmix.la pmix_client_SOURCES = $(headers) \ pmix_client.c test_fence.c test_common.c test_publish.c test_spawn.c \ test_cd.c test_resolve_peers.c test_error.c test_replace.c test_internal.c pmix_client_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) pmix_client_LDADD = \ $(top_builddir)/src/libpmix.la pmix_regex_SOURCES = $(headers) \ pmix_regex.c test_common.c cli_stages.c server_callbacks.c test_server.c utils.c pmix_regex_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) pmix_regex_LDADD = \ $(top_builddir)/src/libpmix.la pmix_environ_SOURCES = pmix_environ.c pmix_environ_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS) pmix_environ_LDADD = $(top_builddir)/src/libpmix.la EXTRA_DIST = $(noinst_SCRIPTS) pmix-6.1.1~rc2/test/run_tests11.pl.in0000777000175000017500000000000015203536752022571 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/test_replace.c0000664000175000017500000001003715203536752017273 0ustar alastairalastair/* * Copyright (c) 2017 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2019 Intel, Inc. All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "test_replace.h" static void release_cb(pmix_status_t status, void *cbdata) { int *ptr = (int *) cbdata; PMIX_HIDE_UNUSED_PARAMS(status); *ptr = 0; } static void get_cb(pmix_status_t status, pmix_value_t *kv, void *cbdata) { get_cbdata *cb = (get_cbdata *) cbdata; if (PMIX_SUCCESS == status) { PMIx_Value_xfer(cb->kv, kv); } cb->in_progress = 0; cb->status = status; } static int key_is_replace(int key_idx) { key_replace_t *item; PMIX_LIST_FOREACH (item, &key_replace, key_replace_t) { if (item->key_idx == key_idx) return 1; } return 0; } int test_replace(char *my_nspace, pmix_rank_t my_rank, test_params params) { int key_idx = 0; int key_cnt = 0; char sval[PMIX_MAX_NSLEN]; pmix_proc_t proc; pmix_status_t rc; key_replace_t *item; PMIX_CONSTRUCT(&key_replace, pmix_list_t); parse_replace(params.key_replace, 1, &key_cnt); for (key_idx = 0; key_idx < key_cnt; key_idx++) { memset(sval, 0, PMIX_MAX_NSLEN); snprintf(sval, PMIX_MAX_NSLEN, "test_replace:%s:%d:%d", my_nspace, my_rank, key_idx); PUT(string, sval, PMIX_GLOBAL, 0, key_idx, 1); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&key_replace); exit(rc); } } PMIX_PROC_CONSTRUCT(&proc); pmix_strncpy(proc.nspace, my_nspace, PMIX_MAX_NSLEN); proc.rank = PMIX_RANK_WILDCARD; /* Submit the data */ if (PMIX_SUCCESS != (rc = PMIx_Commit())) { TEST_ERROR(("%s:%d: PMIx_Commit failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&key_replace); PMIX_PROC_DESTRUCT(&proc); exit(rc); } FENCE(1, 1, (&proc), 1); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Fence failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&key_replace); PMIX_PROC_DESTRUCT(&proc); exit(rc); } PMIX_LIST_FOREACH (item, &key_replace, key_replace_t) { memset(sval, 0, PMIX_MAX_NSLEN); snprintf(sval, PMIX_MAX_NSLEN, "test_replace:%s:%d:%d: replaced key", my_nspace, my_rank, item->key_idx); PUT(string, sval, PMIX_GLOBAL, 0, item->key_idx, 1); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&key_replace); PMIX_PROC_DESTRUCT(&proc); exit(rc); } } /* Submit the data */ if (PMIX_SUCCESS != (rc = PMIx_Commit())) { TEST_ERROR(("%s:%d: PMIx_Commit failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&key_replace); PMIX_PROC_DESTRUCT(&proc); exit(rc); } FENCE(1, 1, (&proc), 1); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Fence failed: %d", my_nspace, my_rank, rc)); PMIX_LIST_DESTRUCT(&key_replace); PMIX_PROC_DESTRUCT(&proc); exit(rc); } for (key_idx = 0; key_idx < key_cnt; key_idx++) { memset(sval, 0, PMIX_MAX_NSLEN); if (key_is_replace(key_idx)) { snprintf(sval, PMIX_MAX_NSLEN, "test_replace:%s:%d:%d: replaced key", my_nspace, my_rank, key_idx); } else { snprintf(sval, PMIX_MAX_NSLEN, "test_replace:%s:%d:%d", my_nspace, my_rank, key_idx); } GET(string, sval, my_nspace, my_rank, 0, key_idx, 1, 1, 0); if (PMIX_SUCCESS != rc) { TEST_ERROR(("%s:%d: PMIx_Get of remote key on local proc", my_nspace, my_rank)); PMIX_LIST_DESTRUCT(&key_replace); PMIX_PROC_DESTRUCT(&proc); exit(rc); } } PMIX_LIST_DESTRUCT(&key_replace); PMIX_PROC_DESTRUCT(&proc); return PMIX_SUCCESS; } pmix-6.1.1~rc2/test/run_tests10.pl.in0000777000175000017500000000000015203536752022570 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/test_error.h0000664000175000017500000000045115203536752017015 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "src/include/pmix_config.h" #include "include/pmix.h" #include "test_common.h" int test_error(char *my_nspace, int my_rank, test_params params); pmix-6.1.1~rc2/test/run_tests06.pl.in0000777000175000017500000000000015203536752022575 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/run_tests05.pl.in0000777000175000017500000000000015203536752022574 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/test/pmix_regex.c0000664000175000017500000000740315203536752016773 0ustar alastairalastair/* * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006-2013 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2013-2017 Intel, Inc. All rights reserved. * Copyright (c) 2018 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include #include #include #include "src/mca/preg/preg.h" #include "src/server/pmix_server_ops.h" #include "src/util/pmix_argv.h" #include "src/util/pmix_output.h" #include "src/util/pmix_environ.h" #include "server_callbacks.h" #include "utils.h" #define TEST_NODES "odin001,odin002,odin003,odin010,odin011,odin075" #define TEST_PROCS "1,2,3,4;5-8;9,11-12;17-20;21-24;100" #define TEST_NODES2 "c712f6n01,c712f6n02,c712f6n03" bool spawn_wait = false; int main(int argc, char **argv) { char *regex; char **nodes, **procs; pmix_status_t rc; PMIX_HIDE_UNUSED_PARAMS(argc, argv); /* smoke test */ if (PMIX_SUCCESS != 0) { TEST_ERROR(("ERROR IN COMPUTING CONSTANTS: PMIX_SUCCESS = %d", PMIX_SUCCESS)); exit(1); } TEST_VERBOSE(("Testing version %s", PMIx_Get_version())); PMIx_server_init(&mymodule, NULL, 0); TEST_VERBOSE(("Start PMIx regex smoke test")); fprintf(stderr, "NODES: %s\n", TEST_NODES); PMIx_generate_regex(TEST_NODES, ®ex); fprintf(stderr, "REGEX: %s\n\n", regex); /* test reverse parsing */ rc = pmix_preg.parse_nodes(regex, &nodes); free(regex); if (PMIX_SUCCESS == rc) { regex = PMIx_Argv_join(nodes, ','); PMIx_Argv_free(nodes); fprintf(stderr, "NODES: %s\n", TEST_NODES); fprintf(stderr, "RSULT: %s\n\n\n", regex); free(regex); } else { fprintf(stderr, "Node reverse failed: %d\n\n\n", rc); } fprintf(stderr, "PROCS: %s\n", TEST_PROCS); PMIx_generate_ppn(TEST_PROCS, ®ex); fprintf(stderr, "PPN: %s\n\n", regex); /* test reverse parsing */ rc = pmix_preg.parse_procs(regex, &procs); free(regex); if (PMIX_SUCCESS == rc) { regex = PMIx_Argv_join(procs, ';'); PMIx_Argv_free(procs); fprintf(stderr, "PROCS: %s\n", TEST_PROCS); fprintf(stderr, "RSULT: %s\n", regex); free(regex); } else { fprintf(stderr, "PPN reverse failed: %d\n", rc); } fprintf(stderr, "NODES: %s\n", TEST_NODES2); PMIx_generate_regex(TEST_NODES2, ®ex); fprintf(stderr, "REGEX: %s\n\n", regex); /* test reverse parsing */ rc = pmix_preg.parse_nodes(regex, &nodes); free(regex); if (PMIX_SUCCESS == rc) { regex = PMIx_Argv_join(nodes, ','); PMIx_Argv_free(nodes); fprintf(stderr, "NODES: %s\n", TEST_NODES2); fprintf(stderr, "RSULT: %s\n\n\n", regex); free(regex); } else { fprintf(stderr, "Node reverse failed: %d\n\n\n", rc); } return 0; } pmix-6.1.1~rc2/test/test_common.h0000664000175000017500000005334415203536752017165 0ustar alastairalastair/* * Copyright (c) 2013-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Artem Y. Polyakov . * All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2021-2025 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #ifndef TEST_COMMON_H #define TEST_COMMON_H #include "src/include/pmix_config.h" #include "pmix_common.h" #include #include #include #include #include #include #include "src/class/pmix_list.h" #include "src/include/pmix_globals.h" #include "src/util/pmix_argv.h" #define TEST_NAMESPACE "smoky_nspace" #define TEST_CREDENTIAL "dummy" #define PMIX_WAIT_FOR_COMPLETION(m) \ do { \ while ((m)) { \ usleep(10); \ } \ } while (0) /* WARNING: pmix_test_output_prepare is currently not threadsafe! * fix it once needed! */ char *pmix_test_output_prepare(const char *fmt, ...); extern int pmix_test_verbose; extern FILE *file; #define STRIPPED_FILE_NAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define TEST_OUTPUT(x) \ { \ struct timeval _tv; \ gettimeofday(&_tv, NULL); \ double _ts = _tv.tv_sec + 1E-6 * (_tv).tv_usec; \ fprintf(file, "==%d== [%lf] %s:%s: %s\n", getpid(), _ts, STRIPPED_FILE_NAME, __func__, \ pmix_test_output_prepare x); \ fflush(file); \ } // Write output without adding anything to it. // Need for automate tests to receive "OK" string #define TEST_OUTPUT_CLEAR(x) \ { \ fprintf(file, "==%d== %s", getpid(), pmix_test_output_prepare x); \ fflush(file); \ } // Always write errors to the stderr #define TEST_ERROR(x) \ { \ struct timeval tv; \ gettimeofday(&tv, NULL); \ double ts = tv.tv_sec + 1E-6 * tv.tv_usec; \ fprintf(stderr, "==%d== [%lf] ERROR [%s:%d:%s]: %s\n", getpid(), ts, STRIPPED_FILE_NAME, \ __LINE__, __func__, pmix_test_output_prepare x); \ fflush(stderr); \ } #define TEST_VERBOSE_ON() (pmix_test_verbose = 1) #define TEST_VERBOSE_GET() (pmix_test_verbose) #define TEST_VERBOSE(x) \ { \ if (pmix_test_verbose) { \ TEST_OUTPUT(x); \ } \ } #define TEST_DEFAULT_TIMEOUT 10 #define MAX_DIGIT_LEN 10 #define TEST_REPLACE_DEFAULT "3:1" #define TEST_SET_FILE(prefix, ns_id, rank) \ { \ size_t ln = strlen(prefix) + MAX_DIGIT_LEN + 2; \ char *fname = malloc(ln); \ snprintf(fname, ln, "%s.%d.%d", prefix, ns_id, rank); \ file = fopen(fname, "w"); \ if (NULL == file) { \ fprintf(stderr, "Cannot open file %s for writing!", fname); \ exit(1); \ } \ free(fname); \ } #define TEST_CLOSE_FILE() \ { \ if (stderr != file) { \ fclose(file); \ } \ } typedef struct { char *binary; char *np; char *prefix; char *nspace; uint32_t nprocs; int timeout; int verbose; pmix_rank_t rank; int early_fail; int test_job_fence; int collect_bad; int use_same_keys; int collect; int nonblocking; char *fences; char *noise; char *ns_dist; int ns_size; int ns_id; pmix_rank_t base_rank; int test_publish; int test_spawn; int test_connect; int test_resolve_peers; int test_error; char *key_replace; int test_internal; char *gds_mode; int nservers; uint32_t lsize; } test_params; #define INIT_TEST_PARAMS(params) \ do { \ params.nprocs = 1; \ params.verbose = 0; \ params.rank = PMIX_RANK_UNDEF; \ params.base_rank = 0; \ params.early_fail = 0; \ params.ns_size = -1; \ params.ns_id = -1; \ params.timeout = TEST_DEFAULT_TIMEOUT; \ params.test_job_fence = 0; \ params.use_same_keys = 0; \ params.collect = 0; \ params.collect_bad = 0; \ params.nonblocking = 0; \ params.test_publish = 0; \ params.test_spawn = 0; \ params.test_connect = 0; \ params.test_resolve_peers = 0; \ params.binary = NULL; \ params.np = NULL; \ params.prefix = NULL; \ params.nspace = NULL; \ params.fences = NULL; \ params.noise = NULL; \ params.ns_dist = NULL; \ params.test_error = 0; \ params.key_replace = NULL; \ params.test_internal = 0; \ params.gds_mode = NULL; \ params.nservers = 1; \ params.lsize = 0; \ } while (0) #define FREE_TEST_PARAMS(params) \ do { \ if (NULL != params.binary) { \ free(params.binary); \ } \ if (NULL != params.np) { \ free(params.np); \ } \ if (NULL != params.prefix) { \ free(params.prefix); \ } \ if (NULL != params.nspace) { \ free(params.nspace); \ } \ if (NULL != params.fences) { \ free(params.fences); \ } \ if (NULL != params.noise) { \ free(params.noise); \ } \ if (NULL != params.ns_dist) { \ free(params.ns_dist); \ } \ } while (0) void parse_cmd(int argc, char **argv, test_params *params); int parse_fence(char *fence_param, int store); int parse_noise(char *noise_param, int store); int parse_replace(char *replace_param, int store, int *key_num); typedef struct { pmix_list_item_t super; int blocking; int data_exchange; pmix_list_t *participants; // list of participants } fence_desc_t; PMIX_CLASS_DECLARATION(fence_desc_t); typedef struct { pmix_list_item_t super; pmix_proc_t proc; } participant_t; PMIX_CLASS_DECLARATION(participant_t); typedef struct { pmix_list_item_t super; int key_idx; } key_replace_t; PMIX_CLASS_DECLARATION(key_replace_t); extern pmix_list_t test_fences; extern pmix_list_t *noise_range; extern pmix_list_t key_replace; int get_total_ns_number(test_params params); int get_all_ranks_from_namespace(test_params params, char *nspace, pmix_proc_t **ranks, size_t *nranks); typedef struct { int in_progress; pmix_value_t *kv; int status; } get_cbdata; #define SET_KEY(key, fence_num, ind, use_same_keys) \ do { \ if (use_same_keys) { \ (void) snprintf(key, sizeof(key) - 1, "key-%d", ind); \ } else { \ (void) snprintf(key, sizeof(key) - 1, "key-f%d:%d", fence_num, ind); \ } \ } while (0) #define PUT(dtype, data, flag, fence_num, ind, use_same_keys) \ do { \ char _key[50]; \ pmix_value_t _value; \ SET_KEY(_key, fence_num, ind, use_same_keys); \ PMIX_VAL_SET(&_value, dtype, data); \ TEST_VERBOSE(("%s:%d put key %s", my_nspace, my_rank, _key)); \ if (PMIX_SUCCESS != (rc = PMIx_Put(flag, _key, &_value))) { \ TEST_ERROR(("%s:%d: PMIx_Put key %s failed: %s", my_nspace, my_rank, _key, \ PMIx_Error_string(rc))); \ } \ PMIX_VALUE_DESTRUCT(&_value); \ } while (0) #define GET(dtype, data, ns, r, fence_num, ind, use_same_keys, blocking, ok_notfnd) \ do { \ char _key[50]; \ pmix_value_t *_val; \ get_cbdata _cbdata; \ _cbdata.status = PMIX_SUCCESS; \ pmix_proc_t _foobar; \ SET_KEY(_key, fence_num, ind, use_same_keys); \ PMIX_LOAD_PROCID(&_foobar, ns, r); \ TEST_VERBOSE(("%s:%d want to get from %s:%d key %s", my_nspace, my_rank, ns, r, _key)); \ if (blocking) { \ if (PMIX_SUCCESS != (rc = PMIx_Get(&_foobar, _key, NULL, 0, &_val))) { \ if (!((rc == PMIX_ERR_NOT_FOUND || rc == PMIX_ERR_NOT_FOUND) \ && ok_notfnd)) { \ TEST_ERROR(("%s:%d: PMIx_Get failed: %s from %s:%d, key %s", my_nspace, \ my_rank, PMIx_Error_string(rc), ns, r, _key)); \ } \ } \ } else { \ _cbdata.in_progress = 1; \ PMIX_VALUE_CREATE(_val, 1); \ _cbdata.kv = _val; \ if (PMIX_SUCCESS \ != (rc = PMIx_Get_nb(&_foobar, _key, NULL, 0, get_cb, (void *) &_cbdata))) { \ TEST_VERBOSE(("%s:%d: PMIx_Get_nb failed: %s from %s:%d, key=%s", my_nspace, \ my_rank, PMIx_Error_string(rc), ns, r, _key)); \ } else { \ while (_cbdata.in_progress) { \ struct timespec ts; \ ts.tv_sec = 0; \ ts.tv_nsec = 100; \ nanosleep(&ts, NULL); \ } \ rc = _cbdata.status; \ PMIX_ACQUIRE_OBJECT(&_cbdata); \ } \ } \ if (PMIX_SUCCESS == rc) { \ if (PMIX_SUCCESS != _cbdata.status) { \ if (!((_cbdata.status == PMIX_ERR_NOT_FOUND) \ && ok_notfnd)) { \ TEST_ERROR(("%s:%d: PMIx_Get_nb failed: %s from %s:%d, key=%s", my_nspace, \ my_rank, PMIx_Error_string(rc), my_nspace, r, _key)); \ } \ } else if (NULL == _val) { \ TEST_VERBOSE(("%s:%d: PMIx_Get returned NULL value", my_nspace, my_rank)); \ } else if (_val->type != PMIX_VAL_TYPE_##dtype \ || PMIX_VAL_CMP(dtype, PMIX_VAL_FIELD_##dtype((_val)), data)) { \ TEST_ERROR(("%s:%u: from %s:%d Key %s value or type mismatch," \ " want type %d get type %d", \ my_nspace, my_rank, ns, r, _key, PMIX_VAL_TYPE_##dtype, _val->type)); \ } \ } \ if (PMIX_SUCCESS == rc) { \ TEST_VERBOSE( \ ("%s:%d: GET OF %s from %s:%d SUCCEEDED", my_nspace, my_rank, _key, ns, r)); \ PMIX_VALUE_RELEASE(_val); \ } \ } while (0) #define FENCE(blocking, data_ex, pcs, nprocs) \ do { \ if (blocking) { \ pmix_info_t *_info = NULL; \ size_t _ninfo = 0; \ if (data_ex) { \ bool _value = 1; \ PMIX_INFO_CREATE(_info, 1); \ pmix_strncpy(_info->key, PMIX_COLLECT_DATA, PMIX_MAX_KEYLEN); \ PMIx_Value_load(&_info->value, &_value, PMIX_BOOL); \ _ninfo = 1; \ } \ rc = PMIx_Fence(pcs, nprocs, _info, _ninfo); \ PMIX_INFO_FREE(_info, _ninfo); \ } else { \ int in_progress = 1, _count; \ rc = PMIx_Fence_nb(pcs, nprocs, NULL, 0, release_cb, &in_progress); \ if (PMIX_SUCCESS == rc) { \ _count = 0; \ while (in_progress) { \ struct timespec ts; \ ts.tv_sec = 0; \ ts.tv_nsec = 100; \ nanosleep(&ts, NULL); \ _count++; \ } \ TEST_VERBOSE( \ ("PMIx_Fence_nb(barrier,collect): free time: %lfs", _count * 100 * 1E-9)); \ } \ } \ if (PMIX_SUCCESS == rc) { \ TEST_VERBOSE(("%s:%d: Fence successfully completed", my_nspace, my_rank)); \ } \ } while (0) /* Key-Value pair management macros */ // TODO: add all possible types/fields here. #define PMIX_VAL_FIELD_int(x) ((x)->data.integer) #define PMIX_VAL_FIELD_uint32_t(x) ((x)->data.uint32) #define PMIX_VAL_FIELD_uint16_t(x) ((x)->data.uint16) #define PMIX_VAL_FIELD_string(x) ((x)->data.string) #define PMIX_VAL_FIELD_float(x) ((x)->data.fval) #define PMIX_VAL_FIELD_byte(x) ((x)->data.byte) #define PMIX_VAL_FIELD_flag(x) ((x)->data.flag) #define PMIX_VAL_TYPE_int PMIX_INT #define PMIX_VAL_TYPE_uint32_t PMIX_UINT32 #define PMIX_VAL_TYPE_uint16_t PMIX_UINT16 #define PMIX_VAL_TYPE_string PMIX_STRING #define PMIX_VAL_TYPE_float PMIX_FLOAT #define PMIX_VAL_TYPE_byte PMIX_BYTE #define PMIX_VAL_TYPE_flag PMIX_BOOL #define PMIX_VAL_set_assign(_v, _field, _val) \ do { \ (_v)->type = PMIX_VAL_TYPE_##_field; \ PMIX_VAL_FIELD_##_field((_v)) = _val; \ } while (0) #define PMIX_VAL_set_strdup(_v, _field, _val) \ do { \ (_v)->type = PMIX_VAL_TYPE_##_field; \ PMIX_VAL_FIELD_##_field((_v)) = strdup(_val); \ } while (0) #define PMIX_VAL_SET_int PMIX_VAL_set_assign #define PMIX_VAL_SET_uint32_t PMIX_VAL_set_assign #define PMIX_VAL_SET_uint16_t PMIX_VAL_set_assign #define PMIX_VAL_SET_string PMIX_VAL_set_strdup #define PMIX_VAL_SET_float PMIX_VAL_set_assign #define PMIX_VAL_SET_byte PMIX_VAL_set_assign #define PMIX_VAL_SET_flag PMIX_VAL_set_assign #define PMIX_VAL_SET(_v, _field, _val) PMIX_VAL_SET_##_field(_v, _field, _val) #define PMIX_VAL_cmp_val(_val1, _val2) ((_val1) != (_val2)) #define PMIX_VAL_cmp_float(_val1, _val2) \ (((_val1) > (_val2)) ? (((_val1) - (_val2)) > 0.000001) : (((_val2) - (_val1)) > 0.000001)) #define PMIX_VAL_cmp_ptr(_val1, _val2) strncmp(_val1, _val2, strlen(_val1) + 1) #define PMIX_VAL_CMP_int PMIX_VAL_cmp_val #define PMIX_VAL_CMP_uint32_t PMIX_VAL_cmp_val #define PMIX_VAL_CMP_uint16_t PMIX_VAL_cmp_val #define PMIX_VAL_CMP_float PMIX_VAL_cmp_float #define PMIX_VAL_CMP_string PMIX_VAL_cmp_ptr #define PMIX_VAL_CMP_byte PMIX_VAL_cmp_val #define PMIX_VAL_CMP_flag PMIX_VAL_cmp_val #define PMIX_VAL_ASSIGN(_v, _field, _val) PMIX_VAL_set_assign(_v, _field, _val) #define PMIX_VAL_CMP(_field, _val1, _val2) PMIX_VAL_CMP_##_field(_val1, _val2) #define PMIX_VAL_FREE(_v) PMIx_free_value_data(_v) #endif // TEST_COMMON_H pmix-6.1.1~rc2/test/utils.c0000664000175000017500000000604015203536752015760 0ustar alastairalastair/* * Copyright (c) 2015-2018 Intel, Inc. All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "utils.h" #include "cli_stages.h" #include "pmix_server.h" #include "test_common.h" #include "test_server.h" void set_client_argv(test_params *params, char ***argv) { PMIx_Argv_append_nosize(argv, params->binary); PMIx_Argv_append_nosize(argv, "-n"); if (NULL == params->np) { PMIx_Argv_append_nosize(argv, "1"); } else { PMIx_Argv_append_nosize(argv, params->np); } if (params->verbose) { PMIx_Argv_append_nosize(argv, "-v"); } if (NULL != params->prefix) { PMIx_Argv_append_nosize(argv, "-o"); PMIx_Argv_append_nosize(argv, params->prefix); } if (params->early_fail) { PMIx_Argv_append_nosize(argv, "--early-fail"); } if (NULL != params->fences) { PMIx_Argv_append_nosize(argv, "--fence"); PMIx_Argv_append_nosize(argv, params->fences); if (params->use_same_keys) { PMIx_Argv_append_nosize(argv, "--use-same-keys"); } } if (params->test_job_fence) { PMIx_Argv_append_nosize(argv, "--job-fence"); if (params->nonblocking) { PMIx_Argv_append_nosize(argv, "-nb"); } if (params->collect) { PMIx_Argv_append_nosize(argv, "-c"); } if (params->collect_bad) { PMIx_Argv_append_nosize(argv, "--collect-corrupt"); } } if (NULL != params->noise) { PMIx_Argv_append_nosize(argv, "--noise"); PMIx_Argv_append_nosize(argv, params->noise); } if (NULL != params->ns_dist) { PMIx_Argv_append_nosize(argv, "--ns-dist"); PMIx_Argv_append_nosize(argv, params->ns_dist); } if (params->test_publish) { PMIx_Argv_append_nosize(argv, "--test-publish"); } if (params->test_spawn) { PMIx_Argv_append_nosize(argv, "--test-spawn"); } if (params->test_connect) { PMIx_Argv_append_nosize(argv, "--test-connect"); } if (params->test_resolve_peers) { PMIx_Argv_append_nosize(argv, "--test-resolve-peers"); } if (params->test_error) { PMIx_Argv_append_nosize(argv, "--test-error"); } if (params->key_replace) { PMIx_Argv_append_nosize(argv, "--test-replace"); PMIx_Argv_append_nosize(argv, params->key_replace); } if (params->test_internal) { char tmp[32]; snprintf(tmp, 32, "%d", params->test_internal); PMIx_Argv_append_nosize(argv, "--test-internal"); PMIx_Argv_append_nosize(argv, tmp); } if (params->gds_mode) { PMIx_Argv_append_nosize(argv, "--gds"); PMIx_Argv_append_nosize(argv, params->gds_mode); } } pmix-6.1.1~rc2/test/server_callbacks.c0000664000175000017500000002614515203536752020135 0ustar alastairalastair/* * Copyright (c) 2015-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2015-2018 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2016 IBM Corporation. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "server_callbacks.h" #include "src/util/pmix_argv.h" #include "test_server.h" #include #include extern bool spawn_wait; pmix_server_module_t mymodule = {.client_connected = connected, .client_finalized = finalized, .abort = abort_fn, .fence_nb = fencenb_fn, .direct_modex = dmodex_fn, .publish = publish_fn, .lookup = lookup_fn, .unpublish = unpublish_fn, .spawn = spawn_fn, .connect = connect_fn, .disconnect = disconnect_fn, .register_events = regevents_fn, .deregister_events = deregevents_fn}; typedef struct { pmix_list_item_t super; pmix_info_t data; char *namespace_published; int rank_published; } pmix_test_info_t; static void tcon(pmix_test_info_t *p) { PMIX_INFO_CONSTRUCT(&p->data); } static void tdes(pmix_test_info_t *p) { PMIX_INFO_DESTRUCT(&p->data); } PMIX_CLASS_INSTANCE(pmix_test_info_t, pmix_list_item_t, tcon, tdes); pmix_list_t *pmix_test_published_list = NULL; static int finalized_count = 0; pmix_status_t connected(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata) { if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } PMIX_HIDE_UNUSED_PARAMS(proc, server_object); return PMIX_SUCCESS; } pmix_status_t finalized(const pmix_proc_t *proc, void *server_object, pmix_op_cbfunc_t cbfunc, void *cbdata) { cli_info_t *cli = NULL; int i; PMIX_HIDE_UNUSED_PARAMS(server_object); for (i = 0; i < cli_info_cnt; i++) { if ((proc->rank == cli_info[i].rank) && (0 == strcmp(proc->nspace, cli_info[i].ns))) { cli = &cli_info[i]; break; } } if (NULL == cli) { TEST_ERROR(("cannot found rank %d", proc->rank)); return PMIX_SUCCESS; } if (CLI_TERM <= cli->state) { TEST_ERROR(("double termination of rank %d", proc->rank)); return PMIX_SUCCESS; } TEST_VERBOSE(("Rank %s:%d terminated", proc->nspace, proc->rank)); cli_finalize(cli); finalized_count++; if (finalized_count == cli_info_cnt) { if (NULL != pmix_test_published_list) { PMIX_LIST_RELEASE(pmix_test_published_list); } } if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } pmix_status_t abort_fn(const pmix_proc_t *proc, void *server_object, int status, const char msg[], pmix_proc_t procs[], size_t nprocs, pmix_op_cbfunc_t cbfunc, void *cbdata) { if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } PMIX_HIDE_UNUSED_PARAMS(proc, server_object, procs, nprocs); TEST_VERBOSE(("Abort is called with status = %d, msg = %s", status, msg)); test_abort = true; return PMIX_SUCCESS; } pmix_status_t fencenb_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, char *data, size_t ndata, pmix_modex_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo); TEST_VERBOSE(("Getting data for %s:%d", procs[0].nspace, procs[0].rank)); if ((pmix_list_get_size(server_list) == 1) && (my_server_id == 0)) { if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, data, ndata, cbdata, NULL, NULL); } return PMIX_SUCCESS; } return server_fence_contrib(data, ndata, cbfunc, cbdata); } pmix_status_t dmodex_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_modex_cbfunc_t cbfunc, void *cbdata) { size_t n; TEST_VERBOSE(("Getting data for %s:%d", proc->nspace, proc->rank)); if (NULL != info) { for (n = 0; n < ninfo; n++) { if (PMIX_CHECK_KEY(&info[n], PMIX_TIMEOUT)) { return PMIX_ERR_NOT_SUPPORTED; } } } /* return not_found for single server mode */ if ((pmix_list_get_size(server_list) == 1) && (my_server_id == 0)) { return PMIX_ERR_NOT_FOUND; } // TODO: add support tracker for dmodex requests return server_dmdx_get(proc->nspace, proc->rank, cbfunc, cbdata); } pmix_status_t publish_fn(const pmix_proc_t *proc, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { size_t i; int found; pmix_test_info_t *new_info, *old_info; if (NULL == pmix_test_published_list) { pmix_test_published_list = PMIX_NEW(pmix_list_t); } for (i = 0; i < ninfo; i++) { found = 0; PMIX_LIST_FOREACH (old_info, pmix_test_published_list, pmix_test_info_t) { if (!strcmp(old_info->data.key, info[i].key)) { found = 1; break; } } if (!found) { new_info = PMIX_NEW(pmix_test_info_t); PMIX_LOAD_KEY(new_info->data.key, info[i].key); PMIx_Value_xfer(&new_info->data.value, (pmix_value_t *) &info[i].value); new_info->namespace_published = strdup(proc->nspace); new_info->rank_published = proc->rank; pmix_list_append(pmix_test_published_list, &new_info->super); } } if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } pmix_status_t lookup_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_lookup_cbfunc_t cbfunc, void *cbdata) { size_t i, ndata, ret; pmix_status_t rc = PMIX_SUCCESS; pmix_pdata_t *pdata; pmix_test_info_t *tinfo; PMIX_HIDE_UNUSED_PARAMS(proc, info, ninfo); if (NULL == pmix_test_published_list) { return PMIX_ERR_NOT_FOUND; } ndata = PMIx_Argv_count(keys); PMIX_PDATA_CREATE(pdata, ndata); ret = 0; for (i = 0; i < ndata; i++) { PMIX_LIST_FOREACH (tinfo, pmix_test_published_list, pmix_test_info_t) { if (0 == strcmp(tinfo->data.key, keys[i])) { pmix_strncpy(pdata[i].proc.nspace, tinfo->namespace_published, PMIX_MAX_NSLEN); pdata[i].proc.rank = tinfo->rank_published; memset(pdata[i].key, 0, PMIX_MAX_KEYLEN + 1); pmix_strncpy(pdata[i].key, keys[i], PMIX_MAX_KEYLEN); PMIx_Value_xfer(&pdata[i].value, &tinfo->data.value); ret++; break; } } } if (ret != ndata) { rc = PMIX_ERR_NOT_FOUND; goto error; } if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, pdata, ndata, cbdata); } error: PMIX_PDATA_FREE(pdata, ndata); return rc; } pmix_status_t unpublish_fn(const pmix_proc_t *proc, char **keys, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { size_t i; pmix_test_info_t *iptr, *next; PMIX_HIDE_UNUSED_PARAMS(proc, info); if (NULL == pmix_test_published_list) { return PMIX_ERR_NOT_FOUND; } PMIX_LIST_FOREACH_SAFE (iptr, next, pmix_test_published_list, pmix_test_info_t) { if (1) { // if data posted by this process if (NULL == keys) { pmix_list_remove_item(pmix_test_published_list, &iptr->super); PMIX_RELEASE(iptr); } else { ninfo = PMIx_Argv_count(keys); for (i = 0; i < ninfo; i++) { if (!strcmp(iptr->data.key, keys[i])) { pmix_list_remove_item(pmix_test_published_list, &iptr->super); PMIX_RELEASE(iptr); break; } } } } } if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } typedef struct { pmix_status_t status; pmix_spawn_cbfunc_t cbfunc; void *cbdata; } release_cbdata; static void *_release_cb(void *arg) { release_cbdata *cb = (release_cbdata *) arg; if (NULL != cb->cbfunc) { cb->cbfunc(cb->status, "foobar", cb->cbdata); } free(cb); spawn_wait = false; pthread_exit(NULL); } static void release_cb(pmix_status_t status, void *cbdata) { pthread_t thread; PMIX_HIDE_UNUSED_PARAMS(status); if (0 > pthread_create(&thread, NULL, _release_cb, cbdata)) { spawn_wait = false; return; } pthread_detach(thread); } pmix_status_t spawn_fn(const pmix_proc_t *proc, const pmix_info_t job_info[], size_t ninfo, const pmix_app_t apps[], size_t napps, pmix_spawn_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(proc, job_info, ninfo, apps); release_cbdata *cb = malloc(sizeof(release_cbdata)); pmix_nspace_t foobar; cb->status = PMIX_SUCCESS; cb->cbfunc = cbfunc; cb->cbdata = cbdata; spawn_wait = true; PMIX_LOAD_NSPACE(foobar, "foobar"); PMIx_server_register_nspace(foobar, napps, NULL, 0, release_cb, (void *) cb); return PMIX_SUCCESS; } static int numconnect = 0; pmix_status_t connect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } numconnect++; return PMIX_SUCCESS; } pmix_status_t disconnect_fn(const pmix_proc_t procs[], size_t nprocs, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(procs, nprocs, info, ninfo); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } pmix_status_t regevents_fn(pmix_status_t *codes, size_t ncodes, const pmix_info_t info[], size_t ninfo, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(ncodes, codes, info, ninfo); TEST_VERBOSE((" pmix host server regevents_fn called ")); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } pmix_status_t deregevents_fn(pmix_status_t *codes, size_t ncodes, pmix_op_cbfunc_t cbfunc, void *cbdata) { PMIX_HIDE_UNUSED_PARAMS(ncodes, codes); TEST_VERBOSE((" pmix host server deregevents_fn called ")); if (NULL != cbfunc) { cbfunc(PMIX_SUCCESS, cbdata); } return PMIX_SUCCESS; } pmix-6.1.1~rc2/test/run_tests03.pl.in0000777000175000017500000000000015203536752022572 2run_tests.pl.inustar alastairalastairpmix-6.1.1~rc2/README.md0000664000175000017500000000532315203536752014757 0ustar alastairalastair# PMIx Reference Library (OpenPMIx) ## Official documentation The OpenPMIx documentation can be viewed in the following ways: 1. Online at https://docs.openpmix.org/ 1. In self-contained (i.e., suitable for local viewing, without an internet connection) in official distribution tarballs under https://github.com/openpmix/openpmix/releases. ## Building the documentation locally The source code for OpenPMIx's docs can be found in the OpenPMIx Git repository under the `docs` folder. Developers who clone the OpenPMIx Git repository will not have the HTML documentation and man pages by default; it must be built. Instructions for how to build the OpenPMIx documentation can be found here: https://docs.openpmix.org/en/latest/developers/prerequisites.html#sphinx-and-therefore-python. ## How to contribute to the PMIx Reference Library General information about contributing to the PMIx project can be found at the [Contributing to PMIx webpage](https://openpmix.github.io/contribute/). The instructions below are specifically for opening issues and pull requests against the PMIx Reference Library. #### **Did you find a bug?** * **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/openpmix/openpmix/issues). * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/openpmix/openpmix/issues/new). #### **Did you write a patch that fixes a bug?** * Open a new GitHub pull request with the patch. * Ensure the PR description clearly describes the problem and solution. If there is an existing GitHub issue open describing this bug, please include it in the description so we can close it. * Before submitting, please read the [Contributing to PMIx](https://docs.openpmix.org/en/latest/contributing.html) web pages. In particular, note that all git commits contributed to PMIx require a Signed-off-by line. #### **Do you intend to add a new feature or change an existing one?** * Suggest your change on the [devel mail list](https://groups.google.com/forum/#!forum/pmix) and start writing code. * Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes. #### **Do you have questions about the source code?** * We are working to provide more online info about the PMIx code. Meantime, the [devel mail list](https://groups.google.com/forum/#!forum/pmix) is a good place to post questions about the source code. Thanks The PMIx Team ## Security policy The OpenPMIx security policy can be viewed online at https://docs.openpmix.org/en/latest/security.html. NOTE: any potential security issue should be reported immediately to us at security@pmix.org pmix-6.1.1~rc2/Makefile.openpmix-rules0000664000175000017500000000307615203536752020131 0ustar alastairalastair# -*- makefile -*- # Copyright (c) 2008-2022 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. # Copyright (c) 2020-2022 Intel, Inc. All rights reserved. # Copyright (c) 2025 Nanook Consulting All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # A little verbosity magic; "make" will show the terse output. "make # V=1" will show the actual commands used (just like the other # Automake-generated cprtelation/linker rules). V=0 PMIX_V_SPHINX_HTML = $(pmix__v_SPHINX_HTML_$V) pmix__v_SPHINX_HTML_ = $(pmix__v_SPHINX_HTML_$AM_DEFAULT_VERBOSITY) pmix__v_SPHINX_HTML_0 = @echo " GENERATE HTML docs"; PMIX_V_SPHINX_MAN = $(pmix__v_SPHINX_MAN_$V) pmix__v_SPHINX_MAN_ = $(pmix__v_SPHINX_MAN_$AM_DEFAULT_VERBOSITY) pmix__v_SPHINX_MAN_0 = @echo " GENERATE man pages"; PMIX_V_LN_S = $(pmix__v_LN_S_$V) pmix__v_LN_S_ = $(pmix__v_LN_S_$AM_DEFAULT_VERBOSITY) pmix__v_LN_S_0 = @echo " LN_S " `basename $@`; PMIX_V_MKDIR = $(pmix__v_MKDIR_$V) pmix__v_MKDIR_ = $(pmix__v_MKDIR_$AM_DEFAULT_VERBOSITY) pmix__v_MKDIR_0 = @echo " MKDIR " $@; PMIX_V_GEN = $(pmix__v_GEN_$V) pmix__v_GEN_ = $(pmix__v_GEN_$AM_DEFAULT_VERBOSITY) pmix__v_GEN_0 = @echo " GENERATE" $@; PMIX_V_COPYALL = $(pmix__v_COPYALL_$V) pmix__v_COPYALL_ = $(pmix__v_COPYALL_$AM_DEFAULT_VERBOSITY) pmix__v_COPYALL_0 = @echo " COPY tree $@"; PMIX_V_SPHINX_COPYRST = $(pmix__v_SPHINX_COPYRST_$V) pmix__v_SPHINX_COPYRST_ = $(pmix__v_SPHINX_COPYRST_$AM_DEFAULT_VERBOSITY) pmix__v_SPHINX_COPYRST_0 = @echo " COPY RST source files"; pmix-6.1.1~rc2/config/0000775000175000017500000000000015203536752014742 5ustar alastairalastairpmix-6.1.1~rc2/config/pmix.m40000664000175000017500000015775015203536752016200 0ustar alastairalastairdnl -*- shell-script -*- dnl dnl Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana dnl University Research and Technology dnl Corporation. All rights reserved. dnl Copyright (c) 2004-2005 The University of Tennessee and The University dnl of Tennessee Research Foundation. All rights dnl reserved. dnl Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, dnl University of Stuttgart. All rights reserved. dnl Copyright (c) 2004-2005 The Regents of the University of California. dnl All rights reserved. dnl Copyright (c) 2006-2022 Cisco Systems, Inc. All rights reserved dnl Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. dnl Copyright (c) 2009-2022 IBM Corporation. All rights reserved. dnl Copyright (c) 2009 Los Alamos National Security, LLC. All rights dnl reserved. dnl Copyright (c) 2009-2011 Oak Ridge National Labs. All rights reserved. dnl Copyright (c) 2011-2013 NVIDIA Corporation. All rights reserved. dnl Copyright (c) 2013-2023 Intel, Inc. All rights reserved. dnl Copyright (c) 2015-2019 Research Organization for Information Science dnl and Technology (RIST). All rights reserved. dnl Copyright (c) 2016 Mellanox Technologies, Inc. dnl All rights reserved. dnl dnl Copyright (c) 2021-2026 Nanook Consulting All rights reserved. dnl Copyright (c) 2018-2022 Amazon.com, Inc. or its affiliates. dnl All Rights reserved. dnl Copyright (c) 2021 FUJITSU LIMITED. All rights reserved. dnl $COPYRIGHT$ dnl dnl Additional copyrights may follow dnl dnl $HEADER$ dnl AC_DEFUN([PMIX_SETUP_CORE],[ AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) AC_REQUIRE([AC_CANONICAL_TARGET]) # AM_PROG_CC_C_O AC_REQUIREs AC_PROG_CC, so we have to be a little # careful about ordering here, and AC_REQUIRE these things so that # they get stamped out in the right order. AC_REQUIRE([_PMIX_START_SETUP_CC]) AC_REQUIRE([_PMIX_PROG_CC]) AC_REQUIRE([AM_PROG_CC_C_O]) OAC_PUSH_PREFIX([PMIX]) # initialize PMIX_EMBEDDED_LDFLAGS= PMIX_EMBEDDED_LIBS= PMIX_EMBEDDED_CPPFLAGS= # If no prefix was defined, set a good value m4_ifval([$1], [m4_define([pmix_config_prefix],[$1/])], [m4_define([pmix_config_prefix], [])]) # Get pmix's absolute top builddir (which may not be the same as # the real $top_builddir) PMIX_startdir=`pwd` if test x"pmix_config_prefix" != "x" && test ! -d "pmix_config_prefix"; then mkdir -p "pmix_config_prefix" fi if test x"pmix_config_prefix" != "x"; then cd "pmix_config_prefix" fi PMIX_top_builddir=`pwd` AC_SUBST(PMIX_top_builddir) # Get pmix's absolute top srcdir (which may not be the same as the # real $top_srcdir. First, go back to the startdir in case the # $srcdir is relative. cd "$PMIX_startdir" cd "$srcdir"/pmix_config_prefix PMIX_top_srcdir="`pwd`" AC_SUBST(PMIX_top_srcdir) # Go back to where we started cd "$PMIX_startdir" AC_MSG_NOTICE([pmix builddir: $PMIX_top_builddir]) AC_MSG_NOTICE([pmix srcdir: $PMIX_top_srcdir]) if test "$PMIX_top_builddir" != "$PMIX_top_srcdir"; then AC_MSG_NOTICE([Detected VPATH build]) fi # Get the version of pmix that we are installing AC_MSG_CHECKING([for pmix version]) PMIX_VERSION="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION`" if test "$?" != "0"; then AC_MSG_ERROR([Cannot continue]) fi AC_MSG_RESULT([$PMIX_VERSION]) AC_SUBST(PMIX_VERSION) AC_DEFINE_UNQUOTED([PMIX_VERSION], ["$PMIX_VERSION"], [The library version is always available, contrary to VERSION]) PMIX_PROXY_BUGREPORT_STRING="https://github.com/openpmix/openpmix" AC_SUBST(PMIX_PROXY_BUGREPORT_STRING) AC_DEFINE_UNQUOTED([PMIX_PROXY_BUGREPORT_STRING], ["$PMIX_PROXY_BUGREPORT_STRING"], [Where to report bugs]) PMIX_RELEASE_DATE="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION --release-date`" AC_SUBST(PMIX_RELEASE_DATE) # Save the breakdown the version information PMIX_MAJOR_VERSION="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION --major`" if test "$?" != "0"; then AC_MSG_ERROR([Cannot continue]) fi AC_SUBST(PMIX_MAJOR_VERSION) AC_DEFINE_UNQUOTED([PMIX_MAJOR_VERSION], [$PMIX_MAJOR_VERSION], [The library major version is always available, contrary to VERSION]) PMIX_MINOR_VERSION="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION --minor`" if test "$?" != "0"; then AC_MSG_ERROR([Cannot continue]) fi AC_SUBST(PMIX_MINOR_VERSION) AC_DEFINE_UNQUOTED([PMIX_MINOR_VERSION], [$PMIX_MINOR_VERSION], [The library minor version is always available, contrary to VERSION]) PMIX_RELEASE_VERSION="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION --release`" if test "$?" != "0"; then AC_MSG_ERROR([Cannot continue]) fi AC_SUBST(PMIX_RELEASE_VERSION) AC_DEFINE_UNQUOTED([PMIX_RELEASE_VERSION], [$PMIX_RELEASE_VERSION], [The library release version is always available, contrary to VERSION]) pmixmajor=${PMIX_MAJOR_VERSION}L pmixminor=${PMIX_MINOR_VERSION}L pmixrelease=${PMIX_RELEASE_VERSION}L pmixnumeric=$(printf 0x%4.4x%2.2x%2.2x $PMIX_MAJOR_VERSION $PMIX_MINOR_VERSION $PMIX_RELEASE_VERSION) AC_SUBST(pmixmajor) AC_SUBST(pmixminor) AC_SUBST(pmixrelease) AC_SUBST(pmixnumeric) AC_CONFIG_FILES(pmix_config_prefix[include/pmix_version.h]) PMIX_GREEK_VERSION="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION --greek`" if test "$?" != "0"; then AC_MSG_ERROR([Cannot continue]) fi AC_SUBST(PMIX_GREEK_VERSION) AC_MSG_CHECKING([for pmix standard version]) PMIX_STD_VERSION="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION --std-version`" if test "$?" != "0"; then AC_MSG_ERROR([Cannot continue]) fi AC_MSG_RESULT([$PMIX_STD_VERSION]) AC_SUBST(PMIX_STD_VERSION) AC_DEFINE_UNQUOTED([PMIX_STD_VERSION], ["$PMIX_STD_VERSION"], [The PMIx Standard compliance level]) AC_MSG_CHECKING([for pmix standard stable ABI version(s)]) PMIX_STD_ABI_STABLE_VERSION="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION --std-abi-stable-version`" if test "$?" != "0"; then AC_MSG_ERROR([Cannot continue]) fi AC_MSG_RESULT([$PMIX_STD_ABI_STABLE_VERSION]) AC_SUBST(PMIX_STD_ABI_STABLE_VERSION) AC_DEFINE_UNQUOTED([PMIX_STD_ABI_STABLE_VERSION], ["$PMIX_STD_ABI_STABLE_VERSION"], [The PMIx Standard Stable ABI compliance level(s)]) AC_MSG_CHECKING([for pmix standard provisional ABI version(s)]) PMIX_STD_ABI_PROVISIONAL_VERSION="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION --std-abi-provisional-version`" if test "$?" != "0"; then AC_MSG_ERROR([Cannot continue]) fi AC_MSG_RESULT([$PMIX_STD_ABI_PROVISIONAL_VERSION]) AC_SUBST(PMIX_STD_ABI_PROVISIONAL_VERSION) AC_DEFINE_UNQUOTED([PMIX_STD_ABI_PROVISIONAL_VERSION], ["$PMIX_STD_ABI_PROVISIONAL_VERSION"], [The PMIx Standard Provisional ABI compliance level(s)]) PMIX_REPO_REV="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION --repo-rev`" if test "$?" != "0"; then AC_MSG_ERROR([Cannot continue]) fi AC_SUBST(PMIX_REPO_REV) AC_DEFINE_UNQUOTED([PMIX_REPO_REV], ["$PMIX_REPO_REV"], [The OpenPMIx Git Revision]) PMIX_RELEASE_DATE="`$PMIX_top_srcdir/config/pmix_get_version.sh $PMIX_top_srcdir/VERSION --release-date`" if test "$?" != "0"; then AC_MSG_ERROR([Cannot continue]) fi AC_SUBST(PMIX_RELEASE_DATE) # Note that private/config.h *MUST* be listed first so that it # becomes the "main" config header file. Any AC-CONFIG-HEADERS # after that (pmix/config.h) will only have selective #defines # replaced, not the entire file. AC_CONFIG_HEADERS(pmix_config_prefix[src/include/pmix_config.h]) # # Package/brand string # AC_MSG_CHECKING([if want package/brand string]) AC_ARG_WITH([pmix-package-string], [AS_HELP_STRING([--with-pmix-package-string=STRING], [Use a branding string throughout PMIx])]) if test "$with_pmix_package_string" = "" || test "$with_pmix_package_string" = "no"; then with_package_string="PMIx $PMIX_CONFIGURE_USER@$PMIX_CONFIGURE_HOST Distribution" fi AC_DEFINE_UNQUOTED([PMIX_PACKAGE_STRING], ["$with_package_string"], [package/branding string for PMIx]) AC_MSG_RESULT([$with_package_string]) # GCC specifics. if test "x$GCC" = "xyes"; then PMIX_GCC_CFLAGS="-Wall -Wmissing-prototypes -Wundef" PMIX_GCC_CFLAGS="$PMIX_GCC_CFLAGS -Wpointer-arith -Wcast-align" fi ############################################################################ # Check for compilers and preprocessors ############################################################################ pmix_show_title "Compiler and preprocessor tests" PMIX_SETUP_CC # # Check for some types # AC_CHECK_TYPES(int8_t) AC_CHECK_TYPES(uint8_t) AC_CHECK_TYPES(int16_t) AC_CHECK_TYPES(uint16_t) AC_CHECK_TYPES(int32_t) AC_CHECK_TYPES(uint32_t) AC_CHECK_TYPES(int64_t) AC_CHECK_TYPES(uint64_t) AC_CHECK_TYPES(__int128) AC_CHECK_TYPES(uint128_t) AC_CHECK_TYPES(long long) AC_CHECK_TYPES(intptr_t) AC_CHECK_TYPES(uintptr_t) AC_CHECK_TYPES(ptrdiff_t) # check for sockaddr_in (a good sign we have TCP) # results used in the pif framework AC_CHECK_HEADERS([netdb.h netinet/in.h netinet/tcp.h]) AC_CHECK_TYPES([struct sockaddr_in], [pmix_found_sockaddr=yes], [pmix_found_sockaddr=no], [AC_INCLUDES_DEFAULT #ifdef HAVE_NETINET_IN_H #include #endif]) # # Check for type sizes # AC_CHECK_SIZEOF(_Bool) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(void *) AS_IF([test "$ac_cv_sizeof_void_p" -eq 4], [AC_MSG_WARN([PMIx does not support 32 bit builds.]) AC_MSG_ERROR([Cannot continue])]) AC_CHECK_SIZEOF(size_t) AC_CHECK_SIZEOF(pid_t) # # Check for type alignments # AC_CHECK_ALIGNOF(bool, [AC_INCLUDES_DEFAULT #include ]) AC_CHECK_ALIGNOF(int) AC_CHECK_ALIGNOF(long) AC_CHECK_ALIGNOF(size_t) if test "$ac_cv_type_long_long" = yes; then AC_CHECK_ALIGNOF(long long) fi AC_CHECK_ALIGNOF(double) # # Does the C compiler native support "bool"? (i.e., without # or any other help) # PMIX_VAR_SCOPE_PUSH([MSG]) AC_MSG_CHECKING(for C bool type) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ AC_INCLUDES_DEFAULT], [[bool bar, foo = true; bar = foo;]])], [PMIX_NEED_C_BOOL=0 MSG=yes],[PMIX_NEED_C_BOOL=1 MSG=no]) AC_DEFINE_UNQUOTED(PMIX_NEED_C_BOOL, $PMIX_NEED_C_BOOL, [Whether the C compiler supports "bool" without any other help (such as )]) AC_MSG_RESULT([$MSG]) AC_CHECK_SIZEOF(_Bool) PMIX_VAR_SCOPE_POP # # Check for other compiler characteristics # PMIX_VAR_SCOPE_PUSH([PMIX_CFLAGS_save]) if test "$GCC" = "yes"; then # gcc 2.96 will emit oodles of warnings if you use "inline" with # -pedantic (which we do in developer builds). However, # "__inline__" is ok. So we have to force gcc to select the # right one. If you use -pedantic, the AC_C_INLINE test will fail # (because it names a function foo() -- without the (void)). So # we turn off all the picky flags, turn on -ansi mode (which is # implied by -pedantic), and set warnings to be errors. Hence, # this does the following (for 2.96): # # - causes the check for "inline" to emit a warning, which then # fails # - checks for __inline__, which then emits no error, and works # # This also works nicely for gcc 3.x because "inline" will work on # the first check, and all is fine. :-) PMIX_CFLAGS_save=$CFLAGS CFLAGS="$PMIX_CFLAGS_BEFORE_PICKY -Werror -ansi" fi AC_C_INLINE if test "$GCC" = "yes"; then CFLAGS=$PMIX_CFLAGS_save fi PMIX_VAR_SCOPE_POP ################################## # Only after setting up # C do we check compiler attributes. ################################## pmix_show_subtitle "Compiler characteristics" PMIX_CHECK_ATTRIBUTES PMIX_CHECK_COMPILER_VERSION_ID # OpenPMIx only supports GCC >=v4.8.1. Notes: # # 1. The default compiler that comes with RHEL 7 is v4.8.5 # (version ID 264197). # 2. We regularly test with GCC v4.8.1 (version ID 264193). # 3. GCC 4.8.0 probably also works; we just haven't tested it. # # Since we regularly test with 4.8.1, that's what we check for. AS_IF([test "$pmix_cv_compiler_FAMILYNAME" = "GNU" && \ test "$pmix_cv_compiler_VERSION" -lt 264193], [AC_MSG_WARN([OpenPMIx no longer supports versions of the GNU compiler suite]) AC_MSG_WARN([less than v4.8.1.]) AC_MSG_WARN([Please upgrade your GNU compiler suite, or use]) AC_MSG_WARN([a different compiler to build OpenPMIx.]) AC_MSG_ERROR([Cannot continue]) ]) ################################## # Check required atomics ################################## AC_MSG_CHECKING([for __atomic_store_n]) AC_COMPILE_IFELSE( [AC_LANG_SOURCE([ #include void test_atomic_store() { int value = 0; __atomic_store_n(&value, 1, __ATOMIC_RELAXED); } ])], [AC_MSG_RESULT([found])], [AC_MSG_RESULT([not found]) AC_MSG_WARN([PMIx requires some minimal C11 atomic support. This was]) AC_MSG_WARN([not found in the current compiler. Please select a compiler]) AC_MSG_WARN([with the required support]) AC_MSG_ERROR([Cannot continue])] ) AC_MSG_CHECKING([for atomic_store]) AC_COMPILE_IFELSE( [AC_LANG_SOURCE([ #include void test_atomic_store() { atomic_bool value = 0; atomic_store(&value, 1); } ])], [AC_MSG_RESULT([found])], [AC_MSG_RESULT([not found]) AC_MSG_WARN([PMIx requires some minimal C11 atomic support. This was]) AC_MSG_WARN([not found in the current compiler. Please select a compiler]) AC_MSG_WARN([with the required support]) AC_MSG_ERROR([Cannot continue])] ) AC_MSG_CHECKING([for __atomic_load_n]) AC_COMPILE_IFELSE( [AC_LANG_SOURCE([ #include void test_atomic_load() { int value = 0; __atomic_load_n(&value, __ATOMIC_RELAXED); } ])], [AC_MSG_RESULT([found])], [AC_MSG_RESULT([not found]) AC_MSG_WARN([PMIx requires some minimal C11 atomic support. This was]) AC_MSG_WARN([not found in the current compiler. Please select a compiler]) AC_MSG_WARN([with the required support]) AC_MSG_ERROR([Cannot continue])] ) AC_MSG_CHECKING([for __atomic_fetch_add]) AC_COMPILE_IFELSE( [AC_LANG_SOURCE([ #include void test_atomic_fetch_add() { int value = 0; __atomic_fetch_add(&value, 1, __ATOMIC_SEQ_CST); } ])], [AC_MSG_RESULT([found])], [AC_MSG_RESULT([not found]) AC_MSG_WARN([PMIx requires some minimal C11 atomic support. This was]) AC_MSG_WARN([not found in the current compiler. Please select a compiler]) AC_MSG_WARN([with the required support]) AC_MSG_ERROR([Cannot continue])] ) AC_MSG_CHECKING([for __atomic_test_and_set]) AC_COMPILE_IFELSE( [AC_LANG_SOURCE([ #include void test_atomic_test_and_set() { _Bool flag = 0; __atomic_test_and_set(&flag, __ATOMIC_SEQ_CST); } ])], [AC_MSG_RESULT([found])], [AC_MSG_RESULT([not found]) AC_MSG_WARN([PMIx requires some minimal C11 atomic support. This was]) AC_MSG_WARN([not found in the current compiler. Please select a compiler]) AC_MSG_WARN([with the required support]) AC_MSG_ERROR([Cannot continue])] ) ################################## # Header files ################################## pmix_show_title "Header file tests" AC_CHECK_HEADERS([arpa/inet.h \ fcntl.h ifaddrs.h inttypes.h libgen.h \ net/uio.h netinet/in.h \ stdint.h stddef.h \ stdlib.h string.h strings.h \ sys/ioctl.h sys/param.h \ sys/select.h sys/socket.h sys/sockio.h \ stdarg.h sys/stat.h sys/time.h \ sys/types.h sys/un.h sys/uio.h \ sys/wait.h syslog.h \ time.h unistd.h dirent.h \ crt_externs.h signal.h \ ioLib.h sockLib.h hostLib.h limits.h \ sys/fcntl.h sys/statfs.h sys/statvfs.h \ netdb.h ucred.h sys/auxv.h \ sys/sysctl.h termio.h termios.h pty.h \ libutil.h util.h grp.h sys/cdefs.h utmp.h stropts.h \ sys/utsname.h stdatomic.h mntent.h]) AC_CHECK_HEADERS([sys/mount.h], [], [], [AC_INCLUDES_DEFAULT #if HAVE_SYS_PARAM_H #include #endif ]) AC_CHECK_HEADERS([sys/sysctl.h], [], [], [AC_INCLUDES_DEFAULT #if HAVE_SYS_PARAM_H #include #endif ]) # Needed to work around Darwin requiring sys/socket.h for # net/if.h AC_CHECK_HEADERS([net/if.h], [], [], [#include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_SOCKET_H # include #endif ]) # Note that sometimes we have , but it doesn't work (e.g., # have both Portland and GNU installed; using pgcc will find GNU's # , which all it does -- by standard -- is define "bool" to # "_Bool" [see # http://pmixw.opengroup.org/onlinepubs/009695399/basedefs/stdbool.h.html], # and Portland has no idea what to do with _Bool). # So first figure out if we have (i.e., check the value of # the macro HAVE_STDBOOL_H from the result of AC_CHECK_HEADERS, # above). If we do have it, then check to see if it actually works. # Define PMIX_USE_STDBOOL_H as approrpaite. AC_CHECK_HEADERS([stdbool.h], [have_stdbool_h=1], [have_stdbool_h=0]) AC_MSG_CHECKING([if works]) if test "$have_stdbool_h" = "1"; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT[ #if HAVE_STDBOOL_H #include #endif ]], [[bool bar, foo = true; bar = foo;]])], [PMIX_USE_STDBOOL_H=1 MSG=yes],[PMIX_USE_STDBOOL_H=0 MSG=no]) else PMIX_USE_STDBOOL_H=0 MSG="no (don't have )" fi AC_DEFINE_UNQUOTED(PMIX_USE_STDBOOL_H, $PMIX_USE_STDBOOL_H, [Whether to use or not]) AC_MSG_RESULT([$MSG]) # checkpoint results AC_CACHE_SAVE ################################## # Types ################################## pmix_show_title "Type tests" AC_CHECK_TYPES([socklen_t, struct sockaddr_in, struct sockaddr_un, struct sockaddr_in6, struct sockaddr_storage], [], [], [AC_INCLUDES_DEFAULT #if HAVE_SYS_SOCKET_H #include #endif #if HAVE_SYS_UN_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif ]) AC_CHECK_DECLS([AF_UNSPEC, PF_UNSPEC, AF_INET6, PF_INET6], [], [], [AC_INCLUDES_DEFAULT #if HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif ]) # SA_RESTART in signal.h PMIX_VAR_SCOPE_PUSH([MSG2]) AC_MSG_CHECKING([if SA_RESTART defined in signal.h]) AC_EGREP_CPP(yes, [ #include #ifdef SA_RESTART yes #endif ], [MSG2=yes VALUE=1], [MSG2=no VALUE=0]) AC_DEFINE_UNQUOTED(PMIX_HAVE_SA_RESTART, $VALUE, [Whether we have SA_RESTART in or not]) AC_MSG_RESULT([$MSG2]) PMIX_VAR_SCOPE_POP AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [], [ #include #if HAVE_SYS_SOCKET_H #include #endif ]) AC_CHECK_MEMBERS([struct dirent.d_type], [], [], [ #include #include ]) AC_CHECK_MEMBERS([siginfo_t.si_fd],,,[#include ]) AC_CHECK_MEMBERS([siginfo_t.si_band],,,[#include ]) # # Checks for struct member names in struct statfs # AC_CHECK_MEMBERS([struct statfs.f_type], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_VFS_H #include #endif #ifdef HAVE_SYS_STATFS_H #include #endif ]) AC_CHECK_MEMBERS([struct statfs.f_fstypename], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_SYS_VFS_H #include #endif #ifdef HAVE_SYS_STATFS_H #include #endif ]) # # Checks for struct member names in struct statvfs # AC_CHECK_MEMBERS([struct statvfs.f_basetype], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_STATVFS_H #include #endif ]) AC_CHECK_MEMBERS([struct statvfs.f_fstypename], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_STATVFS_H #include #endif ]) AC_CHECK_MEMBERS([struct ucred.uid, struct ucred.cr_uid, struct sockpeercred.uid], [], [], [#include #include ]) # # Check for ptrdiff type. Yes, there are platforms where # sizeof(void*) != sizeof(long) (64 bit Windows, apparently). # AC_MSG_CHECKING([for pointer diff type]) if test $ac_cv_type_ptrdiff_t = yes ; then pmix_ptrdiff_t="ptrdiff_t" pmix_ptrdiff_size=$ac_cv_sizeof_ptrdiff_t elif test $ac_cv_sizeof_void_p -eq $ac_cv_sizeof_long ; then pmix_ptrdiff_t="long" pmix_ptrdiff_size=$ac_cv_sizeof_long elif test $ac_cv_type_long_long = yes && test $ac_cv_sizeof_void_p -eq $ac_cv_sizeof_long_long ; then pmix_ptrdiff_t="long long" pmix_ptrdiff_size=$ac_cv_sizeof_long_long #else # AC_MSG_ERROR([Could not find datatype to emulate ptrdiff_t. Cannot continue]) fi AC_DEFINE_UNQUOTED([PMIX_PTRDIFF_TYPE], [$pmix_ptrdiff_t], [type to use for ptrdiff_t]) AC_MSG_RESULT([$pmix_ptrdiff_t (size: $pmix_ptrdiff_size)]) ################################## # Linker characteristics ################################## AC_MSG_CHECKING([the linker for support for the -fini option]) PMIX_VAR_SCOPE_PUSH([LDFLAGS_save]) LDFLAGS_save=$LDFLAGS LDFLAGS="$LDFLAGS_save -Wl,-fini -Wl,finalize" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ void finalize (void) {} ]])], [AC_MSG_RESULT([yes]) pmix_ld_have_fini=1], [AC_MSG_RESULT([no]) pmix_ld_have_fini=0]) LDFLAGS=$LDFLAGS_save PMIX_VAR_SCOPE_POP pmix_destructor_use_fini=0 pmix_no_destructor=0 if test x$pmix_cv___attribute__destructor = x0 ; then if test x$pmix_ld_have_fini = x1 ; then pmix_destructor_use_fini=1 else pmix_no_destructor=1; fi fi AC_DEFINE_UNQUOTED(PMIX_NO_LIB_DESTRUCTOR, [$pmix_no_destructor], [Whether libraries can be configured with destructor functions]) AM_CONDITIONAL(PMIX_DESTRUCTOR_USE_FINI, [test x$pmix_destructor_use_fini = x1]) ################################## # Libraries ################################## pmix_show_title "Library and Function tests" # Darwin doesn't need -lutil, as it's something other than this -lutil. PMIX_SEARCH_LIBS_CORE([openpty], [util]) PMIX_SEARCH_LIBS_CORE([forkpty], [util]) PMIX_SEARCH_LIBS_CORE([gethostbyname], [nsl]) PMIX_SEARCH_LIBS_CORE([socket], [socket]) # IRIX and CentOS have dirname in -lgen, usually in libc PMIX_SEARCH_LIBS_CORE([dirname], [gen]) # Darwin doesn't need -lm, as it's a symlink to libSystem.dylib PMIX_SEARCH_LIBS_CORE([ceil], [m]) # -lrt might be needed for clock_gettime PMIX_SEARCH_LIBS_CORE([clock_gettime], [rt]) AC_CHECK_FUNCS([asprintf snprintf vasprintf vsnprintf strsignal socketpair strncpy_s usleep statfs statvfs getpeereid getpeerucred strnlen posix_fallocate tcgetpgrp setpgid ptsname openpty setenv fork execve waitpid atexit forkpty posix_openpt fileno_unlocked isatty]) # On some hosts, htonl is a define, so the AC_CHECK_FUNC will get # confused. On others, it's in the standard library, but stubbed with # the magic glibc foo as not implemented. and on other systems, it's # just not there. This covers all cases. AC_CACHE_CHECK([for htonl define], [pmix_cv_htonl_define], [AC_PREPROC_IFELSE([AC_LANG_PROGRAM([ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif],[ #ifndef ntohl #error "ntohl not defined" #endif ])], [pmix_cv_htonl_define=yes], [pmix_cv_htonl_define=no])]) AC_CHECK_FUNC([htonl], [pmix_have_htonl=yes], [pmix_have_htonl=no]) AS_IF([test "$pmix_cv_htonl_define" = "yes" || test "$pmix_have_htonl" = "yes"], [AC_DEFINE_UNQUOTED([HAVE_UNIX_BYTESWAP], [1], [whether unix byteswap routines -- htonl, htons, nothl, ntohs -- are available])]) # # Make sure we can copy va_lists (need check declared, not linkable) # AC_CHECK_DECL(va_copy, PMIX_HAVE_VA_COPY=1, PMIX_HAVE_VA_COPY=0, [#include ]) AC_DEFINE_UNQUOTED(PMIX_HAVE_VA_COPY, $PMIX_HAVE_VA_COPY, [Whether we have va_copy or not]) AC_CHECK_DECL(__va_copy, PMIX_HAVE_UNDERSCORE_VA_COPY=1, PMIX_HAVE_UNDERSCORE_VA_COPY=0, [#include ]) AC_DEFINE_UNQUOTED(PMIX_HAVE_UNDERSCORE_VA_COPY, $PMIX_HAVE_UNDERSCORE_VA_COPY, [Whether we have __va_copy or not]) AC_CHECK_DECLS(__func__) # checkpoint results AC_CACHE_SAVE ################################## # System-specific tests ################################## pmix_show_title "System-specific tests" AC_C_BIGENDIAN # # Check out what thread support we have # PMIX_CONFIG_THREADS # # What is the local equivalent of "ln -s" # AC_PROG_LN_S # Check for some common system programs that we need AC_PROG_GREP AC_PROG_EGREP # Setup HTML and man page processing OAC_SETUP_SPHINX([$srcdir/docs/_build/html/index.html], [], [$srcdir/docs/requirements.txt]) AS_IF([test -n "$OAC_MAKEDIST_DISABLE"], [AS_IF([test -n "$PMIX_MAKEDIST_DISABLE"], [PMIX_MAKEDIST_DISABLE="$PMIX_MAKEDIST_DISABLE $OAC_MAKEDIST_DISABLE"], [PMIX_MAKEDIST_DISABLE=$OAC_MAKEDIST_DISABLE])]) AS_IF([test -n "$PMIX_MAKEDIST_DISABLE"], [AC_MSG_WARN(["make dist" will be disabled due to: $PMIX_MAKEDIST_DISABLE])]) AC_SUBST([PMIX_MAKEDIST_DISABLE]) ################################## # Visibility ################################## # Check the visibility declspec at the end to avoid problem with # the previous tests that are not necessarily prepared for # the visibility feature. pmix_show_title "Symbol visibility feature" PMIX_CHECK_VISIBILITY ################################## # Libevent ################################## pmix_show_title "Event library" pmix_found_event_lib=0 PMIX_LIBEVENT_CONFIG([pmix_found_event_lib=1]) AS_IF([test $pmix_found_event_lib -eq 0], [AC_MSG_WARN([libevent support is required, but was not found.]) AC_MSG_WARN([Please use the configure options to point us]) AC_MSG_WARN([to where we can find that library]) AC_MSG_ERROR([Cannot continue])]) ################################## # HWLOC ################################## pmix_show_title "HWLOC" PMIX_SETUP_HWLOC ################################## # JANSSON ################################## pmix_show_title "JANSSON" PMIX_CHECK_JANSSON ################################## # CURL ################################## pmix_show_title "CURL" PMIX_CHECK_CURL ################################## # MCA ################################## pmix_show_title "Modular Component Architecture (MCA) setup" # # Do we want to show component load error messages by default? # AC_MSG_CHECKING([for default value of mca_base_component_show_load_errors]) AC_ARG_WITH([show-load-errors], [AS_HELP_STRING([--with-show-load-errors], [Set the default value for the MCA parameter mca_base_component_show_load_errors (but can be overridden at run time by the usual MCA-variable-setting mechansism). (default: "none")])], [], [with_show_load_errors=no]) if test -z "$with_show_load_errors" || \ test "$with_show_load_errors" = "yes"; then with_show_load_errors=all AC_MSG_RESULT([enabled for all (by default)]) elif test "$with_show_load_errors" = "no"; then with_show_load_errors=none AC_MSG_RESULT([disabled for all (by default)]) fi AC_DEFINE_UNQUOTED(PMIX_SHOW_LOAD_ERRORS_DEFAULT, ["$with_show_load_errors"], [Default value for mca_base_component_show_load_errors MCA variable]) AC_MSG_CHECKING([for subdir args]) PMIX_CONFIG_SUBDIR_ARGS([pmix_subdir_args]) AC_MSG_RESULT([$pmix_subdir_args]) PMIX_MCA ############################################################################ # final compiler config ############################################################################ pmix_show_subtitle "Set path-related compiler flags" # # This is needed for VPATH builds, so that it will -I the appropriate # include directory. We delayed doing it until now just so that # '-I$(top_srcdir)' doesn't show up in any of the configure output -- # purely aesthetic. # # Because pmix_config.h is created by AC_CONFIG_HEADERS, we # don't need to -I the builddir for pmix/include. However, if we # are VPATH building, we do need to include the source directories. # if test "$PMIX_top_builddir" != "$PMIX_top_srcdir"; then # Note the embedded m4 directives here -- we must embed them # rather than have successive assignments to these shell # variables, lest the $(foo) names try to get evaluated here. # Yuck! cpp_includes="$PMIX_top_builddir $PMIX_top_srcdir $PMIX_top_srcdir/src $PMIX_top_builddir/include" else cpp_includes="$PMIX_top_srcdir $PMIX_top_srcdir/src" fi CPP_INCLUDES="$(echo $cpp_includes | $SED 's/[[^ \]]* */'"$pmix_cc_iquote"'&/g')" CPPFLAGS="$CPP_INCLUDES -I$PMIX_top_srcdir/include $CPPFLAGS" ############################################################################ # final wrapper compiler config ############################################################################ pmix_show_subtitle "Wrapper compiler final setup" # The PMIx wrapper script (i.e., not the C-compiled # executables) need perl. AC_PATH_PROG(PERL, perl, perl) # What's the suffix of shared libraries? Inspired by generated # Libtool code (even though we don't support several of these # platforms, there didn't seem to be any harm in leaving in some of # them, alhtough I did remove some that we have never/will never # support, like OS/2). case $host_os in mingw* | pw32* | cegcc*) PMIX_DYN_LIB_SUFFIX=dll ;; darwin* | rhapsody*) PMIX_DYN_LIB_SUFFIX=dylib ;; hpux9* | hpux10* | hpux11*) case $host_cpu in ia64*) PMIX_DYN_LIB_SUFFIX=so ;; *) PMIX_DYN_LIB_SUFFIX=sl ;; esac ;; *) PMIX_DYN_LIB_SUFFIX=so ;; esac AC_SUBST(PMIX_DYN_LIB_SUFFIX) # Need the libtool executable before the rpathify stuff LT_OUTPUT ############################################################################ # pmixdatadir, pmixlibdir, and pmixinclude are essentially the same as # pkg*dir, but will always be */pmix. pmixdatadir='${datadir}/pmix' pmixlibdir='${libdir}/pmix' pmixincludedir='${includedir}/pmix' AC_SUBST(pmixdatadir) AC_SUBST(pmixlibdir) AC_SUBST(pmixincludedir) PMIX_SETUP_WRAPPER_FINAL # PMIX_DELAYED_LIBS is used to allow us to add some libraries to the build, but # not add them to all the tests that are run through configure, since that # can cause some bundled build situations. This is the last minute, so time # to add them to LIBS. PMIX_FLAGS_APPEND_MOVE([LIBS], [$PMIX_DELAYED_LIBS]) ############################################################################ # setup "make check" ############################################################################ PMIX_BUILT_TEST_PREFIX=$PMIX_top_builddir AC_SUBST(PMIX_BUILT_TEST_PREFIX) # expose the mca component library paths in the build system pathfile=$PMIX_top_srcdir/config/mca_library_paths.txt PMIX_COMPONENT_LIBRARY_PATHS=`cat $pathfile` AC_SUBST(PMIX_COMPONENT_LIBRARY_PATHS) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests00.pl], [chmod +x test/run_tests00.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests01.pl], [chmod +x test/run_tests01.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests02.pl], [chmod +x test/run_tests02.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests03.pl], [chmod +x test/run_tests03.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests04.pl], [chmod +x test/run_tests04.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests05.pl], [chmod +x test/run_tests05.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests06.pl], [chmod +x test/run_tests06.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests07.pl], [chmod +x test/run_tests07.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests08.pl], [chmod +x test/run_tests08.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests09.pl], [chmod +x test/run_tests09.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests10.pl], [chmod +x test/run_tests10.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests11.pl], [chmod +x test/run_tests11.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests12.pl], [chmod +x test/run_tests12.pl]) AC_CONFIG_FILES(pmix_config_prefix[test/run_tests13.pl], [chmod +x test/run_tests13.pl]) # AC_CONFIG_FILES(pmix_config_prefix[test/run_tests14.pl], [chmod +x test/run_tests14.pl]) # AC_CONFIG_FILES(pmix_config_prefix[test/run_tests15.pl], [chmod +x test/run_tests15.pl]) if test "$WANT_PYTHON_BINDINGS" = "1"; then AC_CONFIG_FILES(pmix_config_prefix[test/python/run_server.sh], [chmod +x test/python/run_server.sh]) AC_CONFIG_FILES(pmix_config_prefix[test/python/run_sched.sh], [chmod +x test/python/run_sched.sh]) fi ############################################################################ # final output ############################################################################ pmix_show_subtitle "Final output" AC_CONFIG_HEADERS(pmix_config_prefix[include/pmix_common.h]) AC_CONFIG_FILES( pmix_config_prefix[Makefile] pmix_config_prefix[bindings/Makefile] pmix_config_prefix[bindings/python/Makefile] pmix_config_prefix[config/Makefile] pmix_config_prefix[etc/Makefile] pmix_config_prefix[include/Makefile] pmix_config_prefix[src/Makefile] pmix_config_prefix[src/class/Makefile] pmix_config_prefix[src/include/Makefile] pmix_config_prefix[src/util/Makefile] pmix_config_prefix[src/util/keyval/Makefile] pmix_config_prefix[src/mca/base/Makefile] pmix_config_prefix[src/tools/pevent/Makefile] pmix_config_prefix[src/tools/pmix_info/Makefile] pmix_config_prefix[src/tools/plookup/Makefile] pmix_config_prefix[src/tools/pps/Makefile] pmix_config_prefix[src/tools/pattrs/Makefile] pmix_config_prefix[src/tools/pquery/Makefile] pmix_config_prefix[src/tools/wrapper/Makefile] pmix_config_prefix[src/tools/wrapper/pmixcc-wrapper-data.txt] pmix_config_prefix[src/tools/palloc/Makefile] pmix_config_prefix[src/tools/pctrl/Makefile] ) # Success $2 ])dnl AC_DEFUN([PMIX_DEFINE_ARGS],[ # A hint to tell us if we are working with a build from Git or a tarball. # Helpful when preparing diagnostic output. if test -e $PMIX_TOP_SRCDIR/.git; then AC_DEFINE_UNQUOTED([PMIX_GIT_REPO_BUILD], ["1"], [If built from a git repo]) pmix_git_repo_build=yes fi # do we want dlopen support ? AC_MSG_CHECKING([if want dlopen support]) AC_ARG_ENABLE([dlopen], [AS_HELP_STRING([--enable-dlopen], [Whether build should attempt to use dlopen (or similar) to dynamically load components. (default: enabled)])]) AS_IF([test "$enable_dlopen" = "unknown"], [AC_MSG_WARN([enable_dlopen variable has been overwritten by configure]) AC_MSG_WARN([This is an internal error that should be reported to PMIx developers]) AC_MSG_ERROR([Cannot continue])]) AS_IF([test "$enable_dlopen" = "no"], [PMIX_ENABLE_DLOPEN_SUPPORT=0 AC_MSG_RESULT([no])], [PMIX_ENABLE_DLOPEN_SUPPORT=1 AC_MSG_RESULT([yes])]) AC_DEFINE_UNQUOTED(PMIX_ENABLE_DLOPEN_SUPPORT, $PMIX_ENABLE_DLOPEN_SUPPORT, [Whether we want to enable dlopen support]) # # Check the OS flavor here # OAC_CHECK_OS_FLAVORS # Debug mode? AC_MSG_CHECKING([if want pmix maintainer support]) pmix_debug=0 pmix_debug_msg="disabled" AS_IF([test "$enable_debug" = "yes"], [pmix_debug=1 pmix_debug_msg="enabled"]) # Grr; we use #ifndef for PMIX_DEBUG! :-( AH_TEMPLATE(PMIX_ENABLE_DEBUG, [Whether we are in debugging mode or not]) AS_IF([test "$pmix_debug" = "1"], [AC_DEFINE([PMIX_ENABLE_DEBUG])]) AC_MSG_RESULT([$pmix_debug_msg]) AC_MSG_CHECKING([for pmix directory prefix]) AC_MSG_RESULT(m4_ifval([$1], pmix_config_prefix, [(none)])) # # Developer picky compiler options # AC_MSG_CHECKING([if want developer-level compiler pickyness]) AC_ARG_ENABLE(devel-check, AS_HELP_STRING([--enable-devel-check], [enable developer-level compiler pickyness when building PMIx (default: disabled)])) if test "$enable_devel_check" = "yes"; then AC_MSG_RESULT([yes]) WANT_PICKY_COMPILER=1 elif test "$enable_devel_check" = "no"; then AC_MSG_RESULT([no]) WANT_PICKY_COMPILER=0 elif test "$pmix_git_repo_build" = "yes" && test "$pmix_debug" = "1"; then AC_MSG_RESULT([yes]) WANT_PICKY_COMPILER=1 else AC_MSG_RESULT([no]) WANT_PICKY_COMPILER=0 fi AC_DEFINE_UNQUOTED(PMIX_PICKY_COMPILERS, $WANT_PICKY_COMPILER, [Whether or not we are using picky compiler settings]) AC_MSG_CHECKING([if want memory sanitizers]) AC_ARG_ENABLE(memory-sanitizers, AS_HELP_STRING([--memory-sanitizers], [enable developer-level memory sanitizers when building PMIx (default: disabled)])) if test "$enable_memory_sanitizers" = "yes"; then AC_MSG_RESULT([yes]) WANT_MEMORY_SANITIZERS=1 AC_MSG_WARN([******************************************************]) AC_MSG_WARN([**** Memory sanitizers may require that you LD_PRELOAD]) AC_MSG_WARN([**** libasan in order to run an executable.]) AC_MSG_WARN([******************************************************]) else AC_MSG_RESULT([no]) WANT_MEMORY_SANITIZERS=0 fi AC_DEFINE_UNQUOTED(PMIX_MEMORY_SANITIZERS, $WANT_MEMORY_SANITIZERS, [Whether or not we are using memory sanitizers]) # # Developer debugging # AC_MSG_CHECKING([if want developer-level debugging code]) AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [enable developer-level debugging code (not for general PMIx users!) (default: disabled)])) if test "$enable_debug" = "yes"; then AC_MSG_RESULT([yes]) WANT_DEBUG=1 else AC_MSG_RESULT([no]) WANT_DEBUG=0 fi if test "$WANT_DEBUG" = "0"; then CFLAGS="-DNDEBUG $CFLAGS" fi AC_DEFINE_UNQUOTED(PMIX_ENABLE_DEBUG, $WANT_DEBUG, [Whether we want developer-level debugging code or not]) AC_ARG_ENABLE(debug-symbols, AS_HELP_STRING([--disable-debug-symbols], [Disable adding compiler flags to enable debugging symbols if --enable-debug is specified. For non-debugging builds, this flag has no effect.])) AC_MSG_CHECKING([if want to install PMIx header files]) AC_ARG_WITH(pmix-headers, AS_HELP_STRING([--with-pmix-headers], [Install the PMIx header files (pmix.h and friends) (default: enabled)])) if test "$with_pmix_headers" != "no"; then AC_MSG_RESULT([yes]) WANT_PRIMARY_HEADERS=1 pmix_install_primary_headers=yes else AC_MSG_RESULT([no]) WANT_PRIMARY_HEADERS=0 pmix_install_primary_headers=no fi # Install tests and examples? AC_MSG_CHECKING([if tests and examples are to be installed]) AC_ARG_WITH([tests-examples], [AS_HELP_STRING([--with-tests-examples], [Whether or not to install the tests and example programs.])]) AS_IF([test "$pmix_install_primary_headers" = "no"], [AS_IF([test -z "$with_tests_examples" || test "$with_tests_examples" = "no"], [pmix_tests=no AC_MSG_RESULT([no])], [AC_MSG_RESULT([no]) AC_MSG_WARN([Cannot install tests/examples without installing primary headers.]) AC_MSG_ERROR([Please correct the configure line and retry])])], [AS_IF([test ! -z "$with_tests_examples" && test "$with_tests_examples" = "no"], [pmix_tests=no AC_MSG_RESULT([no])], [pmix_tests=yes AC_MSG_RESULT([yes])])]) # # Support per-user config files? # AC_ARG_ENABLE([per-user-config-files], [AS_HELP_STRING([--enable-per-user-config-files], [Disable per-user configuration files, to save disk accesses during job start-up. This is likely desirable for large jobs. Note that this can also be achieved by environment variables at run-time. (default: enabled)])]) if test "$enable_per_user_config_files" = "no" ; then result=0 else result=1 fi AC_DEFINE_UNQUOTED([PMIX_WANT_HOME_CONFIG_FILES], [$result], [Enable per-user config files]) # # Do we want the pretty-print stack trace feature? # AC_MSG_CHECKING([if want pretty-print stacktrace]) AC_ARG_ENABLE([pretty-print-stacktrace], [AS_HELP_STRING([--enable-pretty-print-stacktrace], [Pretty print stacktrace on process signal (default: enabled)])]) if test "$enable_pretty_print_stacktrace" = "no" ; then AC_MSG_RESULT([no]) WANT_PRETTY_PRINT_STACKTRACE=0 else AC_MSG_RESULT([yes]) WANT_PRETTY_PRINT_STACKTRACE=1 fi AC_DEFINE_UNQUOTED([PMIX_WANT_PRETTY_PRINT_STACKTRACE], [$WANT_PRETTY_PRINT_STACKTRACE], [if want pretty-print stack trace feature]) # # # Ident string # AC_MSG_CHECKING([if want ident string]) AC_ARG_WITH([ident-string], [AS_HELP_STRING([--with-ident-string=STRING], [Embed an ident string into PMIx object files])]) if test "$with_ident_string" = "" || test "$with_ident_string" = "no"; then with_ident_string="%VERSION%" fi # This is complicated, because $PMIX_VERSION may have spaces in it. # So put the whole sed expr in single quotes -- i.e., directly # substitute %VERSION% for (not expanded) $PMIX_VERSION. with_ident_string="`echo $with_ident_string | sed -e 's/%VERSION%/$PMIX_VERSION/'`" # Now eval an echo of that so that the "$PMIX_VERSION" token is # replaced with its value. Enclose the whole thing in "" so that it # ends up as 1 token. with_ident_string="`eval echo $with_ident_string`" AC_DEFINE_UNQUOTED([PMIX_IDENT_STRING], ["$with_ident_string"], [ident string for PMIX]) AC_MSG_RESULT([$with_ident_string]) # # Timing support # AC_MSG_CHECKING([if want developer-level timing support]) AC_ARG_ENABLE(pmix-timing, AS_HELP_STRING([--enable-pmix-timing], [enable PMIx developer-level timing code (default: disabled)])) if test "$enable_pmix_timing" = "yes"; then AC_MSG_RESULT([yes]) WANT_PMIX_TIMING=1 else AC_MSG_RESULT([no]) WANT_PMIX_TIMING=0 fi AC_DEFINE_UNQUOTED([PMIX_ENABLE_TIMING], [$WANT_PMIX_TIMING], [Whether we want developer-level timing support or not]) # # Do we want to install binaries? # AC_MSG_CHECKING([if want to disable binaries]) AC_ARG_ENABLE(pmix-binaries, AS_HELP_STRING([--enable-pmix-binaries], [enable PMIx tools])) if test "$enable_pmix_binaries" = "no"; then AC_MSG_RESULT([no]) WANT_PMIX_BINARIES=0 else AC_MSG_RESULT([yes]) WANT_PMIX_BINARIES=1 fi AM_CONDITIONAL([PMIX_INSTALL_BINARIES], [test $WANT_PMIX_BINARIES -eq 1]) # # Install Python bindings? # AC_MSG_CHECKING([if want install Python bindings]) AC_ARG_ENABLE(python-bindings, AS_HELP_STRING([--enable-python-bindings], [enable Python bindings (default: disabled)])) if test "$enable_python_bindings" != "yes"; then AC_MSG_RESULT([no]) WANT_PYTHON_BINDINGS=0 pmix_want_python_bindings=no else AC_MSG_RESULT([yes]) # cannot build Python bindings if we are doing a purely static build if test "$enable_shared" = "no"; then AC_MSG_WARN([Python bindings cannot be built in purely]) AC_MSG_WARN([static configurations. Please either enable]) AC_MSG_WARN([shared libraries or remove the request to]) AC_MSG_WARN([build the Python bindings]) AC_MSG_ERROR([Cannot continue]) fi WANT_PYTHON_BINDINGS=1 pmix_want_python_bindings=yes fi AM_CONDITIONAL([WANT_PYTHON_BINDINGS], [test $WANT_PYTHON_BINDINGS -eq 1]) # We need Python if either of these are true: # - we are building in a git clone (not a distribution tarball) # - we want the Python bindings to be built AC_MSG_CHECKING([if we need Python]) pmix_need_python=no AS_IF([test "$pmix_want_python_bindings" = "yes"], [pmix_need_python=yes], [test "$pmix_git_repo_build" = "yes"], [pmix_need_python=yes], [pmix_need_python=no]) AC_MSG_RESULT([$pmix_need_python]) # if we need it, then check the min version pmix_have_good_python=0 pmix_python_min_version=PMIX_PYTHON_MIN_VERSION AS_IF([test "$pmix_need_python" = "yes"], [AM_PATH_PYTHON([$pmix_python_min_version], [pmix_have_good_python=1], [AC_MSG_ERROR([OpenPMIx requires Python >= $pmix_python_min_version to build. Aborting.])]) PMIX_SUMMARY_ADD([[Required Packages]], [Python], [], [yes ($[PYTHON_VERSION])]) ]) AS_IF([test "$pmix_want_python_bindings" = "yes" && test $pmix_have_good_python -eq 0], [AC_MSG_WARN([Python bindings were enabled, but no suitable]) AC_MSG_WARN([interpreter was found. PMIx requires Python >= $pmix_python_min_version]) AC_MSG_WARN([to provide Python bindings]) AC_MSG_ERROR([Cannot continue])]) # if we want the Python bindings, then we also require Cython if test "$pmix_want_python_bindings" = "yes"; then pyvers=`python3 --version` python_version=${pyvers#"Python "} PMIX_SUMMARY_ADD([Bindings], [Python], [], [yes ($python_version)]) AC_MSG_CHECKING([if Cython package installed as Python package]) have_cython=`$srcdir/config/pmix_check_cython.py 2> /dev/null` if test "$have_cython" = "0"; then AC_MSG_RESULT([yes]) AC_MSG_CHECKING([Cython version]) cython_version=`python -c "from Cython.Compiler.Version import version; print(version)"` AC_MSG_RESULT([$cython_version]) PMIX_SUMMARY_ADD([Required Packages], [Cython], [], [yes ($cython_version)]) else AC_MSG_RESULT([no]) # Cython doesn't have any include or lib files - it is just a binary AC_CHECK_PROG(pmix_cython_rpm, cython, [cython]) if test "$pmix_cython_rpm" != ""; then AC_MSG_CHECKING([Cython version]) cyvers=`cython --version 2>&1` cython_version=${cyvers#"Cython version "} AC_MSG_RESULT([$cython_version]) PMIX_SUMMARY_ADD([Bindings], [Cython], [], [yes ($cython_version)]) else AC_MSG_WARN([Python bindings were enabled, but the Cython]) AC_MSG_WARN([package was not found. PMIx Python bindings]) AC_MSG_WARN([require that the Cython package be installed]) AC_MSG_ERROR([Cannot continue]) fi fi pmix_pythondir=`eval echo $pythondir` AC_SUBST([PMIX_PYTHON_EGG_PATH], [$pmix_pythondir], [Path to installed Python egg]) fi # see if they want to disable non-RTLD_GLOBAL dlopen AC_MSG_CHECKING([if want to support dlopen of non-global namespaces]) AC_ARG_ENABLE([nonglobal-dlopen], AS_HELP_STRING([--enable-nonglobal-dlopen], [enable non-global dlopen (default: enabled)])) if test "$enable_nonglobal_dlopen" = "no"; then AC_MSG_RESULT([no]) pmix_need_libpmix=0 else AC_MSG_RESULT([yes]) pmix_need_libpmix=1 fi # # Do we want PTY support? # AC_MSG_CHECKING([if want pty support]) AC_ARG_ENABLE(pty-support, AS_HELP_STRING([--enable-pty-support], [Enable/disable PTY support for STDIO forwarding. (default: enabled)])) if test "$enable_pty_support" = "no" ; then AC_MSG_RESULT([no]) PMIX_ENABLE_PTY_SUPPORT=0 else AC_MSG_RESULT([yes]) PMIX_ENABLE_PTY_SUPPORT=1 fi AC_DEFINE_UNQUOTED([PMIX_ENABLE_PTY_SUPPORT], [$PMIX_ENABLE_PTY_SUPPORT], [Whether user wants PTY support or not]) # # psec/dummy_handshake # AC_MSG_CHECKING([if want build psec/dummy_handshake]) AC_ARG_ENABLE(dummy-handshake, AS_HELP_STRING([--enable-dummy-handshake], [Enables psec dummy component intended to check the PTL handshake scenario (default: disabled)])) if test "$enable_dummy_handshake" != "yes"; then AC_MSG_RESULT([no]) eval "DISABLE_psec_dummy_handshake=1" else AC_MSG_RESULT([yes]) eval "DISABLE_psec_dummy_handshake=0" fi AM_CONDITIONAL(MCA_BUILD_PSEC_DUMMY_HANDSHAKE, test "$DISABLE_psec_dummy_handshake" = "0") # # Do we want to enable IPv6 support? # AC_MSG_CHECKING([if want IPv6 support]) AC_ARG_ENABLE([ipv6], [AS_HELP_STRING([--enable-ipv6], [Enable IPv6 support, but only if the underlying system supports it (default: disabled)])]) if test "$enable_ipv6" = "yes"; then AC_MSG_RESULT([yes]) pmix_want_ipv6=1 pmix_ipv6_enabled="enabled" else AC_MSG_RESULT([no]) pmix_want_ipv6=0 pmix_ipv6_enabled="disabled" fi AC_DEFINE_UNQUOTED([PMIX_ENABLE_IPV6], [$pmix_want_ipv6], [Enable IPv6 support, but only if the underlying system supports it]) PMIX_SUMMARY_ADD([Miscellaneous], [IPv6 Support], [], [$pmix_ipv6_enabled]) ])dnl # This must be a standalone routine so that it can be called both by # PMIX_INIT and an external caller (if PMIX_INIT is not invoked). AC_DEFUN([PMIX_DO_AM_CONDITIONALS],[ AS_IF([test "$pmix_did_am_conditionals" != "yes"],[ AM_CONDITIONAL([PMIX_TESTS_EXAMPLES], [test "x$pmix_tests" = "xyes"]) AM_CONDITIONAL([PMIX_COMPILE_TIMING], [test "$WANT_TIMING" = "1"]) AM_CONDITIONAL([PMIX_WANT_MUNGE], [test "$pmix_munge_support" = "1"]) AM_CONDITIONAL([PMIX_WANT_SASL], [test "$pmix_sasl_support" = "1"]) AM_CONDITIONAL([WANT_PRIMARY_HEADERS], [test "x$pmix_install_primary_headers" = "xyes"]) AM_CONDITIONAL(NEED_LIBPMIX, [test "$pmix_need_libpmix" = "1"]) AM_CONDITIONAL([PMIX_HAVE_JANSSON], [test "x$pmix_check_jansson_happy" = "xyes"]) AM_CONDITIONAL([PMIX_HAVE_CURL], [test "x$pmix_check_curl_happy" = "xyes"]) AM_CONDITIONAL([PMIX_PICKY_COMPILERS], [test "$WANT_PICKY_COMPILER" = "1"]) ]) pmix_did_am_conditionals=yes ])dnl pmix-6.1.1~rc2/config/pmix_check_ident.m40000664000175000017500000000744315203536752020511 0ustar alastairalastairdnl -*- shell-script -*- dnl dnl Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. dnl Copyright (c) 2015 Intel, Inc. All rights reserved dnl $COPYRIGHT$ dnl dnl Additional copyrights may follow dnl dnl $HEADER$ dnl dnl defines: dnl PMIX_$1_USE_PRAGMA_IDENT dnl PMIX_$1_USE_IDENT dnl PMIX_$1_USE_CONST_CHAR_IDENT dnl # PMIX_CHECK_IDENT(compiler-env, compiler-flags, # file-suffix, lang) Try to compile a source file containing # a #pragma ident, and determine whether the ident was # inserted into the resulting object file # ----------------------------------------------------------- AC_DEFUN([PMIX_CHECK_IDENT], [ AC_MSG_CHECKING([for $4 ident string support]) pmix_pragma_ident_happy=0 pmix_ident_happy=0 pmix_static_const_char_happy=0 _PMIX_CHECK_IDENT( [$1], [$2], [$3], [[#]pragma ident], [], [pmix_pragma_ident_happy=1 pmix_message="[#]pragma ident"], _PMIX_CHECK_IDENT( [$1], [$2], [$3], [[#]ident], [], [pmix_ident_happy=1 pmix_message="[#]ident"], _PMIX_CHECK_IDENT( [$1], [$2], [$3], [[#]pragma comment(exestr, ], [)], [pmix_pragma_comment_happy=1 pmix_message="[#]pragma comment"], [pmix_static_const_char_happy=1 pmix_message="static const char[[]]"]))) AC_DEFINE_UNQUOTED([PMIX_$1_USE_PRAGMA_IDENT], [$pmix_pragma_ident_happy], [Use #pragma ident strings for $4 files]) AC_DEFINE_UNQUOTED([PMIX_$1_USE_IDENT], [$pmix_ident_happy], [Use #ident strings for $4 files]) AC_DEFINE_UNQUOTED([PMIX_$1_USE_PRAGMA_COMMENT], [$pmix_pragma_comment_happy], [Use #pragma comment for $4 files]) AC_DEFINE_UNQUOTED([PMIX_$1_USE_CONST_CHAR_IDENT], [$pmix_static_const_char_happy], [Use static const char[] strings for $4 files]) AC_MSG_RESULT([$pmix_message]) unset pmix_pragma_ident_happy pmix_ident_happy pmix_static_const_char_happy pmix_message ]) # _PMIX_CHECK_IDENT(compiler-env, compiler-flags, # file-suffix, header_prefix, header_suffix, action-if-success, action-if-fail) # Try to compile a source file containing a #-style ident, # and determine whether the ident was inserted into the # resulting object file # ----------------------------------------------------------- AC_DEFUN([_PMIX_CHECK_IDENT], [ eval pmix_compiler="\$$1" eval pmix_flags="\$$2" pmix_ident="string_not_coincidentally_inserted_by_the_compiler" cat > conftest.$3 <&5 pmix_output=`$pmix_compiler $pmix_flags -c conftest.$3 -o conftest.${OBJEXT} 2>&1 1>/dev/null` pmix_status=$? AS_IF([test $pmix_status = 0], [test -z "$pmix_output" pmix_status=$?]) PMIX_LOG_MSG([\$? = $pmix_status], 1) AS_IF([test $pmix_status = 0 && test -f conftest.${OBJEXT}], [pmix_output="`strings -a conftest.${OBJEXT} | grep $pmix_ident`" grep $pmix_ident conftest.${OBJEXT} 2>&1 1>/dev/null pmix_status=$? AS_IF([test "$pmix_output" != "" || test "$pmix_status" = "0"], [$6], [$7])], [PMIX_LOG_MSG([the failed program was:]) PMIX_LOG_FILE([conftest.$3]) $7]) unset pmix_compiler pmix_flags pmix_output pmix_status rm -rf conftest.* conftest${EXEEXT} ])dnl pmix-6.1.1~rc2/config/pmix_try_assemble.m40000664000175000017500000000361515203536752020737 0ustar alastairalastairdnl dnl Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana dnl University Research and Technology dnl Corporation. All rights reserved. dnl Copyright (c) 2004-2005 The University of Tennessee and The University dnl of Tennessee Research Foundation. All rights dnl reserved. dnl Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, dnl University of Stuttgart. All rights reserved. dnl Copyright (c) 2004-2005 The Regents of the University of California. dnl All rights reserved. dnl Copyright (c) 2014-2017 Intel, Inc. All rights reserved. dnl Copyright (c) 2021 Nanook Consulting. All rights reserved. dnl $COPYRIGHT$ dnl dnl Additional copyrights may follow dnl dnl $HEADER$ dnl dnl PMIX_TRY_ASSEMBLE(asm-code, [action-if-success], [action-if-fail]) dnl dnl Attempt to assemble asm-code. If success, run action-if-success. dnl Otherwise, run action-if-fail. Neither action-if-success nor dnl action-if-fail are required. dnl dnl No preprocessing is guaranteed to be done on asm-code. Some dnl compilers do not run the preprocessor on assembly files. dnl dnl On failure, asm-test.s will be included in config.out AC_DEFUN([PMIX_TRY_ASSEMBLE], [cat >conftest.s <&AS_MESSAGE_LOG_FD ifelse([$2],,:,[$2]) else # save compiler output and failed program cat conftest.out >&AS_MESSAGE_LOG_FD echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.s >&AS_MESSAGE_LOG_FD ifelse([$3],,:,[$3]) fi rm -rf conftest* unset pmix_assemble ])dnl pmix-6.1.1~rc2/config/pmix_check_attributes.m40000664000175000017500000004727015203536752021576 0ustar alastairalastair# -*- shell-script -*- # PMIx copyrights: # Copyright (c) 2013-2018 Intel, Inc. All rights reserved. # ######################### # # Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2010 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2009 Oak Ridge National Labs. All rights reserved. # Copyright (c) 2010-2018 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2013 Mellanox Technologies, Inc. # All rights reserved. # Copyright (c) 2015 Intel, Inc. All rights reserved. ######################### # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2021-2022 Amazon.com, Inc. or its affiliates. All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # # Search the generated warnings for # keywords regarding skipping or ignoring certain attributes # Intel: ignore # Sun C++: skip # AC_DEFUN([_PMIX_ATTRIBUTE_FAIL_SEARCH],[ AC_REQUIRE([AC_PROG_GREP]) if test -s conftest.err ; then # icc uses 'invalid attribute' and 'attribute "__XXX__" ignored' # Sun 12.1 emits 'warning: attribute parameter "__printf__" is undefined' for i in invalid ignore skip undefined ; do $GREP -iq $i conftest.err if test "$?" = "0" ; then pmix_cv___attribute__[$1]=0 break; fi done fi ]) # # Check for one specific attribute by compiling with C # # The last argument is for specific CFLAGS, that need to be set # for the compiler to generate a warning on the cross-check. # This may need adaption for future compilers / CFLAG-settings. # AC_DEFUN([_PMIX_CHECK_SPECIFIC_ATTRIBUTE], [ AC_MSG_CHECKING([for __attribute__([$1])]) AC_CACHE_VAL(pmix_cv___attribute__[$1], [ # # Try to compile using the C compiler # AC_COMPILE_IFELSE([AC_LANG_SOURCE([$2])], [ # # In case we did succeed: Fine, but was this due to the # attribute being ignored/skipped? Grep for IgNoRe/skip in conftest.err # and if found, reset the pmix_cv__attribute__var=0 # pmix_cv___attribute__[$1]=1 _PMIX_ATTRIBUTE_FAIL_SEARCH([$1]) ], [pmix_cv___attribute__[$1]=0]) ]) if test "$pmix_cv___attribute__[$1]" = "1" ; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ]) # # Test the availability of __attribute__ and with the help # of _PMIX_CHECK_SPECIFIC_ATTRIBUTE for the support of # particular attributes. Compilers, that do not support an # attribute most often fail with a warning (when the warning # level is set). # The compilers output is parsed in _PMIX_ATTRIBUTE_FAIL_SEARCH # # To add a new attributes __NAME__ add the # pmix_cv___attribute__NAME # add a new check with _PMIX_CHECK_SPECIFIC_ATTRIBUTE (possibly with a cross-check) # _PMIX_CHECK_SPECIFIC_ATTRIBUTE([name], [int foo (int arg) __attribute__ ((__name__));], [], []) # and define the corresponding # AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_NAME, [$pmix_cv___attribute__NAME], # [Whether your compiler has __attribute__ NAME or not]) # and decide on a correct macro (in pmix/include/pmix_config_bottom.h): # # define __pmix_attribute_NAME(x) __attribute__(__NAME__) # # Please use the "__"-notation of the attribute in order not to # clash with predefined names or macros (e.g. const, which some compilers # do not like..) # AC_DEFUN([PMIX_CHECK_ATTRIBUTES], [ AC_LANG(C) AC_MSG_CHECKING(for __attribute__) AC_CACHE_VAL(pmix_cv___attribute__, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], [/* Check for the longest available __attribute__ (since gcc-2.3) */ struct foo { char a; int x[2] __attribute__ ((__packed__)); }; ])], [pmix_cv___attribute__=1], [pmix_cv___attribute__=0])]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE, [$pmix_cv___attribute__], [Whether your compiler has __attribute__ or not]) # # Now that we know the compiler support __attribute__ let's check which kind of # attributed are supported. # if test "$pmix_cv___attribute__" = "0" ; then AC_MSG_RESULT([no]) pmix_cv___attribute__aligned=0 pmix_cv___attribute__always_inline=0 pmix_cv___attribute__cold=0 pmix_cv___attribute__const=0 pmix_cv___attribute__deprecated=0 pmix_cv___attribute__deprecated_argument=0 pmix_cv___attribute__format=0 pmix_cv___attribute__format_funcptr=0 pmix_cv___attribute__hot=0 pmix_cv___attribute__malloc=0 pmix_cv___attribute__may_alias=0 pmix_cv___attribute__no_instrument_function=0 pmix_cv___attribute__nonnull=0 pmix_cv___attribute__noreturn=0 pmix_cv___attribute__noreturn_funcptr=0 pmix_cv___attribute__packed=0 pmix_cv___attribute__pure=0 pmix_cv___attribute__sentinel=0 pmix_cv___attribute__unused=0 pmix_cv___attribute__visibility=0 pmix_cv___attribute__warn_unused_result=0 pmix_cv___attribute__destructor=0 pmix_cv___attribute__optnone=0 pmix_cv___attribute__extension=0 else AC_MSG_RESULT([yes]) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([aligned], [struct foo { char text[4]; } __attribute__ ((__aligned__(8)));], [], []) # # Ignored by PGI-6.2.5; -- recognized by output-parser # _PMIX_CHECK_SPECIFIC_ATTRIBUTE([always_inline], [int foo (int arg) __attribute__ ((__always_inline__));], [], []) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([cold], [ int foo(int arg1, int arg2) __attribute__ ((__cold__)); int foo(int arg1, int arg2) { return arg1 * arg2 + arg1; } ], [], []) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([const], [ int foo(int arg1, int arg2) __attribute__ ((__const__)); int foo(int arg1, int arg2) { return arg1 * arg2 + arg1; } ], [], []) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([deprecated], [ int foo(int arg1, int arg2) __attribute__ ((__deprecated__)); int foo(int arg1, int arg2) { return arg1 * arg2 + arg1; } ], [], []) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([deprecated_argument], [ int foo(int arg1, int arg2) __attribute__ ((__deprecated__("compiler allows argument"))); int foo(int arg1, int arg2) { return arg1 * arg2 + arg1; } ], [], []) ATTRIBUTE_CFLAGS= case "$oac_cv_c_compiler_vendor" in gnu|clang) ATTRIBUTE_CFLAGS="-Wall" ;; intel) # we want specifically the warning on format string conversion ATTRIBUTE_CFLAGS="-we181" ;; esac _PMIX_CHECK_SPECIFIC_ATTRIBUTE([format], [ int this_printf (void *my_object, const char *my_format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); ], [ static int usage (int * argument); extern int this_printf (int arg1, const char *my_format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); static int usage (int * argument) { return this_printf (*argument, "%d", argument); /* This should produce a format warning */ } /* The autoconf-generated main-function is int main(), which produces a warning by itself */ int main(void); ], [$ATTRIBUTE_CFLAGS]) ATTRIBUTE_CFLAGS= case "$oac_cv_c_compiler_vendor" in gnu|clang) ATTRIBUTE_CFLAGS="-Wall" ;; intel) # we want specifically the warning on format string conversion ATTRIBUTE_CFLAGS="-we181" ;; esac _PMIX_CHECK_SPECIFIC_ATTRIBUTE([format_funcptr], [ int (*this_printf)(void *my_object, const char *my_format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); ], [ static int usage (int * argument); extern int (*this_printf) (int arg1, const char *my_format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); static int usage (int * argument) { return (*this_printf) (*argument, "%d", argument); /* This should produce a format warning */ } /* The autoconf-generated main-function is int main(), which produces a warning by itself */ int main(void); ], [$ATTRIBUTE_CFLAGS]) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([hot], [ int foo(int arg1, int arg2) __attribute__ ((__hot__)); int foo(int arg1, int arg2) { return arg1 * arg2 + arg1; } ], [], []) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([malloc], [ #ifdef HAVE_STDLIB_H # include #endif int * foo(int arg1) __attribute__ ((__malloc__)); int * foo(int arg1) { return (int*) malloc(arg1); } ], [], []) # # Attribute may_alias: No suitable cross-check available, that works for non-supporting compilers # Ignored by intel-9.1.045 -- turn off with -wd1292 # Ignored by PGI-6.2.5; ignore not detected due to missing cross-check # _PMIX_CHECK_SPECIFIC_ATTRIBUTE([may_alias], [int * p_value __attribute__ ((__may_alias__));], [], []) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([no_instrument_function], [int * foo(int arg1) __attribute__ ((__no_instrument_function__));], [], []) # # Attribute nonnull: # Ignored by intel-compiler 9.1.045 -- recognized by cross-check # Ignored by PGI-6.2.5 (pgCC) -- recognized by cross-check # ATTRIBUTE_CFLAGS= case "$oac_cv_c_compiler_vendor" in gnu|clang) ATTRIBUTE_CFLAGS="-Wall" ;; intel) # we do not want to get ignored attributes warnings, but rather real warnings ATTRIBUTE_CFLAGS="-wd1292" ;; esac _PMIX_CHECK_SPECIFIC_ATTRIBUTE([nonnull], [ int square(int *arg) __attribute__ ((__nonnull__)); int square(int *arg) { return *arg; } ], [ static int usage(int * argument); int square(int * argument) __attribute__ ((__nonnull__)); int square(int * argument) { return (*argument) * (*argument); } static int usage(int * argument) { return square( ((void*)0) ); /* This should produce an argument must be nonnull warning */ } /* The autoconf-generated main-function is int main(), which produces a warning by itself */ int main(void); ], [$ATTRIBUTE_CFLAGS]) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([noreturn], [ #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_STDLIB_H # include #endif void fatal(int arg1) __attribute__ ((__noreturn__)); void fatal(int arg1) { exit(arg1); } ], [], []) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([noreturn_funcptr], [ #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_STDLIB_H # include #endif extern void (*fatal_exit)(int arg1) __attribute__ ((__noreturn__)); void fatal(int arg1) { fatal_exit (arg1); } ], [], [$ATTRIBUTE_CFLAGS]) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([packed], [ struct foo { char a; int x[2] __attribute__ ((__packed__)); }; ], [], []) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([pure], [ int square(int arg) __attribute__ ((__pure__)); int square(int arg) { return arg * arg; } ], [], []) # # Attribute sentinel: # Ignored by the intel-9.1.045 -- recognized by cross-check # intel-10.0beta works fine # Ignored by PGI-6.2.5 (pgCC) -- recognized by output-parser and cross-check # Ignored by pathcc-2.2.1 -- recognized by cross-check (through grep ignore) # ATTRIBUTE_CFLAGS= case "$oac_cv_c_compiler_vendor" in gnu|clang) ATTRIBUTE_CFLAGS="-Wall" ;; intel) # we do not want to get ignored attributes warnings ATTRIBUTE_CFLAGS="-wd1292" ;; esac _PMIX_CHECK_SPECIFIC_ATTRIBUTE([sentinel], [ int my_execlp(const char * file, const char *arg, ...) __attribute__ ((__sentinel__)); ], [ static int usage(int * argument); int my_execlp(const char * file, const char *arg, ...) __attribute__ ((__sentinel__)); static int usage(int * argument) { void * last_arg_should_be_null = argument; return my_execlp ("lala", "/home/there", last_arg_should_be_null); /* This should produce a warning */ } /* The autoconf-generated main-function is int main(), which produces a warning by itself */ int main(void); ], [$ATTRIBUTE_CFLAGS]) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([unused], [ int square(int arg1 __attribute__ ((__unused__)), int arg2); int square(int arg1, int arg2) { return arg2; } ], [], []) # # Ignored by PGI-6.2.5 (pgCC) -- recognized by the output-parser # _PMIX_CHECK_SPECIFIC_ATTRIBUTE([visibility], [ int square(int arg1) __attribute__ ((__visibility__("hidden"))); ], [], []) # # Attribute warn_unused_result: # Ignored by the intel-compiler 9.1.045 -- recognized by cross-check # Ignored by pathcc-2.2.1 -- recognized by cross-check (through grep ignore) # ATTRIBUTE_CFLAGS= case "$oac_cv_c_compiler_vendor" in gnu|clang) ATTRIBUTE_CFLAGS="-Wall" ;; intel) # we do not want to get ignored attributes warnings ATTRIBUTE_CFLAGS="-wd1292" ;; esac _PMIX_CHECK_SPECIFIC_ATTRIBUTE([warn_unused_result], [ int foo(int arg) __attribute__ ((__warn_unused_result__)); int foo(int arg) { return arg + 3; } ], [ static int usage(int * argument); int foo(int arg) __attribute__ ((__warn_unused_result__)); int foo(int arg) { return arg + 3; } static int usage(int * argument) { foo (*argument); /* Should produce an unused result warning */ return 0; } /* The autoconf-generated main-function is int main(), which produces a warning by itself */ int main(void); ], [$ATTRIBUTE_CFLAGS]) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([destructor], [ void foo(void) __attribute__ ((__destructor__)); void foo(void) { return ; } ], [], []) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([optnone], [ void __attribute__ ((__optnone__)) foo(void); void foo(void) { return ; } ], [], []) _PMIX_CHECK_SPECIFIC_ATTRIBUTE([extension], [ int i = __extension__ 3; ], [], []) fi # Now that all the values are set, define them AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_ALIGNED, [$pmix_cv___attribute__aligned], [Whether your compiler has __attribute__ aligned or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_ALWAYS_INLINE, [$pmix_cv___attribute__always_inline], [Whether your compiler has __attribute__ always_inline or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_COLD, [$pmix_cv___attribute__cold], [Whether your compiler has __attribute__ cold or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_CONST, [$pmix_cv___attribute__const], [Whether your compiler has __attribute__ const or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_DEPRECATED, [$pmix_cv___attribute__deprecated], [Whether your compiler has __attribute__ deprecated or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_DEPRECATED_ARGUMENT, [$pmix_cv___attribute__deprecated_argument], [Whether your compiler has __attribute__ deprecated with optional argument]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_FORMAT, [$pmix_cv___attribute__format], [Whether your compiler has __attribute__ format or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_FORMAT_FUNCPTR, [$pmix_cv___attribute__format_funcptr], [Whether your compiler has __attribute__ format and it works on function pointers]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_HOT, [$pmix_cv___attribute__hot], [Whether your compiler has __attribute__ hot or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_MALLOC, [$pmix_cv___attribute__malloc], [Whether your compiler has __attribute__ malloc or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_MAY_ALIAS, [$pmix_cv___attribute__may_alias], [Whether your compiler has __attribute__ may_alias or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_NO_INSTRUMENT_FUNCTION, [$pmix_cv___attribute__no_instrument_function], [Whether your compiler has __attribute__ no_instrument_function or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_NONNULL, [$pmix_cv___attribute__nonnull], [Whether your compiler has __attribute__ nonnull or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_NORETURN, [$pmix_cv___attribute__noreturn], [Whether your compiler has __attribute__ noreturn or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_NORETURN_FUNCPTR, [$pmix_cv___attribute__noreturn_funcptr], [Whether your compiler has __attribute__ noreturn and it works on function pointers]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_PACKED, [$pmix_cv___attribute__packed], [Whether your compiler has __attribute__ packed or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_PURE, [$pmix_cv___attribute__pure], [Whether your compiler has __attribute__ pure or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_SENTINEL, [$pmix_cv___attribute__sentinel], [Whether your compiler has __attribute__ sentinel or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_UNUSED, [$pmix_cv___attribute__unused], [Whether your compiler has __attribute__ unused or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_VISIBILITY, [$pmix_cv___attribute__visibility], [Whether your compiler has __attribute__ visibility or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_WARN_UNUSED_RESULT, [$pmix_cv___attribute__warn_unused_result], [Whether your compiler has __attribute__ warn unused result or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_WEAK_ALIAS, [$pmix_cv___attribute__weak_alias], [Whether your compiler has __attribute__ weak alias or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_DESTRUCTOR, [$pmix_cv___attribute__destructor], [Whether your compiler has __attribute__ destructor or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_OPTNONE, [$pmix_cv___attribute__optnone], [Whether your compiler has __attribute__ optnone or not]) AC_DEFINE_UNQUOTED(PMIX_HAVE_ATTRIBUTE_EXTENSION, [$pmix_cv___attribute__extension], [Whether your compiler has __attribute__ extension or not]) ]) pmix-6.1.1~rc2/config/ltmain_nag_pthread.diff0000664000175000017500000000155215203536752021417 0ustar alastairalastair--- config/ltmain.sh +++ config/ltmain.sh @@ -6417,8 +6417,14 @@ func_source "$lib" # Convert "-framework foo" to "foo.ltframework" + # and "-pthread" to "-Wl,-pthread" if NAG compiler if test -n "$inherited_linker_flags"; then - tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + case "$CC" in + *nagfor*) + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g' | $SED 's/-pthread/-Wl,-pthread/g'`;; + *) + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`;; + esac for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; pmix-6.1.1~rc2/config/pmix_config_threads.m40000664000175000017500000000476015203536752021227 0ustar alastairalastairdnl dnl Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana dnl University Research and Technology dnl Corporation. All rights reserved. dnl Copyright (c) 2004-2005 The University of Tennessee and The University dnl of Tennessee Research Foundation. All rights dnl reserved. dnl Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, dnl University of Stuttgart. All rights reserved. dnl Copyright (c) 2004-2005 The Regents of the University of California. dnl All rights reserved. dnl Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. dnl Copyright (c) 2009-2011 Oak Ridge National Labs. All rights reserved. dnl Copyright (c) 2014-2019 Intel, Inc. All rights reserved. dnl Copyright (c) 2015 Research Organization for Information Science dnl and Technology (RIST). All rights reserved. dnl Copyright (c) 2025 Nanook Consulting All rights reserved. dnl $COPYRIGHT$ dnl dnl Additional copyrights may follow dnl dnl $HEADER$ dnl AC_DEFUN([PMIX_CONFIG_THREADS],[ # # Arguments: none # # Dependencies: None # # Modifies: # none - see called tests # # configure threads # # # Check we have POSIX threads # PMIX_CONFIG_POSIX_THREADS(HAVE_POSIX_THREADS=1, HAVE_POSIX_THREADS=0) AC_MSG_CHECKING([for working POSIX threads package]) if test "$HAVE_POSIX_THREADS" = "1" ; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi export HAVE_POSIX_THREADS # # Ask what threading we want (allow posix right now) # if test "$HAVE_POSIX_THREADS" = "0"; then AC_MSG_WARN(["*** POSIX threads are not"]) AC_MSG_WARN(["*** available on your system "]) AC_MSG_ERROR(["*** Can not continue"]) fi THREAD_CFLAGS="$PTHREAD_CFLAGS" THREAD_CPPFLAGS="$PTHREAD_CPPFLAGS" THREAD_LDFLAGS="$PTHREAD_LDFLAGS" THREAD_LIBS="$PTHREAD_LIBS" PMIX_CHECK_PTHREAD_PIDS #update the flags CFLAGS="$CFLAGS $THREAD_CFLAGS" CPPFLAGS="$CPPFLAGS $THREAD_CPPFLAGS" LDFLAGS="$LDFLAGS $THREAD_LDFLAGS" LIBS="$LIBS $THREAD_LIBS" PMIX_WRAPPER_FLAGS_ADD([CFLAGS], [$THREAD_CFLAGS]) PMIX_WRAPPER_FLAGS_ADD([LDFLAGS], [$THREAD_LDFLAGS]) # Check for the setaffinity function - must come after # we update the flags AC_CHECK_FUNCS([pthread_setaffinity_np]) # Some folks apparently split that function definition # into a separate header, even though they leave the # function in pthreads.h. Go figure. AC_CHECK_HEADERS([pthread_np.h]) ])dnl pmix-6.1.1~rc2/config/pmix_config_subdir_args.m40000664000175000017500000000414515203536752022076 0ustar alastairalastairdnl -*- shell-script -*- dnl dnl Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana dnl University Research and Technology dnl Corporation. All rights reserved. dnl Copyright (c) 2004-2005 The University of Tennessee and The University dnl of Tennessee Research Foundation. All rights dnl reserved. dnl Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, dnl University of Stuttgart. All rights reserved. dnl Copyright (c) 2004-2005 The Regents of the University of California. dnl All rights reserved. dnl Copyright (c) 2014-2016 Intel, Inc. All rights reserved. dnl Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. dnl $COPYRIGHT$ dnl dnl Additional copyrights may follow dnl dnl $HEADER$ dnl AC_DEFUN([PMIX_CONFIG_SUBDIR_ARGS],[ PMIX_VAR_SCOPE_PUSH([subdirs_str subdirs_skip subdirs_args subdirs_arg]) # # Invoke configure in subdirectories. # # $1 is the name of the variable to assign the output to # # # Make a list of command line args --eliminate the --srcdir and # --cache-file args, because we need to replace them with our own # values when invoking the sub-configure script. Also eliminate # the --with-platform as this will confuse any subdir with # similar options # subdirs_args= subdirs_skip=no eval "set x $ac_configure_args" shift for subdirs_arg do if test "$subdirs_skip" = "yes"; then subdirs_skip=no else case $subdirs_arg in -cache-file | --cache-file | -cache | --cache) subdirs_skip=yes ;; --config-cache | -C) ;; -cache-file=* | --cache-file=*) ;; -srcdir | --srcdir) subdirs_skip=yes ;; -srcdir=* | --srcdir=*) ;; -with-platform=* | --with-platform=*) ;; *) case $subdir_arg in *\'*) subdir_arg=`echo "$subdir_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac subdirs_args="$subdirs_args '$subdirs_arg'" ;; esac fi done # # Assign the output # subdirs_str=$1=\"$subdirs_args\" eval "$subdirs_str" # # Clean up # PMIX_VAR_SCOPE_POP])dnl pmix-6.1.1~rc2/config/pmix_check_cflags.m40000664000175000017500000000265315203536752020643 0ustar alastairalastairdnl -*- shell-script -*- dnl dnl Copyright (c) 2021 IBM Corporation. All rights reserved. dnl dnl Copyright (c) 2021-2025 Nanook Consulting All rights reserved. dnl $COPYRIGHT$ dnl dnl Additional copyrights may follow dnl dnl $HEADER$ dnl AC_DEFUN([_PMIX_CFLAGS_FAIL_SEARCH],[ AC_REQUIRE([AC_PROG_GREP]) if test -s conftest.err ; then $GREP -iq $1 conftest.err if test "$?" = "0" ; then pmix_cv_cc_[$2]=0 fi fi ]) AC_DEFUN([_PMIX_CHECK_SPECIFIC_CFLAGS], [ AC_MSG_CHECKING(if $CC supports ([$1])) CFLAGS_orig=$CFLAGS PMIX_APPEND_UNIQ([CFLAGS], ["$1"]) AC_CACHE_VAL(pmix_cv_cc_[$2], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [$3])], [ pmix_cv_cc_[$2]=1 _PMIX_CFLAGS_FAIL_SEARCH("ignored\|not recognized\|not supported\|not compatible\|unrecognized\|unknown", [$2]) ], pmix_cv_cc_[$2]=1 _PMIX_CFLAGS_FAIL_SEARCH("ignored\|not recognized\|not supported\|not compatible\|unrecognized\|unknown", [$2]) )]) if test "$pmix_cv_cc_[$2]" = "0" ; then CFLAGS="$CFLAGS_orig" AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) fi ]) pmix-6.1.1~rc2/config/pmix_mca.m40000664000175000017500000010704015203536752017003 0ustar alastairalastairdnl -*- shell-script -*- dnl dnl Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana dnl University Research and Technology dnl Corporation. All rights reserved. dnl Copyright (c) 2004-2005 The University of Tennessee and The University dnl of Tennessee Research Foundation. All rights dnl reserved. dnl Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, dnl University of Stuttgart. All rights reserved. dnl Copyright (c) 2004-2005 The Regents of the University of California. dnl All rights reserved. dnl Copyright (c) 2010-2015 Cisco Systems, Inc. All rights reserved. dnl Copyright (c) 2013-2019 Intel, Inc. All rights reserved. dnl Copyright (c) 2021-2025 Nanook Consulting All rights reserved. dnl Copyright (c) 2018-2021 Amazon.com, Inc. or its affiliates. dnl All Rights reserved. dnl $COPYRIGHT$ dnl dnl Additional copyrights may follow dnl dnl $HEADER$ dnl # PMIX_EVAL_ARG(arg) # ------------------ # evaluates and returns argument AC_DEFUN([PMIX_EVAL_ARG], [$1]) ###################################################################### # # PMIX_MCA # # configure the MCA (modular component architecture). Works hand in hand # with PMIX's autogen.pl, requiring it's specially formatted lists # of frameworks, components, etc. # # USAGE: # PMIX_MCA() # ###################################################################### AC_DEFUN([PMIX_MCA],[ dnl for PMIX_CONFIGURE_USER env variable AC_REQUIRE([PMIX_CONFIGURE_SETUP]) # Find which components should be built as run-time loadable components # Acceptable combinations: # # [default -- no option given] # --enable-mca-dso # --enable-mca-dso=[.+,]*COMPONENT_TYPE[.+,]* # --enable-mca-dso=[.+,]*COMPONENT_TYPE-COMPONENT_NAME[.+,]* # --disable-mca-dso # AC_ARG_ENABLE([mca-no-build], [AS_HELP_STRING([--enable-mca-no-build=LIST], [Comma-separated list of - pairs that will not be built. Example: "--enable-mca-no-build=pgpu,pcompress-zlib" will disable building all pgpu components and the "zlib" pcompress component.])]) AC_ARG_ENABLE(mca-dso, AS_HELP_STRING([--enable-mca-dso=LIST], [Comma-separated list of types and/or type-component pairs that will be built as run-time loadable components (as opposed to statically linked in), if supported on this platform.]), [], [enable_mca_dso=pcompress,pnet-sshot]) AC_ARG_ENABLE(mca-static, AS_HELP_STRING([--enable-mca-static=LIST], [Comma-separated list of types and/or type-component pairs that will be built statically linked into the library. The default (if DSOs are supported) is to build all components as DSOs. Enabling a component as static disables it building as a DSO. The default is to build all components statically.])) AC_MSG_CHECKING([which components should be disabled]) if test "$enable_mca_no_build" = "yes"; then AC_MSG_RESULT([yes]) AC_MSG_ERROR([*** The enable-mca-no-build flag requires an explicit list *** of type-component pairs. For example, --enable-mca-no-build-ob1]) else ifs_save="$IFS" IFS="${IFS}$PATH_SEPARATOR," msg= for item in $enable_mca_no_build; do type="`echo $item | cut -s -f1 -d-`" comp="`echo $item | cut -s -f2- -d-`" if test -z $type ; then type=$item fi if test -z $comp ; then str="`echo DISABLE_${type}=1 | sed s/-/_/g`" eval $str msg="$item $msg" else str="`echo DISABLE_${type}_${comp}=1 | sed s/-/_/g`" eval $str msg="$item $msg" fi done IFS="$ifs_save" fi AC_MSG_RESULT([$msg]) unset msg # # First, set the DSO_all and STATIC_all variables. conflict # resolution (prefer static) is done in the big loop below # AC_MSG_CHECKING([which components should be run-time loadable]) if test "$enable_static" != "no"; then DSO_all=0 msg="none (static libraries built)" elif test "$PMIX_ENABLE_DLOPEN_SUPPORT" = 0; then DSO_all=0 msg="none (dlopen disabled)" elif test -z "$enable_mca_dso"; then DSO_all=0 msg="default" elif test "$enable_mca_dso" = "no"; then DSO_all=0 msg="none" elif test "$enable_mca_dso" = "yes"; then DSO_all=1 msg="all" else DSO_all=0 ifs_save="$IFS" IFS="${IFS}$PATH_SEPARATOR," msg= for item in $enable_mca_dso; do str="`echo DSO_$item=1 | sed s/-/_/g`" eval $str msg="$item $msg" done IFS="$ifs_save" fi AC_MSG_RESULT([$msg]) unset msg if test "$enable_static" != "no"; then AC_MSG_WARN([*** Shared libraries have been disabled (--disable-shared)]) AC_MSG_WARN([*** Building MCA components as DSOs automatically disabled]) fi AC_MSG_CHECKING([which components should be static]) if test -z "$enable_mca_static"; then STATIC_all=0 msg="default" elif test "$enable_mca_static" = "no"; then STATIC_all=0 msg="none" elif test "$enable_mca_static" = "yes"; then STATIC_all=1 msg="all" else STATIC_all=0 ifs_save="$IFS" IFS="${IFS}$PATH_SEPARATOR," msg= for item in $enable_mca_static; do str="`echo STATIC_$item=1 | sed s/-/_/g`" eval $str msg="$item $msg" done IFS="$ifs_save" fi AC_MSG_RESULT([$msg]) unset msg # now configure the PMIx project. Most # of the hard stuff is in here MCA_PROJECT_SUBDIRS= # can't use a variable rename here because these need to be evaled # at auto* time. pmix_show_subtitle "Configuring MCA" AC_MSG_CHECKING([for frameworks]) AC_MSG_RESULT([mca_pmix_framework_list]) # iterate through the list of frameworks. There is something # funky with m4 foreach if the list is defined, but empty. It # will call the 3rd argument once with an empty value for the # first argument. Protect against calling MCA_CONFIGURE_FRAMEWORK # with an empty second argument. Grrr.... # if there isn't a project list, abort # # Also setup two variables for Makefiles: # MCA_project_FRAMEWORKS - list of frameworks in that project # MCA_project_FRAMEWORK_LIBS - list of libraries (or variables pointing # to more libraries) that must be included # in the project's main library m4_ifdef([mca_pmix_framework_list], [], [m4_fatal([Could not find mca_pmix_framework_list - please rerun autogen.pl])]) MCA_pmix_FRAMEWORKS= MCA_pmix_FRAMEWORKS_SUBDIRS= MCA_pmix_FRAMEWORK_COMPONENT_ALL_SUBDIRS= MCA_pmix_FRAMEWORK_COMPONENT_DSO_SUBDIRS= MCA_pmix_FRAMEWORK_COMPONENT_STATIC_SUBDIRS= MCA_pmix_FRAMEWORK_LIBS= m4_foreach(mca_framework, [mca_pmix_framework_list], [m4_ifval(mca_framework, [dnl common has to go up front m4_if(mca_framework, [common], [MCA_pmix_FRAMEWORKS="mca_framework $MCA_pmix_FRAMEWORKS" MCA_pmix_FRAMEWORKS_SUBDIRS="[mca/]mca_framework $MCA_pmix_FRAMEWORKS_SUBDIRS" MCA_pmix_FRAMEWORK_COMPONENT_ALL_SUBDIRS="[\$(MCA_pmix_]mca_framework[_ALL_SUBDIRS)] $MCA_pmix_FRAMEWORK_COMPONENT_ALL_SUBDIRS" MCA_pmix_FRAMEWORK_COMPONENT_DSO_SUBDIRS="[\$(MCA_pmix_]mca_framework[_DSO_SUBDIRS)] $MCA_pmix_FRAMEWORK_COMPONENT_DSO_SUBDIRS" MCA_pmix_FRAMEWORK_COMPONENT_STATIC_SUBDIRS="[\$(MCA_pmix_]mca_framework[_STATIC_SUBDIRS)] $MCA_pmix_FRAMEWORK_COMPONENT_STATIC_SUBDIRS" ], [ MCA_pmix_FRAMEWORKS="$MCA_pmix_FRAMEWORKS mca_framework" MCA_pmix_FRAMEWORKS_SUBDIRS="$MCA_pmix_FRAMEWORKS_SUBDIRS [mca/]mca_framework" MCA_pmix_FRAMEWORK_COMPONENT_ALL_SUBDIRS="$MCA_pmix_FRAMEWORK_COMPONENT_ALL_SUBDIRS [\$(MCA_pmix_]mca_framework[_ALL_SUBDIRS)]" MCA_pmix_FRAMEWORK_COMPONENT_DSO_SUBDIRS="$MCA_pmix_FRAMEWORK_COMPONENT_DSO_SUBDIRS [\$(MCA_]pmix[_]mca_framework[_DSO_SUBDIRS)]" MCA_pmix_FRAMEWORK_COMPONENT_STATIC_SUBDIRS="$MCA_pmix_FRAMEWORK_COMPONENT_STATIC_SUBDIRS [\$(MCA_pmix_]mca_framework[_STATIC_SUBDIRS)]" MCA_pmix_FRAMEWORK_LIBS="$MCA_pmix_FRAMEWORK_LIBS [mca/]mca_framework[/libmca_]mca_framework[.la]"]) MCA_pmix_FRAMEWORK_LIBS="$MCA_pmix_FRAMEWORK_LIBS [\$(MCA_pmix_]mca_framework[_STATIC_LTLIBS)]" m4_ifdef([MCA_pmix_]mca_framework[_CONFIG], [MCA_pmix_]mca_framework[_CONFIG](mca_framework), [MCA_CONFIGURE_FRAMEWORK(mca_framework, 1)])])]) AC_SUBST(MCA_pmix_FRAMEWORKS) AC_SUBST(MCA_pmix_FRAMEWORKS_SUBDIRS) AC_SUBST(MCA_pmix_FRAMEWORK_COMPONENT_ALL_SUBDIRS) AC_SUBST(MCA_pmix_FRAMEWORK_COMPONENT_DSO_SUBDIRS) AC_SUBST(MCA_pmix_FRAMEWORK_COMPONENT_STATIC_SUBDIRS) AC_SUBST(MCA_pmix_FRAMEWORK_LIBS) AC_SUBST(MCA_PROJECT_SUBDIRS) ]) # MCA_ORDER_COMPONENT_LIST(framework_name) AC_DEFUN([MCA_ORDER_COMPONENT_LIST], [ m4_foreach(mca_component, [mca_pmix_$1_m4_config_component_list], [m4_ifval(mca_component, [m4_ifdef([MCA_pmix_]$1[_]mca_component[_PRIORITY], [], [m4_fatal([MCA_pmix_$1_]mca_component[_PRIORITY not found, but required.])])])]) m4_define([component_list], [esyscmd([config/pmix_mca_priority_sort.pl] m4_foreach([mca_component], [mca_pmix_$1_m4_config_component_list], [m4_ifval(mca_component, [mca_component ]PMIX_EVAL_ARG([MCA_pmix_]$1[_]mca_component[_PRIORITY ]))]))]) ]) AC_DEFUN([MCA_CHECK_IGNORED_PRIORITY], [ m4_foreach(mca_component, [mca_pmix_$1_m4_config_component_list], [m4_ifval(mca_component, [m4_ifdef([MCA_pmix_]$1[_]mca_component[_PRIORITY], [m4_warn([unsupported], [MCA_pmix_]$1[_]mca_component[_PRIORITY found, but ignored.])])])]) ]) ###################################################################### # # MCA_CONFIGURE_FRAMEWORK # # Configure the given framework and all components inside the # framework. Assumes that the framework is located in # src/mca/[framework], and that all components are # available under the framework directory. Will configure all # no-configure and builtin components, then search for components with # configure scripts. Assumes that no component is marked as builtin # AND has a configure script. # # USAGE: # MCA_CONFIGURE_FRAMEWORK(framework_name, allow_succeed) # ###################################################################### AC_DEFUN([MCA_CONFIGURE_FRAMEWORK],[ pmix_show_subsubtitle "Configuring MCA framework $1" m4_ifdef([mca_pmix_$1_no_config_component_list], [], [m4_fatal([Could not find mca_pmix_$1_no_config_component_list - please rerun autogen.pl])]) m4_ifdef([mca_pmix_$1_m4_config_component_list], [], [m4_fatal([Could not find mca_pmix_$1_m4_config_component_list - please rerun autogen.pl])]) # setup for framework all_components= static_components= dso_components= static_ltlibs= # Ensure that the directory where the #include file is to live # exists. Need to do this for VPATH builds, because the directory # may not exist yet. For the "common" type, it's not really a # component, so it doesn't have a base. m4_if([$1], [common], [outdir=src/mca/common], [outdir=src/mca/$1/base]) AS_MKDIR_P([$outdir]) # emit Makefile rule AC_CONFIG_FILES([src/mca/$1/Makefile]) # remove any previously generated #include files outfile_real=$outdir/static-components.h outfile=$outfile_real.new rm -f $outfile $outfile.struct $outfile.extern touch $outfile.struct $outfile.extern # print some nice messages about what we're about to do... AC_MSG_CHECKING([for no configure components in framework $1]) AC_MSG_RESULT([mca_pmix_$1_no_config_component_list]) AC_MSG_CHECKING([for m4 configure components in framework $1]) AC_MSG_RESULT([mca_pmix_$1_m4_config_component_list]) # If there are components in the no configure list, but we're # doing one of the "special" selection logics, abort with a # reasonable message. m4_if(PMIX_EVAL_ARG([MCA_pmix_$1_CONFIGURE_MODE]), [STOP_AT_FIRST], [m4_ifval(mca_pmix_$1_no_config_component_list, [m4_fatal([Framework $1 using STOP_AT_FIRST but at least one component has no configure.m4])])]) m4_if(PMIX_EVAL_ARG([MCA_pmix_$1_CONFIGURE_MODE]), [STOP_AT_FIRST_PRIORITY], [m4_ifval(mca_pmix_$1_no_config_component_list, [m4_fatal([Framework $1 using STOP_AT_FIRST_PRIORITY but at least one component has no configure.m4])])]) m4_if(PMIX_EVAL_ARG([MCA_pmix_$1_CONFIGURE_MODE]), [PRIORITY], [m4_ifval(mca_pmix_$1_no_config_component_list, [m4_fatal([Framework $1 using PRIORITY but at least one component has no configure.m4])])]) # run the configure logic for the no-config components m4_foreach(mca_component, [mca_pmix_$1_no_config_component_list], [m4_ifval(mca_component, [MCA_CONFIGURE_NO_CONFIG_COMPONENT($1, mca_component, [all_components], [static_components], [dso_components], [static_ltlibs], [$2])])]) # configure components that use built-in configuration scripts m4_ifdef([component_list], [m4_undefine([component_list])]) m4_if(PMIX_EVAL_ARG([MCA_pmix_$1_CONFIGURE_MODE]), [STOP_AT_FIRST], [MCA_ORDER_COMPONENT_LIST($1)], [m4_if(PMIX_EVAL_ARG([MCA_pmix_$1_CONFIGURE_MODE]), [STOP_AT_FIRST_PRIORITY], [MCA_ORDER_COMPONENT_LIST($1)], [m4_if(PMIX_EVAL_ARG([MCA_pmix_$1_CONFIGURE_MODE]), [PRIORITY], [MCA_ORDER_COMPONENT_LIST($1)], [m4_define([component_list], [mca_pmix_$1_m4_config_component_list])])])]) best_mca_component_priority=0 components_looking_for_succeed=$2 components_last_result=0 m4_foreach(mca_component, [component_list], [m4_ifval(mca_component, [m4_if(PMIX_EVAL_ARG([MCA_pmix_$1_CONFIGURE_MODE]), [STOP_AT_FIRST_PRIORITY], [AS_IF([test $best_mca_component_priority -gt MCA_pmix_$1_]mca_component[_PRIORITY], [components_looking_for_succeed=0])]) MCA_CONFIGURE_M4_CONFIG_COMPONENT($1, mca_component, [all_components], [static_components], [dso_components], [static_ltlibs], [$components_looking_for_succeed], [components_last_result=1], [components_last_result=0]) m4_if(PMIX_EVAL_ARG([MCA_pmix_$1_CONFIGURE_MODE]), [STOP_AT_FIRST], [AS_IF([test $components_last_result -eq 1], [components_looking_for_succeed=0])]) m4_if(PMIX_EVAL_ARG([MCA_pmix_$1_CONFIGURE_MODE]), [STOP_AT_FIRST_PRIORITY], [AS_IF([test $components_last_result -eq 1], [best_mca_component_priority=]PMIX_EVAL_ARG([MCA_pmix_$1_]mca_component[_PRIORITY]))]) ])]) # configure components that provide their own configure script. # It would be really hard to run these for "find first that # works", so we don't :) m4_if(PMIX_EVAL_ARG([MCA_pmix_]$1[_CONFIGURE_MODE]), [STOP_AT_FIRST], [], [m4_if(PMIX_EVAL_ARG([MCA_pmix_]$1[_CONFIGURE_MODE]), [STOP_AT_FIRST_PRIORITY], [], [m4_if(PMIX_EVAL_ARG([MCA_pmix_]$1[_CONFIGURE_MODE]), [PRIORITY], [], [MCA_CHECK_IGNORED_PRIORITY($1) AS_IF([test "$2" != "0"], [MCA_CONFIGURE_ALL_CONFIG_COMPONENTS($1, [all_components], [static_components], [dso_components], [static_ltlibs])])])])]) MCA_pmix_$1_ALL_COMPONENTS="$all_components" MCA_pmix_$1_STATIC_COMPONENTS="$static_components" MCA_pmix_$1_DSO_COMPONENTS="$dso_components" MCA_pmix_$1_STATIC_LTLIBS="$static_ltlibs" AC_SUBST(MCA_pmix_$1_ALL_COMPONENTS) AC_SUBST(MCA_pmix_$1_STATIC_COMPONENTS) AC_SUBST(MCA_pmix_$1_DSO_COMPONENTS) AC_SUBST(MCA_pmix_$1_STATIC_LTLIBS) PMIX_MCA_MAKE_DIR_LIST(MCA_pmix_$1_ALL_SUBDIRS, $1, [$all_components]) PMIX_MCA_MAKE_DIR_LIST(MCA_pmix_$1_STATIC_SUBDIRS, $1, [$static_components]) PMIX_MCA_MAKE_DIR_LIST(MCA_pmix_$1_DSO_SUBDIRS, $1, [$dso_components]) # Create the final .h file that will be included in the type's # top-level glue. This lists all the static components. We don't # need to do this for "common". if test "$1" != "common"; then cat > $outfile < /dev/null 2>&1 if test "$?" != "0"; then mv $outfile $outfile_real else rm -f $outfile fi fi rm -f $outfile.struct $outfile.extern unset all_components static_components dso_components outfile outfile_real ]) ###################################################################### # # MCA_CONFIGURE_NO_CONFIG_COMPONENT # # Configure the given framework and all components inside the framework. # Assumes that the framework is located in [project_name]/mca/[framework], # and that all components are available under the framework directory. # Will configure all builtin components, then search for components with # configure scripts. Assumes that no component is marked as builtin # AND has a configure script. # # USAGE: # MCA_CONFIGURE_PROJECT(framework_name, component_name # all_components_variable, # static_components_variable, # dso_components_variable, # static_ltlibs_variable, # allowed_to_succeed) # ###################################################################### AC_DEFUN([MCA_CONFIGURE_NO_CONFIG_COMPONENT],[ pmix_show_subsubsubtitle "MCA component $1:$2 (no configuration)" pmix_show_verbose "PMIX_MCA_NO_CONFIG_COMPONENT: before, should_build=$7" MCA_COMPONENT_BUILD_CHECK($1, $2, [should_build=$7], [should_build=0]) MCA_COMPONENT_COMPILE_MODE($1, $2, compile_mode) pmix_show_verbose "PMIX_MCA_NO_CONFIG_COMPONENT: after, should_build=$should_build" if test "$should_build" = "1" ; then MCA_PROCESS_COMPONENT($1, $2, $3, $4, $5, $6, $compile_mode) else MCA_PROCESS_DEAD_COMPONENT($1, $2) # add component to all component list $3="$$3 $2" fi # set the AM_CONDITIONAL on how we should build if test "$compile_mode" = "dso" ; then BUILD_pmix_$1_$2_DSO=1 else BUILD_pmix_$1_$2_DSO=0 fi AM_CONDITIONAL(MCA_BUILD_pmix_$1_$2_DSO, test "$BUILD_pmix_$1_$2_DSO" = "1") AC_CONFIG_FILES([src/mca/$1/$2/Makefile]) unset compile_mode ]) ###################################################################### # # MCA_CONFIGURE_M4_CONFIG_COMPONENT # # # USAGE: # MCA_CONFIGURE_PROJECT(framework_name, component_name # all_components_variable, # static_components_variable, # dso_components_variable, # static_ltlibs_variable, # allowed_to_succeed, # [eval if should build], # [eval if should not build]) # ###################################################################### AC_DEFUN([MCA_CONFIGURE_M4_CONFIG_COMPONENT],[ m4_ifdef([MCA_pmix_$1_$2_PRIORITY], [pmix_show_subsubsubtitle "MCA component $1:$2 (m4 configuration macro, priority MCA_pmix_$1_$2_PRIORITY)"], [pmix_show_subsubsubtitle "MCA component $1:$2 (m4 configuration macro)"]) pmix_show_verbose "PMIX_MCA_M4_CONFIG_COMPONENT: before, should_build=$7" MCA_COMPONENT_BUILD_CHECK($1, $2, [should_build=$7], [should_build=0]) # Allow the component to override the build mode if it really wants to. # It is, of course, free to end up calling MCA_COMPONENT_COMPILE_MODE m4_ifdef([MCA_pmix_$1_$2_COMPILE_MODE], [MCA_pmix_$1_$2_COMPILE_MODE($1, $2, compile_mode)], [MCA_COMPONENT_COMPILE_MODE($1, $2, compile_mode)]) # try to configure the component m4_ifdef([MCA_pmix_$1_$2_CONFIG], [MCA_pmix_$1_$2_CONFIG([should_build=$should_build], [should_build=0])], [m4_fatal([MCA_pmix_$1_$2_CONFIG macro not found])]) pmix_show_verbose "PMIX_MCA_M4_CONFIG_COMPONENT: after, should_build=$should_build" AS_IF([test "$should_build" = "1"], [MCA_PROCESS_COMPONENT($1, $2, $3, $4, $5, $6, $compile_mode)], [MCA_PROCESS_DEAD_COMPONENT($1, $2) # add component to all component list $3="$$3 $2"]) m4_ifdef([MCA_pmix_$1_$2_POST_CONFIG], [ MCA_pmix_$1_$2_POST_CONFIG($should_build)]) # set the AM_CONDITIONAL on how we should build AS_IF([test "$compile_mode" = "dso"], [BUILD_pmix_$1_$2_DSO=1], [BUILD_pmix_$1_$2_DSO=0]) AM_CONDITIONAL(MCA_BUILD_pmix_$1_$2_DSO, test "$BUILD_pmix_$1_$2_DSO" = "1") AS_IF([test "$should_build" = "1"], [$8], [$9]) unset compile_mode ]) ###################################################################### # # MCA_CONFIGURE_ALL_CONFIG_COMPONENTS # # configure all components in the given framework that have configure # scripts and should be configured according to the usual rules... # # USAGE: # MCA_CONFIGURE_ALL_CONFIG_COMPONENTS(framework_name, # all_components_variable, # static_components_variable, # dso_components_variable, # static_ltlibs_variable) # ###################################################################### AC_DEFUN([MCA_CONFIGURE_ALL_CONFIG_COMPONENTS],[ for component_path in $srcdir/src/mca/$1/* ; do component="`basename $component_path`" if test -d $component_path && test -x $component_path/configure ; then pmix_show_subsubsubtitle "MCA component $1:$component (need to configure)" pmix_show_verbose "PMIX_MCA_ALL_CONFIG_COMPONENTS: before, should_build=$7" MCA_COMPONENT_BUILD_CHECK($1, $component, [should_build=1], [should_build=0]) MCA_COMPONENT_COMPILE_MODE($1, $component, compile_mode) pmix_show_verbose "PMIX_MCA_ALL_CONFIG_COMPONENTS: after, should_build=$should_build" if test "$should_build" = "1" ; then PMIX_CONFIG_SUBDIR([src/mca/$1/$component], [$pmix_subdir_args], [should_build=1], [should_build=0]) pmix_show_verbose "PMIX_MCA_ALL_CONFIG_COMPONENTS: after subdir, should_build=$should_build" fi if test "$should_build" = "1" ; then # do some extra work to pass flags back from the # top-level configure, the way a configure.m4 # component would. infile="$srcdir/src/mca/$1/$2/post_configure.sh" if test -f $infile; then # First check for the ABORT tag line="`$GREP ABORT= $infile | cut -d= -f2-`" if test -n "$line" && test "$line" != "no"; then AC_MSG_WARN([MCA component configure script told me to abort]) AC_MSG_ERROR([cannot continue]) fi fi MCA_PROCESS_COMPONENT($1, $component, $2, $3, $4, $5, $compile_mode) else MCA_PROCESS_DEAD_COMPONENT($1, $component) fi fi done ]) # MCA_COMPONENT_COMPILE_MODE(framework_name (1), # component_name (2), compile_mode_variable (3)) # ------------------------------------------------------------------------- # set compile_mode_variable to the compile mode for the given component # # NOTE: component_name may not be determined until runtime.... AC_DEFUN([MCA_COMPONENT_COMPILE_MODE],[ SHARED_FRAMEWORK="$DSO_$1" AS_LITERAL_IF([$2], [SHARED_COMPONENT="$DSO_$1_$2"], [str="SHARED_COMPONENT=\$DSO_$1_$2" eval $str]) STATIC_FRAMEWORK="$STATIC_$1" AS_LITERAL_IF([$2], [STATIC_COMPONENT="$STATIC_$1_$2"], [str="STATIC_COMPONENT=\$STATIC_$1_$2" eval $str]) # Look for the most specific specifier between static/dso. If # there is a tie (either neither or both specified), prefer # static. if test "$STATIC_COMPONENT" = "1"; then $3=static elif test "$SHARED_COMPONENT" = "1"; then $3=dso elif test "$STATIC_FRAMEWORK" = "1"; then $3=static elif test "$SHARED_FRAMEWORK" = "1"; then $3=dso elif test "$STATIC_all" = "1"; then $3=static elif test "$DSO_all" = "1"; then $3=dso else $3=static fi AC_MSG_CHECKING([for MCA component $1:$2 compile mode]) AC_MSG_RESULT([$$3]) ]) # PMIX_MCA_STRIP_LAFILES(output_variable(1), # input_list(2) #-------------------------------------------- # Helper function to MCA_PROCESS_COMPONENT which will strip # any .la file entries in the LIBS list. Used for when copying # a component's LIBS into WRAPPER_LIBS. AC_DEFUN([PMIX_MCA_STRIP_LAFILES], [ PMIX_VAR_SCOPE_PUSH([pmix_tmp]) $1= for arg in $2; do pmix_tmp=`echo $arg | awk '{print substr([$][1], length([$][1])-2) }'` AS_IF([test "$pmix_tmp" != ".la"], [PMIX_APPEND([$1], [$arg])]) done PMIX_VAR_SCOPE_POP ]) # MCA_PROCESS_COMPONENT(framework_name (1), component_name (2), # all_components_variable (3), static_components_variable (4) # dso_components_variable (5), static_ltlibs_variable (6), # compile_mode_variable (7)) #--------------------------------------------------------------------- # Final setup work for a given component. It should be known before # calling that this component can build properly (and exists) # # NOTE: component_name may not be determined until runtime.... AC_DEFUN([MCA_PROCESS_COMPONENT],[ AC_REQUIRE([AC_PROG_GREP]) # See if it dropped an output file for us to pick up some # shell variables in. infile="$srcdir/src/mca/$1/$2/post_configure.sh" # Add this subdir to the mast list of all MCA component subdirs $3="$$3 $2" if test "$7" = "dso" ; then $5="$$5 $2" else if test "$1" = "common"; then # Static libraries in "common" frameworks are installed, and # therefore must obey the $FRAMEWORK_LIB_PREFIX that was # set. $6="mca/$1/$2/lib${m4_translit([pmix], [a-z], [A-Z])_LIB_PREFIX}pmix_mca_$1_$2.la $$6" else # Other frameworks do not have to obey the # $FRAMEWORK_LIB_PREFIX prefix. $6="mca/$1/$2/libpmix_mca_$1_$2.la $$6" fi echo "extern const pmix_mca_base_component_t *pmix_mca_$1_$2_component_ptr;" >> $outfile.extern echo " &pmix_mca_$1_$2_component_ptr, " >> $outfile.struct $4="$$4 $2" fi # Output pretty results AC_MSG_CHECKING([if MCA component $1:$2 can compile]) AC_MSG_RESULT([yes]) # If a component is building static (ie, sucked into the parent # library), we need to provide LDFLAGS and LIBS and pkg-config # module name configuration to the wrapper compiler, so that it # can provide them for the final link of the application. # Components can explicitly set # __WRAPPER_EXTRA_ for LDFLAGS, LIBS, # or PC_MODULES, for cases where the component wants to explicitly # manage which flags are passed to the wrapper compiler. If the # __WRAPPER_EXTRA_ variable is not # set, then it is assumed that the component wishes all LDFLAGS, # LIBS, and PC_MODULES to be provided as wrapper flags. AS_IF([test "$7" = "static"], [AS_VAR_SET_IF([$1_$2_WRAPPER_EXTRA_LDFLAGS], [AS_VAR_COPY([tmp_flags], [$1_$2_WRAPPER_EXTRA_LDFLAGS])], [AS_VAR_COPY([tmp_flags], [$1_$2_LDFLAGS])]) PMIX_FLAGS_APPEND_UNIQ([pmix_mca_wrapper_extra_ldflags], [$tmp_flags]) AS_VAR_SET_IF([$1_$2_WRAPPER_EXTRA_STATIC_LDFLAGS], [AS_VAR_COPY([tmp_flags], [$1_$2_WRAPPER_EXTRA_STATIC_LDFLAGS])], [AS_VAR_COPY([tmp_flags], [$1_$2_STATIC_LDFLAGS])]) PMIX_FLAGS_APPEND_UNIQ([pmix_mca_wrapper_extra_static_ldflags], [$tmp_flags]) AS_VAR_SET_IF([$1_$2_WRAPPER_EXTRA_PC_MODULES], [AS_VAR_COPY([tmp_flags], [$1_$2_WRAPPER_EXTRA_PC_MODULES])], [AS_VAR_COPY([tmp_flags], [$1_$2_PC_MODULES])]) PMIX_APPEND_UNIQ([pmix_mca_wrapper_extra_pc_modules], [$tmp_flags]) AS_VAR_SET_IF([$1_$2_WRAPPER_EXTRA_LIBS], [AS_VAR_COPY([tmp_flags], [$1_$1_WRAPPER_EXTRA_LIBS])], [AS_VAR_COPY([tmp_all_flags], [$1_$2_LIBS]) PMIX_MCA_STRIP_LAFILES([tmp_flags], [$tmp_all_flags])]) PMIX_FLAGS_APPEND_MOVE([pmix_mca_wrapper_extra_libs], [$tmp_flags]) AS_VAR_SET_IF([$1_$2_WRAPPER_EXTRA_STATIC_LIBS], [AS_VAR_COPY([tmp_flags], [$1_$1_WRAPPER_EXTRA_STATIC_LIBS])], [AS_VAR_COPY([tmp_all_flags], [$1_$2_STATIC_LIBS]) PMIX_MCA_STRIP_LAFILES([tmp_flags], [$tmp_all_flags])]) echo "Adding static libs $tmp_flags" PMIX_FLAGS_APPEND_MOVE([pmix_mca_wrapper_extra_static_libs], [$tmp_flags])]) # WRAPPER_EXTRA_CPPFLAGS are only needed for STOP_AT_FIRST # components, as all other components are not allowed to leak # headers or compile-time flags into the top-level library or # wrapper compilers. If needed, copy over WRAPPER_EXTRA_CPPFLAGS. # Since a configure script component can never be used in a # STOP_AT_FIRST framework, we don't have to implement the else # clause in the literal check. AS_LITERAL_IF([$2], [AS_IF([test "$$1_$2_WRAPPER_EXTRA_CPPFLAGS" != ""], [m4_if(PMIX_EVAL_ARG([MCA_$1_CONFIGURE_MODE]), [STOP_AT_FIRST], [stop_at_first=1], [stop_at_first=0]) AS_IF([test "$8" = "static" && test "$stop_at_first" = "1"], [AS_IF([test "$with_devel_headers" = "yes"], [PMIX_FLAGS_APPEND_UNIQ([pmix_mca_wrapper_extra_cppflags], [$$2_$3_WRAPPER_EXTRA_CPPFLAGS])])], [AC_MSG_WARN([ignoring $1_$2_WRAPPER_EXTRA_CPPFLAGS ($$1_$2_WRAPPER_EXTRA_CPPFLAGS): component conditions not met])])])]) ]) # MCA_PROCESS_DEAD_COMPONENT(framework_name (1), # component_name (2)) # ---------------------------------------------------------------- # Finall setup work for a component that can not be built. Do the # last minute checks to make sure the user isn't doing something # stupid. # # NOTE: component_name may not be determined until runtime.... AC_DEFUN([MCA_PROCESS_DEAD_COMPONENT],[ AC_MSG_CHECKING([if MCA component $1:$2 can compile]) AC_MSG_RESULT([no]) # If this component was requested as the default for this # type, then abort. if test "$with_$1" = "$2" ; then AC_MSG_WARN([MCA component "$2" failed to configure properly]) AC_MSG_WARN([This component was selected as the default]) AC_MSG_ERROR([Cannot continue]) fi ]) # MCA_COMPONENT_BUILD_CHECK(framework_name(1), # component_name (2), action-if-build (3) # action-if-not-build (4) # ----------------------------------------------------------------- # checks the standard rules of component building to see if the # given component should be built. # # Note: component_name may not be determined until runtime.... AC_DEFUN([MCA_COMPONENT_BUILD_CHECK],[ AC_REQUIRE([AC_PROG_GREP]) component_path="$srcdir/src/mca/$1/$2" want_component=0 # build if: # - there is no pmix_ignore file # - there is an pmix_ignore, but there is an empty pmix_unignore # - there is an pmix_ignore, but username is in pmix_unignore if test -d $component_path ; then # decide if we want the component to be built or not. This # is spread out because some of the logic is a little complex # and test's syntax isn't exactly the greatest. We want to # build the component by default. want_component=1 if test -f $component_path/.pmix_ignore ; then # If there is an pmix_ignore file, don't build # the component. Note that this decision can be # overridden by the unignore logic below. want_component=0 fi if test -f $component_path/.pmix_unignore ; then # if there is an empty pmix_unignore, that is # equivalent to having your userid in the unignore file. # If userid is in the file, unignore the ignore file. if test ! -s $component_path/.pmix_unignore ; then want_component=1 elif test ! -z "`$GREP $PMIX_CONFIGURE_USER $component_path/.pmix_unignore`" ; then want_component=1 fi fi fi # if we were explicitly disabled, don't build :) AS_IF([test "$DISABLE_$1" = "1"], [want_component=0]) AS_LITERAL_IF([$2], [AS_IF([test "$DISABLE_$1_$2" = "1"], [want_component=0])], [str="DISABLED_COMPONENT_CHECK=\$DISABLE_$1_$2" eval $str if test "$DISABLED_COMPONENT_CHECK" = "1" ; then want_component=0 fi]) AS_IF([test "$want_component" = "1"], [$3], [$4]) ]) # PMIX_MCA_MAKE_DIR_LIST(subst'ed variable, framework, shell list) # ------------------------------------------------------------------------- AC_DEFUN([PMIX_MCA_MAKE_DIR_LIST],[ $1= for item in $3 ; do $1="$$1 mca/$2/$item" done AC_SUBST($1) ]) pmix-6.1.1~rc2/config/pmix_check_compiler_version.m40000664000175000017500000000341515203536752022760 0ustar alastairalastairdnl -*- shell-script -*- dnl dnl Copyright (c) 2009 Oak Ridge National Labs. All rights reserved. dnl Copyright (c) 2021 Cisco Systems, Inc. All rights reserved. dnl Copyright (c) 2021 Amazon.com, Inc. or its affiliates. All Rights dnl reserved. dnl dnl Copyright (c) 2021-2026 Nanook Consulting All rights reserved. dnl $COPYRIGHT$ dnl dnl Additional copyrights may follow dnl dnl $HEADER$ dnl # PMIX_CHECK_COMPILER_VERSION_ID() # ---------------------------------------------------- # Try to figure out the compiler's name and version to detect cases, # where users compile Open MPI with one version and compile the application # with a different compiler. # AC_DEFUN([PMIX_CHECK_COMPILER_VERSION_ID], [ PMIX_CHECK_COMPILER(FAMILYID) PMIX_CHECK_COMPILER(VERSION) ])dnl AC_DEFUN([PMIX_CHECK_COMPILER], [ AS_LITERAL_IF([$1], [], [m4_fatal([PMIX_CHECK_COMPILER argument must be a literal])]) lower=m4_tolower([$1]) AC_CACHE_CHECK([for compiler $lower], [pmix_cv_compiler_$1], [ CPPFLAGS_orig=$CPPFLAGS CPPFLAGS="-I${PMIX_TOP_SRCDIR} $CPPFLAGS" AC_RUN_IFELSE([AC_LANG_PROGRAM([[ #include #include #include "src/include/pmix_portable_platform.h" ]],[[ FILE * f; f=fopen("conftestval", "w"); if (!f) exit(1); fprintf (f, "%d", PLATFORM_COMPILER_$1); ]])], [ pmix_cv_compiler_$1=`cat conftestval` ], [ pmix_cv_compiler_$1=0 ], [ pmix_cv_compiler_$1=0 ]) CPPFLAGS=$CPPFLAGS_orig ]) AC_DEFINE_UNQUOTED([PMIX_BUILD_PLATFORM_COMPILER_$1], [$pmix_cv_compiler_$1], [The compiler $lower which OMPI was built with]) ])dnl pmix-6.1.1~rc2/config/pmix_check_jansson.m40000664000175000017500000000662115203536752021056 0ustar alastairalastair# -*- autoconf -*- # # Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2006 The Regents of the University of California. # All rights reserved. # Copyright (c) 2006 QLogic Corp. All rights reserved. # Copyright (c) 2009-2016 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2016-2020 Intel, Inc. All rights reserved. # Copyright (c) 2015 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2016 Los Alamos National Security, LLC. All rights # reserved. # Copyright (c) 2021 Nanook Consulting. All rights reserved. # Copyright (c) 2022 Amazon.com, Inc. or its affiliates. # All Rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # PMIX_CHECK_JANSSON # -------------------------------------------------------- # check if JANSSON support can be found. sets jansson_{CPPFLAGS, # LDFLAGS, LIBS} AC_DEFUN([PMIX_CHECK_JANSSON],[ PMIX_VAR_SCOPE_PUSH([pmix_check_jansson_save_CPPFLAGS]) dnl Intentionally disable Jansson unless explicitly requested AC_ARG_WITH([jansson], [AS_HELP_STRING([--with-jansson(=DIR)], [Build jansson support (default=no), optionally adding DIR/include, DIR/lib, and DIR/lib64 to the search path for headers and libraries])], [], [with_jansson=no]) AC_ARG_WITH([jansson-libdir], [AS_HELP_STRING([--with-jansson-libdir=DIR], [Search for Jansson libraries in DIR])]) OAC_CHECK_PACKAGE([jansson], [pmix_check_jansson], [jansson.h], [jansson], [json_loads], [pmix_check_jansson_happy="yes"], [pmix_check_jansson_happy="no"]) if test "$pmix_check_jansson_happy" = "yes"; then AC_MSG_CHECKING([if libjansson version is 2.11 or greater]) pmix_check_jansson_save_CPPFLAGS="${CPPFLAGS}" PMIX_FLAGS_APPEND_UNIQ([CPPFLAGS], [${pmix_check_jansson_CPPFLAGS}]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[ #if JANSSON_VERSION_HEX < 0x00020b00 #error "jansson API version is less than 2.11" #endif ]])], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) pmix_check_jansson_happy=no]) CPPFLAGS="$pmix_check_jansson_save_CPPFLAGS" fi AS_IF([test "$pmix_check_jansson_happy" = "no" -a "$with_jansson" != "no"], [AC_MSG_ERROR([Jansson support requested but not found. Aborting])]) AC_MSG_CHECKING([Jansson support available]) AC_MSG_RESULT([$pmix_check_jansson_happy]) AM_CONDITIONAL([HAVE_JANSSON], [test "$pmix_check_jansson_happy" = "yes"]) PMIX_SUMMARY_ADD([External Packages], [Jansson], [], [${pmix_check_jansson_SUMMARY}]) PMIX_VAR_SCOPE_POP ]) pmix-6.1.1~rc2/config/pmix_get_version.sh0000775000175000017500000001176315203536752020672 0ustar alastairalastair#!/bin/sh # # Copyright (c) 2004-2006 The Trustees of Indiana University and Indiana # University Research and Technology # Corporation. All rights reserved. # Copyright (c) 2004-2005 The University of Tennessee and The University # of Tennessee Research Foundation. All rights # reserved. # Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. # Copyright (c) 2008-2020 Cisco Systems, Inc. All rights reserved # Copyright (c) 2015-2020 Intel, Inc. All rights reserved. # Copyright (c) 2021-2022 IBM Corporation. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow # # $HEADER$ # # PMIX_GET_VERSION(version_file, variable_prefix) # ----------------------------------------------- # parse version_file for version information, setting # the following shell variables: # # prefix_VERSION # prefix_BASE_VERSION # prefix_MAJOR_VERSION # prefix_MINOR_VERSION # prefix_RELEASE_VERSION # prefix_GREEK_VERSION # prefix_REPO_REV # prefix_TARBALL_VERSION # prefix_RELEASE_DATE srcfile="$1" option="$2" if test -z "$srcfile"; then option="--help" else if test -f "$srcfile"; then srcdir=`dirname $srcfile` pmix_vers=`sed -n " t clear : clear s/^major/PMIX_MAJOR_VERSION/ s/^minor/PMIX_MINOR_VERSION/ s/^release/PMIX_RELEASE_VERSION/ s/^greek/PMIX_GREEK_VERSION/ s/^std_major/PMIX_STD_MAJOR_VERSION/ s/^std_minor/PMIX_STD_MINOR_VERSION/ s/^std_abi_stable/PMIX_STD_ABI_STABLE_VERSION/ s/^std_abi_provisional/PMIX_STD_ABI_PROVISIONAL_VERSION/ s/^repo_rev/PMIX_REPO_REV/ s/^tarball_version/PMIX_TARBALL_VERSION/ s/^date/PMIX_RELEASE_DATE/ t print b : print p" < "$srcfile"` eval "$pmix_vers" PMIX_VERSION="$PMIX_MAJOR_VERSION.$PMIX_MINOR_VERSION.$PMIX_RELEASE_VERSION" PMIX_VERSION="${PMIX_VERSION}${PMIX_GREEK_VERSION}" PMIX_STD_VERSION="$PMIX_STD_MAJOR_VERSION.$PMIX_STD_MINOR_VERSION" PMIX_STD_ABI_STABLE_VERSION="$PMIX_STD_ABI_STABLE_VERSION" PMIX_STD_ABI_PROVISIONAL_VERSION="$PMIX_STD_ABI_PROVISIONAL_VERSION" if test "$PMIX_TARBALL_VERSION" = ""; then PMIX_TARBALL_VERSION=$PMIX_VERSION fi # If repo_rev was not set in the VERSION file, then get it now if test "$PMIX_REPO_REV" = ""; then # See if we can find the "git" command. git_happy=0 git --version > /dev/null 2>&1 if test $? -eq 0; then git_happy=1 fi # If we're in a git repo and we found the git command, use # git describe to get the repo rev if test -r "$srcdir/.git" && test $git_happy -eq 1; then if test "$srcdir" != "`pwd`"; then git_save_dir=`pwd` cd "$srcdir" PMIX_REPO_REV=`git describe --tags --always` cd "$git_save_dir" unset git_save_dir else PMIX_REPO_REV=`git describe --tags --always` fi else PMIX_REPO_REV=`$srcdir/config/getdate.sh '+%Y-%m-%d'` fi fi fi if test "$option" = ""; then option="--full" fi fi case "$option" in --full|-v|--version) echo $PMIX_VERSION ;; --major) echo $PMIX_MAJOR_VERSION ;; --minor) echo $PMIX_MINOR_VERSION ;; --release) echo $PMIX_RELEASE_VERSION ;; --greek) echo $PMIX_GREEK_VERSION ;; --std-version) echo $PMIX_STD_VERSION ;; --std-abi-stable-version) echo $PMIX_STD_ABI_STABLE_VERSION ;; --std-abi-provisional-version) echo $PMIX_STD_ABI_PROVISIONAL_VERSION ;; --repo-rev) echo $PMIX_REPO_REV ;; --tarball) echo $PMIX_TARBALL_VERSION ;; --release-date) echo $PMIX_RELEASE_DATE ;; --all) echo ${PMIX_VERSION} : ${PMIX_MAJOR_VERSION} : ${PMIX_MINOR_VERSION} : ${PMIX_RELEASE_VERSION} : ${PMIX_GREEK_VERSION} : ${PMIX_REPO_REV} : ${PMIX_TARBALL_VERSION} ;; -h|--help) cat <