diff --git a/NEWS b/NEWS index 01ed04d9ef7fc9526f581e7087bd49bf558d598a..73bbc3cbe087376bccff1e5bd6ac0b0d091874b3 100644 --- a/NEWS +++ b/NEWS @@ -52,6 +52,10 @@ documents those changes that are of interest to users and admins. -- Add support for job time limit specification formats: min, min:sec, hour:min:sec, and days-hour:min:sec (formerly only supported minutes). Applies to salloc, sbatch, and srun commands. + -- Improve scheduling support for exclusive constraint list, nodes can + now be in more than one constraint specific exclusively for a job + (e.g. "srun -C [rack1|rack2|rack3|rowB] srun") + -- Create separate MPICH/MX plugin (split out from MPICH/GM plugin) * Changes in SLURM 1.2.12 ========================= diff --git a/configure b/configure index 39ed9e6f1e47311d3b82716cf6b30782ffd88e5b..a74ad03255ece9fcb6ce7c938f5fc33543e40b87 100755 --- a/configure +++ b/configure @@ -26612,7 +26612,7 @@ _ACEOF -ac_config_files="$ac_config_files Makefile config.xml auxdir/Makefile contribs/Makefile contribs/perlapi/Makefile contribs/perlapi/libslurm-perl/Makefile.PL contribs/torque/Makefile src/Makefile src/api/Makefile src/common/Makefile src/sacct/Makefile src/salloc/Makefile src/sbatch/Makefile src/sattach/Makefile src/srun/Makefile src/slaunch/Makefile src/slurmd/Makefile src/slurmd/slurmd/Makefile src/slurmd/slurmstepd/Makefile src/slurmctld/Makefile src/sbcast/Makefile src/scontrol/Makefile src/scancel/Makefile src/squeue/Makefile src/sinfo/Makefile src/smap/Makefile src/strigger/Makefile src/sview/Makefile src/plugins/Makefile src/plugins/auth/Makefile src/plugins/auth/authd/Makefile src/plugins/auth/munge/Makefile src/plugins/auth/none/Makefile src/plugins/checkpoint/Makefile src/plugins/checkpoint/aix/Makefile src/plugins/checkpoint/none/Makefile src/plugins/crypto/Makefile src/plugins/crypto/munge/Makefile src/plugins/crypto/openssl/Makefile src/plugins/jobacct/Makefile src/plugins/jobacct/linux/Makefile src/plugins/jobacct/aix/Makefile src/plugins/jobacct/none/Makefile src/plugins/jobcomp/Makefile src/plugins/jobcomp/filetxt/Makefile src/plugins/jobcomp/none/Makefile src/plugins/jobcomp/script/Makefile src/plugins/jobcomp/database/Makefile src/plugins/proctrack/Makefile src/plugins/proctrack/aix/Makefile src/plugins/proctrack/pgid/Makefile src/plugins/proctrack/linuxproc/Makefile src/plugins/proctrack/rms/Makefile src/plugins/proctrack/sgi_job/Makefile src/plugins/sched/Makefile src/plugins/sched/backfill/Makefile src/plugins/sched/builtin/Makefile src/plugins/sched/gang/Makefile src/plugins/sched/hold/Makefile src/plugins/sched/wiki/Makefile src/plugins/sched/wiki2/Makefile src/plugins/select/Makefile src/plugins/select/bluegene/Makefile src/plugins/select/bluegene/block_allocator/Makefile src/plugins/select/bluegene/plugin/Makefile src/plugins/select/linear/Makefile src/plugins/select/cons_res/Makefile src/plugins/switch/Makefile src/plugins/switch/elan/Makefile src/plugins/switch/none/Makefile src/plugins/switch/federation/Makefile src/plugins/mpi/Makefile src/plugins/mpi/mpich1_p4/Makefile src/plugins/mpi/mpich1_shmem/Makefile src/plugins/mpi/mpichgm/Makefile src/plugins/mpi/mvapich/Makefile src/plugins/mpi/lam/Makefile src/plugins/mpi/none/Makefile src/plugins/mpi/openmpi/Makefile src/plugins/task/Makefile src/plugins/task/affinity/Makefile src/plugins/task/none/Makefile src/plugins/database/Makefile src/plugins/database/flatfile/Makefile src/plugins/database/mysql/Makefile src/plugins/database/pgsql/Makefile doc/Makefile doc/man/Makefile doc/html/Makefile doc/html/configurator.html testsuite/Makefile testsuite/expect/Makefile testsuite/slurm_unit/Makefile testsuite/slurm_unit/common/Makefile testsuite/slurm_unit/slurmctld/Makefile testsuite/slurm_unit/slurmd/Makefile testsuite/slurm_unit/api/Makefile testsuite/slurm_unit/api/manual/Makefile" +ac_config_files="$ac_config_files Makefile config.xml auxdir/Makefile contribs/Makefile contribs/perlapi/Makefile contribs/perlapi/libslurm-perl/Makefile.PL contribs/torque/Makefile src/Makefile src/api/Makefile src/common/Makefile src/sacct/Makefile src/salloc/Makefile src/sbatch/Makefile src/sattach/Makefile src/srun/Makefile src/slaunch/Makefile src/slurmd/Makefile src/slurmd/slurmd/Makefile src/slurmd/slurmstepd/Makefile src/slurmctld/Makefile src/sbcast/Makefile src/scontrol/Makefile src/scancel/Makefile src/squeue/Makefile src/sinfo/Makefile src/smap/Makefile src/strigger/Makefile src/sview/Makefile src/plugins/Makefile src/plugins/auth/Makefile src/plugins/auth/authd/Makefile src/plugins/auth/munge/Makefile src/plugins/auth/none/Makefile src/plugins/checkpoint/Makefile src/plugins/checkpoint/aix/Makefile src/plugins/checkpoint/none/Makefile src/plugins/crypto/Makefile src/plugins/crypto/munge/Makefile src/plugins/crypto/openssl/Makefile src/plugins/jobacct/Makefile src/plugins/jobacct/linux/Makefile src/plugins/jobacct/aix/Makefile src/plugins/jobacct/none/Makefile src/plugins/jobcomp/Makefile src/plugins/jobcomp/filetxt/Makefile src/plugins/jobcomp/none/Makefile src/plugins/jobcomp/script/Makefile src/plugins/jobcomp/database/Makefile src/plugins/proctrack/Makefile src/plugins/proctrack/aix/Makefile src/plugins/proctrack/pgid/Makefile src/plugins/proctrack/linuxproc/Makefile src/plugins/proctrack/rms/Makefile src/plugins/proctrack/sgi_job/Makefile src/plugins/sched/Makefile src/plugins/sched/backfill/Makefile src/plugins/sched/builtin/Makefile src/plugins/sched/gang/Makefile src/plugins/sched/hold/Makefile src/plugins/sched/wiki/Makefile src/plugins/sched/wiki2/Makefile src/plugins/select/Makefile src/plugins/select/bluegene/Makefile src/plugins/select/bluegene/block_allocator/Makefile src/plugins/select/bluegene/plugin/Makefile src/plugins/select/linear/Makefile src/plugins/select/cons_res/Makefile src/plugins/switch/Makefile src/plugins/switch/elan/Makefile src/plugins/switch/none/Makefile src/plugins/switch/federation/Makefile src/plugins/mpi/Makefile src/plugins/mpi/mpich1_p4/Makefile src/plugins/mpi/mpich1_shmem/Makefile src/plugins/mpi/mpichgm/Makefile src/plugins/mpi/mpichmx/Makefile src/plugins/mpi/mvapich/Makefile src/plugins/mpi/lam/Makefile src/plugins/mpi/none/Makefile src/plugins/mpi/openmpi/Makefile src/plugins/task/Makefile src/plugins/task/affinity/Makefile src/plugins/task/none/Makefile src/plugins/database/Makefile src/plugins/database/flatfile/Makefile src/plugins/database/mysql/Makefile src/plugins/database/pgsql/Makefile doc/Makefile doc/man/Makefile doc/html/Makefile doc/html/configurator.html testsuite/Makefile testsuite/expect/Makefile testsuite/slurm_unit/Makefile testsuite/slurm_unit/common/Makefile testsuite/slurm_unit/slurmctld/Makefile testsuite/slurm_unit/slurmd/Makefile testsuite/slurm_unit/api/Makefile testsuite/slurm_unit/api/manual/Makefile" cat >confcache <<\_ACEOF @@ -27403,6 +27403,7 @@ do "src/plugins/mpi/mpich1_p4/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/mpi/mpich1_p4/Makefile" ;; "src/plugins/mpi/mpich1_shmem/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/mpi/mpich1_shmem/Makefile" ;; "src/plugins/mpi/mpichgm/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/mpi/mpichgm/Makefile" ;; + "src/plugins/mpi/mpichmx/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/mpi/mpichmx/Makefile" ;; "src/plugins/mpi/mvapich/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/mpi/mvapich/Makefile" ;; "src/plugins/mpi/lam/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/mpi/lam/Makefile" ;; "src/plugins/mpi/none/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/mpi/none/Makefile" ;; diff --git a/configure.ac b/configure.ac index 761eaa4c1dd1d7c92423b5a4b4b4c317a3b9eec7..cecb74a6dd2df6a90e4505585e90e334cd469511 100644 --- a/configure.ac +++ b/configure.ac @@ -318,6 +318,7 @@ AC_CONFIG_FILES([Makefile src/plugins/mpi/mpich1_p4/Makefile src/plugins/mpi/mpich1_shmem/Makefile src/plugins/mpi/mpichgm/Makefile + src/plugins/mpi/mpichmx/Makefile src/plugins/mpi/mvapich/Makefile src/plugins/mpi/lam/Makefile src/plugins/mpi/none/Makefile diff --git a/contribs/perlapi/libslurm-perl/Makefile.PL.in b/contribs/perlapi/libslurm-perl/Makefile.PL.in index 1afcc798c8e220ffd3d2a651446e22065a304c68..260b29eb52fcf9d5cb1b4b36cd67bf625a0d7744 100644 --- a/contribs/perlapi/libslurm-perl/Makefile.PL.in +++ b/contribs/perlapi/libslurm-perl/Makefile.PL.in @@ -11,6 +11,69 @@ following link(s): @prefix@/lib/libslurm.so\n"); } +# Most all the extra code is to deal with MakeMaker < 6.11 not working +# correctly to build rpms + +my( + $mm_version, + $mm_knows_destdir, + $mm_has_destdir, + $mm_has_good_destdir, + $mm_needs_destdir, + ); + +# Gather some information about what EU::MM offers and/or needs + +# Store the version for later use +$mm_version = $ExtUtils::MakeMaker::VERSION; + +# MakeMaker prior to 6.11 doesn't support DESTDIR which is needed for +# packaging with builddir!=destdir. See bug 2388. +$mm_knows_destdir = $ExtUtils::MakeMaker::Recognized_Att_Keys{DESTDIR}; +$mm_has_good_destdir = $mm_version >= 6.11; +# Add DESTDIR hack only if it's requested (and necessary) +$mm_needs_destdir = !$mm_has_good_destdir; +$mm_has_destdir = $mm_knows_destdir || $mm_needs_destdir; +$ExtUtils::MakeMaker::Recognized_Att_Keys{"DESTDIR"} = 1 if $mm_needs_destdir; + +if ($mm_needs_destdir) { + my $error = <<DESTDIR_HACK; + + *********************************************************************** + ExtUtils::MakeMaker ${mm_version} does not include support for DESTDIR, + so if you want to be on the safe side, you might want to upgrade your + ExtUtils::MakeMaker to version 6.11 or later. It is available via CPAN. + + You can use either the CPAN shell or go to + <http://search.cpan.org/search?module=ExtUtils::MakeMaker> + to get an up-to-date version. + + This should only be necessary if you are creating binary packages. + *********************************************************************** + +DESTDIR_HACK + $error =~ s/^ {4}//gm; + warn $error; +} elsif (!$mm_has_good_destdir) { + my $error = <<DESTDIR_BUG; + + *********************************************************************** + ExtUtils::MakeMaker ${mm_version} contains bugs that may cause problems + in the \"make\" process. It is recommended that you upgrade + ExtUtils::MakeMaker to version 6.11 or later. It is available via CPAN. + + You can use either the CPAN shell or go to + <http://search.cpan.org/search?module=ExtUtils::MakeMaker> + to get an up-to-date version. + + This should only be necessary if you are creating binary packages. + *********************************************************************** + +DESTDIR_BUG + $error =~ s/^ {4}//gm; + warn $error; +} + WriteMakefile( NAME => 'Slurm', VERSION_FROM => 'Slurm.pm', # finds $VERSION @@ -187,3 +250,203 @@ else { die "Error creating constant files: $!"; } +# Override the install routine to add our additional install dirs and +# hack DESTDIR support into old EU::MMs. +sub MY::install { + package MY; + my $self = shift; + my @code = split(/\n/, $self->SUPER::install(@_)); + init_MY_globals($self); + + foreach (@code) { + # Write the correct path to perllocal.pod + next if /installed into/; + + # Replace all other $(INSTALL*) vars (except $(INSTALLDIRS) of course) + # with their $(DESTINSTALL*) counterparts + s/\Q$(\E(INSTALL(?!DIRS)${MACRO_RE})\Q)\E/\$(DEST$1)/g; + } + + clean_MY_globals($self); + return join("\n", @code); +} + +# Now override the constants routine to add our own macros. +sub MY::constants { + package MY; + my $self = shift; + my @code = split(/\n/, $self->SUPER::constants(@_)); + init_MY_globals($self); + + foreach my $line (@code) { + # Skip comments + next if $line =~ /^\s*\#/; + # Skip everything which isn't a var assignment. + next unless line_has_macro_def($line); + + #tore the assignment string if necessary. + set_EQ_from_line($line); + + # Add some "dummy" (PERL|SITE|VENDOR)PREFIX macros for later use (only if + # necessary for old EU::MMs of course) + if (line_has_macro_def($line, 'PREFIX')) { + foreach my $r (@REPOSITORIES) { + my $rprefix = "${r}PREFIX"; + + if (!defined(get_macro($rprefix))) { + set_macro($rprefix, macro_ref('PREFIX')); + $line .= "\n" . macro_def($rprefix); + } + } + } + + # fix problem with /usr(/local) being used as a prefix + # instead of the real thing. + + if ($line =~ 'INSTALL') { + $line =~ s/= \/usr\/local/= \$(PREFIX)/; + $line =~ s/= \/usr/= \$(PREFIX)/; + } + + # Add DESTDIR support if necessary + if (line_has_macro_def($line, 'INSTALLDIRS')) { + if(!get_macro('DESTDIR')) { + $line .= "\n" . macro_def('DESTDIR'); + } + } elsif (line_has_macro_def($line, + qr/INSTALL${MACRO_RE}/)) { + my $macro = get_macro_name_from_line($line); + if(!get_macro('DEST' . $macro, + macro_ref('DESTDIR') + . macro_ref($macro))) { + $line .= "\n" + . macro_def('DEST' . $macro, + macro_ref('DESTDIR') + . macro_ref($macro)); + } + } + } + push(@code, qq{}); + + clean_MY_globals($self); + return join("\n", @code); +} + + +package MY; + +use vars qw( + @REPOSITORIES + + $MY_GLOBALS_ARE_SANE + + $MACRO_RE + $EQ_RE + $EQ + + $SELF +); + + +sub line_has_macro_def { + my($line, $name) = (@_, undef); + $name = $MACRO_RE unless defined $name; + + return $line =~ /^($name)${EQ_RE}/; +} + + +sub macro_def { + my($name, $val) = (@_, undef); + my $error_message = "Problems building report error."; + + die $error_message unless defined $name; + die $error_message unless defined $EQ; + $val = $SELF->{$name} unless defined $val; + + return $name . $EQ . $val; +} + +sub set_EQ_from_line { + my($line) = (@_); + + return if defined($EQ); + + $line =~ /\S(${EQ_RE})/; + $EQ = $1; +} + +# Reads the name of the macro defined on the given line. +# +# The first parameter must be the line to be expected. If the line doesn't +# contain a macro definition, weird things may happen. So check with +# line_has_macro_def() before! +sub get_macro_name_from_line { + my($line) = (@_); + + $line =~ /^(${MACRO_RE})${EQ_RE}/; + return $1; +} + +sub macro_ref { + my($name) = (@_); + + return sprintf('$(%s)', $name); +} + +# Reads the value of the given macro from the current instance of EU::MM. +# +# The first parameter must be the name of a macro. +sub get_macro { + my($name) = (@_); + + return $SELF->{$name}; +} + +# Sets the value of the macro with the given name to the given value in the +# current instance of EU::MM. Just sets, doesn't write to the Makefile! +# +# The first parameter must be the macro's name, the second the value. +sub set_macro { + my($name, $val) = (@_); + + $SELF->{$name} = $val; +} + +# For some reason initializing the vars on the global scope doesn't work; +# guess its some weird Perl behaviour in combination with bless(). +sub init_MY_globals { + my $self = shift; + + # Keep a reference to ourselves so we don't have to feed it to the helper + # scripts. + $SELF = $self; + + return if $MY_GLOBALS_ARE_SANE; + + $MY_GLOBALS_ARE_SANE = 1; + + @REPOSITORIES = qw( + PERL + SITE + VENDOR + ); + + # Macro names follow this RE -- at least stricly enough for our purposes. + $MACRO_RE = qr/[A-Z0-9_]+/; + # Normally macros are assigned via FOO = bar. But the part with the equal + # sign might differ from platform to platform. So we use this RE: + $EQ_RE = qr/\s*:?=\s*/; + # To assign or own macros we'll follow the first assignment string we find; + # normally " = ". + $EQ = undef; + +} + +# Unset $SELF to avoid any leaking memory. +sub clean_MY_globals { + my $self = shift; + + $SELF = undef; +} + diff --git a/contribs/perlapi/libslurm-perl/alloc.c b/contribs/perlapi/libslurm-perl/alloc.c index 0910813b3eb1c7dec45ba03fdb4301439af25945..e98ed7f8e36befe79f9637c28847b06a25b038c7 100644 --- a/contribs/perlapi/libslurm-perl/alloc.c +++ b/contribs/perlapi/libslurm-perl/alloc.c @@ -131,15 +131,15 @@ hv_to_job_desc_msg(HV* hv, job_desc_msg_t* job_desc_msg) /* geometry */ #if SYSTEM_DIMENSIONS if((svp = hv_fetch(hv, "geometry", 8, FALSE))) { - SV *avp; + AV *avp; if (!SvROK(*svp) || SvTYPE(SvRV(*svp)) != SVt_PVAV) { Perl_warn(aTHX_ "`geometry' is not an array reference in job descriptor"); free_job_desc_msg_memory(job_desc_msg); return -1; } - avp = SvRV(*svp); + avp = (AV*)SvRV(*svp); for(i = 0; i < SYSTEM_DIMENSIONS; i ++) { - if(! (svp = av_fetch(avp, i, 0))) { + if(! (svp = av_fetch(avp, i, FALSE))) { Perl_warn(aTHX_ "geometry of dimension %s missing in job descriptor", i); free_job_desc_msg_memory(job_desc_msg); return -1; diff --git a/doc/html/quickstart.shtml b/doc/html/quickstart.shtml index d37aa790e6e015b73b10f259b702a6ce70b0b114..f5c8ba5499f3779e11b5326f521d8588d6ae5ec1 100644 --- a/doc/html/quickstart.shtml +++ b/doc/html/quickstart.shtml @@ -309,7 +309,6 @@ of 1 or higher for the PMI libary to print debugging information</li> </ul></p> <p><a href="http://www.myri.com/scs/download-mpichgm.html"><b>MPICH-GM</b></a> -and <a href="http://www.myri.com/scs/download-mpichmx.html"><b>MPICH-MX</b></a> jobs can be launched directly by <b>srun</b> command. SLURM's <i>mpichgm</i> MPI plugin must be used to establish communications between the laucnhed tasks. This can be accomplished either using the SLURM @@ -320,6 +319,17 @@ $ mpicc ... $ srun -n16 --mpi=mpichgm a.out </pre> +<p><a href="http://www.myri.com/scs/download-mpichmx.html"><b>MPICH-MX</b></a> +jobs can be launched directly by <b>srun</b> command. +SLURM's <i>mpichmx</i> MPI plugin must be used to establish communications +between the laucnhed tasks. This can be accomplished either using the SLURM +configuration parameter <i>MpiDefault=mpichmx</i> in <b>slurm.conf</b> +or srun's <i>--mpi=mpichmx</i> option. +<pre> +$ mpicc ... +$ srun -n16 --mpi=mpichmx a.out +</pre> + <p><a href="http://nowlab.cse.ohio-state.edu/projects/mpi-iba"><b>MVAPICH</b></a> jobs can be launched directly by <b>srun</b> command. SLURM's <i>mvapich</i> MPI plugin must be used to establish communications @@ -419,6 +429,6 @@ sbatch: Submitted batch job 1234 tasks. These tasks are not managed by SLURM since they are launched outside of its control.</p> -<p style="text-align:center;">Last modified 1 August 2007</p> +<p style="text-align:center;">Last modified 14 August 2007</p> <!--#include virtual="footer.txt"--> diff --git a/doc/html/team.shtml b/doc/html/team.shtml index ab90d33f1b9ebd3259448d7336e90998f0be0e67..1ec2f00d6c4e1417eba5614314d0516953427447 100644 --- a/doc/html/team.shtml +++ b/doc/html/team.shtml @@ -40,6 +40,7 @@ <li>Puenlap Lee (Bull)</li> <li>Bernard Li (Genome Sciences Centre, Canada)</li> <li>Donna Mecozzi (LLNL)</li> +<li>Pere Munt (Barcelona Supercomputer Center, Spain)<li> <li>Bryan O'Sullivan (Pathscale)</li> <li>Gennaro Oliva (Institute of High Performance Computing and Networking, Italy)</li> @@ -56,6 +57,6 @@ Networking, Italy)</li> <li>Anne-Marie Wunderlin (Bull)</li> </ul> -<p style="text-align:center;">Last modified 26 July 2007</p> +<p style="text-align:center;">Last modified 14 August 2007</p> <!--#include virtual="footer.txt"--> diff --git a/doc/man/man1/salloc.1 b/doc/man/man1/salloc.1 index 6518e5ed082e308fef0ceac678fdc74176a88819..e888e4b5d70b42b4cc2b8a54a8ff91a7f64f7d39 100644 --- a/doc/man/man1/salloc.1 +++ b/doc/man/man1/salloc.1 @@ -38,9 +38,10 @@ The value may be changed after job submission using the .TP \fB\-\-bell\fR -Force salloc to ring the terminal bell when the job allocation is granted. -By default, salloc only rings the bell if the allocation is pending for more -than ten seconds. Also see the option \fB\-\-no\-bell\fR. +Force salloc to ring the terminal bell when the job allocation is granted +(and only if stdout is a tty). By default, salloc only rings the bell +if the allocation is pending for more than ten seconds (and only if stdout +is a tty). Also see the option \fB\-\-no\-bell\fR. .TP \fB\-C\fR, \fB\-\-constraint\fR[=]<\fIlist\fR> @@ -51,6 +52,11 @@ The \fIlist\fR of constraints may include multiple features separated by ampersand (AND) and/or vertical bar (OR) operators. For example: \fB\-\-constraint="opteron&video"\fR or \fB\-\-constraint="fast|faster"\fR. +If only one of a set of possible options should be used for all allocated +nodes, then use the OR operator and enclose the options within square brackets. +For example: "\fB\-\-constraint="[rack1|rack2|rack3|rack4]"\fR might +be used to specify that all nodes must be allocated on a single rack of +the cluster, but any of those four racks can be used. If no nodes have the requested features, then the job will be rejected by the slurm job manager. @@ -77,11 +83,6 @@ the \-\-cpus\-per\-task=3 options, the controller knows that each task requires 3 processors on the same node, and the controller will grant an allocation of 4 nodes, one for each of the 4 tasks. -.TP -\fB\-D\fR, \fB\-\-workdir\fR[=]<\fIdirectory\fR> -Set the working directory of the batch script to \fIdirectory\fR before -it it executed. - .TP \fB\-d\fR, \fB\-\-dependency\fR[=]<\fIjobid\fR> Defer the start of this job until the specified \fIjobid\fR has completed. diff --git a/doc/man/man1/sbatch.1 b/doc/man/man1/sbatch.1 index 31592e406b15b635b729be2e54b6fd07a59f3bde..7adc20b75441609cd125a0753b668af483aa9a34 100644 --- a/doc/man/man1/sbatch.1 +++ b/doc/man/man1/sbatch.1 @@ -55,6 +55,11 @@ The \fIlist\fR of constraints may include multiple features separated by ampersand (AND) and/or vertical bar (OR) operators. For example: \fB\-\-constraint="opteron&video"\fR or \fB\-\-constraint="fast|faster"\fR. +If only one of a set of possible options should be used for all allocated +nodes, then use the OR operator and enclose the options within square brackets. +For example: "\fB\-\-constraint="[rack1|rack2|rack3|rack4]"\fR might +be used to specify that all nodes must be allocated on a single rack of +the cluster, but any of those four racks can be used. If no nodes have the requested features, then the job will be rejected by the slurm job manager. diff --git a/doc/man/man1/srun.1 b/doc/man/man1/srun.1 index 6879c4239c418438e173febe5ead3b307b7b783b..c557acea76de9f2a3fe3cc8de1d9008582f3cd7c 100644 --- a/doc/man/man1/srun.1 +++ b/doc/man/man1/srun.1 @@ -72,7 +72,7 @@ For example: .fi .TP -\fB\-C\fR, \fB\-\-constraint\fR=\fIlist\fR +\fB\-C\fR, \fB\-\-constraint\fR[=]<\fIlist\fR> Specify a list of constraints. The constraints are features that have been assigned to the nodes by the slurm administrator. @@ -80,6 +80,11 @@ The \fIlist\fR of constraints may include multiple features separated by ampersand (AND) and/or vertical bar (OR) operators. For example: \fB\-\-constraint="opteron&video"\fR or \fB\-\-constraint="fast|faster"\fR. +If only one of a set of possible options should be used for all allocated +nodes, then use the OR operator and enclose the options within square brackets. +For example: "\fB\-\-constraint="[rack1|rack2|rack3|rack4]"\fR might +be used to specify that all nodes must be allocated on a single rack of +the cluster, but any of those four racks can be used. If no nodes have the requested features, then the job will be rejected by the slurm job manager. diff --git a/slurm.spec b/slurm.spec index 21723047ac096dd2526343713fc5364d68e4df46..060b9e2893ba922ae1ab921399d8bf5ddd15f5de 100644 --- a/slurm.spec +++ b/slurm.spec @@ -320,6 +320,7 @@ rm -rf $RPM_BUILD_ROOT %{_libdir}/slurm/mpi_mpich1_p4.so %{_libdir}/slurm/mpi_mpich1_shmem.so %{_libdir}/slurm/mpi_mpichgm.so +%{_libdir}/slurm/mpi_mpichmx.so %{_libdir}/slurm/mpi_mvapich.so %{_libdir}/slurm/mpi_lam.so %{_libdir}/slurm/task_none.so diff --git a/src/plugins/mpi/Makefile.am b/src/plugins/mpi/Makefile.am index 9db6b883a187eab4513ad253899f12943fde0b6c..c69678ac76d1d59201ceec04a92eb188a27843b3 100644 --- a/src/plugins/mpi/Makefile.am +++ b/src/plugins/mpi/Makefile.am @@ -1,3 +1,3 @@ # Makefile for mpi plugins -SUBDIRS = mpich1_p4 mpich1_shmem mpichgm mvapich none lam openmpi +SUBDIRS = mpich1_p4 mpich1_shmem mpichgm mpichmx mvapich none lam openmpi diff --git a/src/plugins/mpi/Makefile.in b/src/plugins/mpi/Makefile.in index 7bd4680240cf8303ff74d294e8c46205224f12b1..1221af5b4c9c313da0321cab3f4ea01ee85e26a4 100644 --- a/src/plugins/mpi/Makefile.in +++ b/src/plugins/mpi/Makefile.in @@ -240,7 +240,7 @@ target_os = @target_os@ target_vendor = @target_vendor@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -SUBDIRS = mpich1_p4 mpich1_shmem mpichgm mvapich none lam openmpi +SUBDIRS = mpich1_p4 mpich1_shmem mpichgm mpichmx mvapich none lam openmpi all: all-recursive .SUFFIXES: diff --git a/src/plugins/mpi/mpichmx/Makefile.am b/src/plugins/mpi/mpichmx/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..c0bbfaf2bf02d6f843dfaf419c05b047033e8384 --- /dev/null +++ b/src/plugins/mpi/mpichmx/Makefile.am @@ -0,0 +1,14 @@ +# Makefile for mpi/mx plugin + +AUTOMAKE_OPTIONS = foreign + +PLUGIN_FLAGS = -module -avoid-version --export-dynamic + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src/common + +pkglib_LTLIBRARIES = mpi_mpichmx.la + +# Null switch plugin. +mpi_mpichmx_la_SOURCES = mpi_mpichmx.c mpichmx.c mpichmx.h\ + $(top_srcdir)/src/common/mpi.h +mpi_mpichmx_la_LDFLAGS = $(SO_LDFLAGS) $(PLUGIN_FLAGS) diff --git a/src/plugins/mpi/mpichmx/Makefile.in b/src/plugins/mpi/mpichmx/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..4b0feba9c103e3aa209579d345a1012a08cd819a --- /dev/null +++ b/src/plugins/mpi/mpichmx/Makefile.in @@ -0,0 +1,545 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile for mpi/mx plugin + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src/plugins/mpi/mpichmx +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/auxdir/acx_pthread.m4 \ + $(top_srcdir)/auxdir/slurm.m4 \ + $(top_srcdir)/auxdir/x_ac__system_configuration.m4 \ + $(top_srcdir)/auxdir/x_ac_affinity.m4 \ + $(top_srcdir)/auxdir/x_ac_aix.m4 \ + $(top_srcdir)/auxdir/x_ac_bluegene.m4 \ + $(top_srcdir)/auxdir/x_ac_debug.m4 \ + $(top_srcdir)/auxdir/x_ac_elan.m4 \ + $(top_srcdir)/auxdir/x_ac_federation.m4 \ + $(top_srcdir)/auxdir/x_ac_gpl_licensed.m4 \ + $(top_srcdir)/auxdir/x_ac_gtk.m4 \ + $(top_srcdir)/auxdir/x_ac_munge.m4 \ + $(top_srcdir)/auxdir/x_ac_ncurses.m4 \ + $(top_srcdir)/auxdir/x_ac_pam.m4 \ + $(top_srcdir)/auxdir/x_ac_ptrace.m4 \ + $(top_srcdir)/auxdir/x_ac_readline.m4 \ + $(top_srcdir)/auxdir/x_ac_setpgrp.m4 \ + $(top_srcdir)/auxdir/x_ac_setproctitle.m4 \ + $(top_srcdir)/auxdir/x_ac_sgi_job.m4 \ + $(top_srcdir)/auxdir/x_ac_slurm_ssl.m4 \ + $(top_srcdir)/auxdir/x_ac_xcpu.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h $(top_builddir)/slurm/slurm.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(pkglibdir)" +pkglibLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(pkglib_LTLIBRARIES) +mpi_mpichmx_la_LIBADD = +am_mpi_mpichmx_la_OBJECTS = mpi_mpichmx.lo mpichmx.lo +mpi_mpichmx_la_OBJECTS = $(am_mpi_mpichmx_la_OBJECTS) +mpi_mpichmx_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(mpi_mpichmx_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I. -I$(top_builddir) -I$(top_builddir)/slurm@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/auxdir/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(mpi_mpichmx_la_SOURCES) +DIST_SOURCES = $(mpi_mpichmx_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTHD_CFLAGS = @AUTHD_CFLAGS@ +AUTHD_LIBS = @AUTHD_LIBS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BG_INCLUDES = @BG_INCLUDES@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CMD_LDFLAGS = @CMD_LDFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ELAN_LIBS = @ELAN_LIBS@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FEDERATION_LDFLAGS = @FEDERATION_LDFLAGS@ +FFLAGS = @FFLAGS@ +GREP = @GREP@ +GTK2_CFLAGS = @GTK2_CFLAGS@ +GTK2_LIBS = @GTK2_LIBS@ +HAVEPKGCONFIG = @HAVEPKGCONFIG@ +HAVE_AIX = @HAVE_AIX@ +HAVE_ELAN = @HAVE_ELAN@ +HAVE_FEDERATION = @HAVE_FEDERATION@ +HAVE_SOME_CURSES = @HAVE_SOME_CURSES@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_LDFLAGS = @LIB_LDFLAGS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MUNGE_CPPFLAGS = @MUNGE_CPPFLAGS@ +MUNGE_LDFLAGS = @MUNGE_LDFLAGS@ +MUNGE_LIBS = @MUNGE_LIBS@ +NCURSES = @NCURSES@ +NUMA_LIBS = @NUMA_LIBS@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PAM_LIBS = @PAM_LIBS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PLPA_LIBS = @PLPA_LIBS@ +PROCTRACKDIR = @PROCTRACKDIR@ +PROJECT = @PROJECT@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +READLINE_LIBS = @READLINE_LIBS@ +RELEASE = @RELEASE@ +SEMAPHORE_LIBS = @SEMAPHORE_LIBS@ +SEMAPHORE_SOURCES = @SEMAPHORE_SOURCES@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SLURMCTLD_PORT = @SLURMCTLD_PORT@ +SLURMD_PORT = @SLURMD_PORT@ +SLURM_API_AGE = @SLURM_API_AGE@ +SLURM_API_CURRENT = @SLURM_API_CURRENT@ +SLURM_API_MAJOR = @SLURM_API_MAJOR@ +SLURM_API_REVISION = @SLURM_API_REVISION@ +SLURM_API_VERSION = @SLURM_API_VERSION@ +SLURM_MAJOR = @SLURM_MAJOR@ +SLURM_MICRO = @SLURM_MICRO@ +SLURM_MINOR = @SLURM_MINOR@ +SLURM_VERSION = @SLURM_VERSION@ +SO_LDFLAGS = @SO_LDFLAGS@ +SSL_CPPFLAGS = @SSL_CPPFLAGS@ +SSL_LDFLAGS = @SSL_LDFLAGS@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign +PLUGIN_FLAGS = -module -avoid-version --export-dynamic +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src/common +pkglib_LTLIBRARIES = mpi_mpichmx.la + +# Null switch plugin. +mpi_mpichmx_la_SOURCES = mpi_mpichmx.c mpichmx.c mpichmx.h\ + $(top_srcdir)/src/common/mpi.h + +mpi_mpichmx_la_LDFLAGS = $(SO_LDFLAGS) $(PLUGIN_FLAGS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/mpi/mpichmx/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/mpi/mpichmx/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(pkglibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(pkglibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(pkglibdir)/$$f"; \ + else :; fi; \ + done + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +mpi_mpichmx.la: $(mpi_mpichmx_la_OBJECTS) $(mpi_mpichmx_la_DEPENDENCIES) + $(mpi_mpichmx_la_LINK) -rpath $(pkglibdir) $(mpi_mpichmx_la_OBJECTS) $(mpi_mpichmx_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpi_mpichmx.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpichmx.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/plugins/mpi/mpichmx/mpi_mpichmx.c b/src/plugins/mpi/mpichmx/mpi_mpichmx.c new file mode 100644 index 0000000000000000000000000000000000000000..c8fd562f116f0022619de74c17e0ec0b70e141f2 --- /dev/null +++ b/src/plugins/mpi/mpichmx/mpi_mpichmx.c @@ -0,0 +1,119 @@ +/*****************************************************************************\ + ** mpi_mpichmx.c - Library routines for initiating jobs with MPICH-MX + ***************************************************************************** + * Copyright (C) 2004 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Danny Auble <da@llnl.gov> + * UCRL-CODE-226842. + * + * This file is part of SLURM, a resource management program. + * For details, see <http://www.llnl.gov/linux/slurm/>. + * + * SLURM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * In addition, as a special exception, the copyright holders give permission + * to link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. You must obey the GNU + * General Public License in all respects for all of the code used other than + * OpenSSL. If you modify file(s) with this exception, you may extend this + * exception to your version of the file(s), but you are not obligated to do + * so. If you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files in + * the program, then also delete it here. + * + * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with SLURM; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +\*****************************************************************************/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <fcntl.h> +#include <signal.h> +#include <sys/types.h> + +#include <slurm/slurm_errno.h> +#include "src/common/slurm_xlator.h" +#include "src/plugins/mpi/mpichmx/mpichmx.h" + +/* + * These variables are required by the generic plugin interface. If they + * are not found in the plugin, the plugin loader will ignore it. + * + * plugin_name - a string giving a human-readable description of the + * plugin. There is no maximum length, but the symbol must refer to + * a valid string. + * + * plugin_type - a string suggesting the type of the plugin or its + * applicability to a particular form of data or method of data handling. + * If the low-level plugin API is used, the contents of this string are + * unimportant and may be anything. SLURM uses the higher-level plugin + * interface which requires this string to be of the form + * + * <application>/<method> + * + * where <application> is a description of the intended application of + * the plugin (e.g., "switch" for SLURM switch) and <method> is a description + * of how this plugin satisfies that application. SLURM will only load + * a switch plugin if the plugin_type string has a prefix of "switch/". + * + * plugin_version - an unsigned 32-bit integer giving the version number + * of the plugin. If major and minor revisions are desired, the major + * version number may be multiplied by a suitable magnitude constant such + * as 100 or 1000. Various SLURM versions will likely require a certain + * minimum versions for their plugins as this API matures. + */ +const char plugin_name[] = "mpi MPICH-GM plugin"; +const char plugin_type[] = "mpi/mpichgm"; +const uint32_t plugin_version = 100; + +int p_mpi_hook_slurmstepd_task(const mpi_plugin_task_info_t *job, + char ***env) +{ + char addrbuf[1024]; + char *p; + char *addr = getenvp(*env, "SLURM_LAUNCH_NODE_IPADDR"); + + debug("Using mpi/mpich-gm"); + slurm_print_slurm_addr (job->self, addrbuf, sizeof(addrbuf)); + + if ((p = strchr (addrbuf, ':')) != NULL) + *p = '\0'; + + env_array_overwrite_fmt(env, "GMPI_MASTER", "%s", addr); + env_array_overwrite_fmt(env, "GMPI_SLAVE", "%s", addrbuf); + env_array_overwrite_fmt(env, "GMPI_ID", "%u", job->gtaskid); + env_array_overwrite_fmt(env, "MXMPI_MASTER", "%s", addr); + env_array_overwrite_fmt(env, "MXMPI_ID", "%u", job->gtaskid); + debug2("init for mpi rank %u\n", job->gtaskid); + + return SLURM_SUCCESS; +} + +mpi_plugin_client_state_t * +p_mpi_hook_client_prelaunch(mpi_plugin_client_info_t *job, char ***env) +{ + debug("Using mpi/mpich-gm"); + return (mpi_plugin_client_state_t *)gmpi_thr_create(job, env); +} + +int p_mpi_hook_client_single_task_per_node() +{ + return false; +} + +int p_mpi_hook_client_fini(mpi_plugin_client_state_t *state) +{ + return gmpi_thr_destroy((gmpi_state_t *)state); +} diff --git a/src/plugins/mpi/mpichmx/mpichmx.c b/src/plugins/mpi/mpichmx/mpichmx.c new file mode 100644 index 0000000000000000000000000000000000000000..b1d48fffd8f00b48d055073fd5a624b50c3fe7e9 --- /dev/null +++ b/src/plugins/mpi/mpichmx/mpichmx.c @@ -0,0 +1,409 @@ +/*****************************************************************************\ + ** mpichmx.c - srun support for MPICH-MX (based upon MPICH-GM code) + ***************************************************************************** + * Copyright (C) 2004 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Takao Hatazaki <takao.hatazaki@hp.com> + * UCRL-CODE-226842. + * + * This file is part of SLURM, a resource management program. + * For details, see <http://www.llnl.gov/linux/slurm/>. + * + * SLURM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * In addition, as a special exception, the copyright holders give permission + * to link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. You must obey the GNU + * General Public License in all respects for all of the code used other than + * OpenSSL. If you modify file(s) with this exception, you may extend this + * exception to your version of the file(s), but you are not obligated to do + * so. If you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files in + * the program, then also delete it here. + * + * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with SLURM; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef WITH_PTHREADS +# include <pthread.h> +#endif + +#include <signal.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <strings.h> + +#include "src/common/slurm_xlator.h" +#include "src/common/xmalloc.h" +#include "src/common/xstring.h" +#include "src/common/net.h" +#include "src/common/mpi.h" + +#include "src/plugins/mpi/mpichmx/mpichmx.h" + +typedef struct { + int defined; + unsigned int port_board_id; + unsigned int unique_high_id; + unsigned int unique_low_id; + unsigned int numanode; + unsigned int remote_pid; + unsigned int remote_port; +} gm_slave_t; + +#define GMPI_RECV_BUF_LEN 65536 + +struct gmpi_state { + pthread_t tid; + int fd; /* = -1 */ + mpi_plugin_client_info_t *job; +}; + +static int _gmpi_parse_init_recv_msg(mpi_plugin_client_info_t *job, char *rbuf, + gm_slave_t *slave_data, int *ii) +{ + unsigned int magic, id, port_board_id, unique_high_id, + unique_low_id, numanode, remote_pid, remote_port; + int got; + gm_slave_t *dp; + + got = sscanf(rbuf, "<<<%u:%u:%u:%u:%u:%u:%u::%u>>>", + &magic, &id, &port_board_id, &unique_high_id, + &unique_low_id, &numanode, &remote_pid, &remote_port); + *ii = id; + if (got != 8) { + error("GMPI master received invalid init message"); + return -1; + } + if (magic != job->jobid) { + error("GMPI master received invalid magic number"); + return -1; + } + if (id >= job->step_layout->task_cnt) + fatal("GMPI id is out of range"); +#if 0 + /* Unlike GM ports, MX endpoints can be 0, + * Pere Munt, BSC-CMS */ + if (port_board_id == 0) + fatal("MPI id=%d was unable to open a GM port", id); +#endif + + dp = &slave_data[id]; + if (dp->defined) { + error("Ignoring the message from MPI id=%d", id); + return -1; + } + dp->defined = 1; + dp->port_board_id = port_board_id; + dp->unique_high_id = unique_high_id; + dp->unique_low_id = unique_low_id; + dp->numanode = numanode; + dp->remote_pid = remote_pid; + dp->remote_port = remote_port; + + debug3("slave_data[%d]: <<<%u:%u:%u:%u:%u:%u:%u::%u>>>", + id, magic, id, port_board_id, + dp->unique_high_id, dp->unique_low_id, dp->numanode, + dp->remote_pid, dp->remote_port); + return 0; +} + + +static int _gmpi_establish_map(gmpi_state_t *st) +{ + mpi_plugin_client_info_t *job = st->job; + struct sockaddr_in addr; + in_addr_t *iaddrs; + socklen_t addrlen; + int accfd, newfd, rlen, nprocs, i, j, id; + size_t gmaplen, lmaplen, maplen; + char *p, *rbuf = NULL, *gmap = NULL, *lmap = NULL, *map = NULL; + char tmp[128]; + gm_slave_t *slave_data = NULL, *dp; + + /* + * Collect info from slaves. + * Will never finish unless slaves are GMPI processes. + */ + accfd = st->fd; + addrlen = sizeof(addr); + nprocs = job->step_layout->task_cnt; + iaddrs = (in_addr_t *)xmalloc(sizeof(*iaddrs)*nprocs); + slave_data = (gm_slave_t *)xmalloc(sizeof(*slave_data)*nprocs); + for (i=0; i<nprocs; i++) + slave_data[i].defined = 0; + i = 0; + rbuf = (char *)xmalloc(GMPI_RECV_BUF_LEN); + + while (i < nprocs) { + newfd = accept(accfd, (struct sockaddr *)&addr, &addrlen); + if (newfd == -1) { + error("accept(2) in GMPI master thread: %m"); + continue; + } + rlen = recv(newfd, rbuf, GMPI_RECV_BUF_LEN, 0); + if (rlen <= 0) { + error("GMPI master recv returned %d", rlen); + close(newfd); + continue; + } else { + rbuf[rlen] = 0; + } + if (_gmpi_parse_init_recv_msg(job, rbuf, slave_data, + &id) == 0) { + i++; + iaddrs[id] = ntohl(addr.sin_addr.s_addr); + } + close(newfd); + } + xfree(rbuf); + debug2("Received data from all of %d GMPI processes.", i); + + /* + * Compose the global map string. + */ + gmap = (char *)xmalloc(128*nprocs); + p = gmap; + strcpy(p, "[[["); + p += 3; + for (i=0; i<nprocs; i++) { + dp = &slave_data[i]; + sprintf(tmp, "<%u:%u:%u:%u>", dp->port_board_id, + dp->unique_high_id, dp->unique_low_id, dp->numanode); + strcpy(p, tmp); + p += strlen(tmp); + } + strcpy(p, "|||"); + p += 3; + gmaplen = (size_t)(p - gmap); + + /* + * Respond to slaves. + */ + lmap = (char *)xmalloc(128*nprocs); + for (i=0; i<nprocs; i++) { + /* + * Compose the string to send. + */ + dp = &slave_data[i]; + p = lmap; + for (j=0; j<nprocs; j++) { + if (iaddrs[i] == iaddrs[j] && + (dp->numanode == slave_data[j].numanode)) { + sprintf(tmp, "<%u>", j); + strcpy(p, tmp); + p += strlen(tmp); + } + } + lmaplen = (size_t)(p - lmap); + map = (char *)xmalloc(gmaplen+lmaplen+4); + strcpy(map, gmap); + strcpy(map+gmaplen, lmap); + strcpy(map+gmaplen+lmaplen, "]]]"); + maplen = gmaplen + lmaplen + 3; + + /* + * Send it. + */ + if ((newfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + fatal("GMPI master failed to respond"); + } + j = 1; + if (setsockopt(newfd, SOL_SOCKET, SO_REUSEADDR, + (void *)&j, sizeof(j))) + error("setsockopt in GMPI master: %m"); + bzero(&addr, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(iaddrs[i]); + addr.sin_port = htons(dp->remote_port); + if (connect(newfd, (struct sockaddr *)&addr, sizeof(addr))) + fatal("GMPI master failed to connect"); + send(newfd, map, maplen, 0); + close(newfd); + xfree(map); + } + xfree(slave_data); + xfree(lmap); + xfree(gmap); + xfree(iaddrs); + + debug2("GMPI master responded to all GMPI processes"); + return 0; +} + +static void _gmpi_wait_abort(gmpi_state_t *st) +{ + mpi_plugin_client_info_t *job = st->job; + struct sockaddr_in addr; + socklen_t addrlen; + int newfd, rlen; + unsigned int magic; + char *rbuf; + + rbuf = (char *)xmalloc(GMPI_RECV_BUF_LEN); + addrlen = sizeof(addr); + while (1) { + newfd = accept(st->fd, (struct sockaddr *)&addr, + &addrlen); + if (newfd == -1) { + fatal("GMPI master failed to accept (abort-wait)"); + } + rlen = recv(newfd, rbuf, GMPI_RECV_BUF_LEN, 0); + if (rlen <= 0) { + error("GMPI recv (abort-wait) returned %d", rlen); + close(newfd); + continue; + } else { + rbuf[rlen] = 0; + } + if (sscanf(rbuf, "<<<ABORT_%u_ABORT>>>", &magic) != 1) { + error("GMPI (abort-wait) received spurious message."); + close(newfd); + continue; + } + if (magic != job->jobid) { + error("GMPI (abort-wait) received bad magic number."); + close(newfd); + continue; + } + close(newfd); + debug("Received ABORT message from an MPI process."); + slurm_signal_job_step(job->jobid, job->stepid, SIGKILL); +#if 0 + xfree(rbuf); + close(jgmpi_fd); + gmpi_fd = -1; + return; +#endif + } +} + + +static void *_gmpi_thr(void *arg) +{ + gmpi_state_t *st; + mpi_plugin_client_info_t *job; + + st = (gmpi_state_t *) arg; + job = st->job; + + debug3("GMPI master thread pid=%lu", (unsigned long) getpid()); + _gmpi_establish_map(st); + + debug3("GMPI master thread is waiting for ABORT message."); + _gmpi_wait_abort(st); + + return (void *)0; +} + +static gmpi_state_t * +gmpi_state_create(const mpi_plugin_client_info_t *job) +{ + gmpi_state_t *state; + + state = (gmpi_state_t *)xmalloc(sizeof(gmpi_state_t)); + + state->tid = (pthread_t)-1; + state->fd = -1; + state->job = (mpi_plugin_client_info_t *) job; + + return state; +} + +static void +gmpi_state_destroy(gmpi_state_t *st) +{ + xfree(st); +} + +extern gmpi_state_t * +gmpi_thr_create(const mpi_plugin_client_info_t *job, char ***env) +{ + short port; + pthread_attr_t attr; + gmpi_state_t *st = NULL; + + st = gmpi_state_create(job); + + /* + * It is possible for one to modify the mpirun command in + * MPICH-GM distribution so that it calls srun, instead of + * rsh, for remote process invocations. In that case, we + * should not override envs nor open the master port. + */ + if (getenv("GMPI_PORT")) + return st; + + if (net_stream_listen (&st->fd, &port) < 0) { + error ("Unable to create GMPI listen port: %m"); + gmpi_state_destroy(st); + return NULL; + } + + /* + * Accept in a separate thread. + */ + slurm_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (pthread_create(&st->tid, &attr, &_gmpi_thr, (void *)st)) { + slurm_attr_destroy(&attr); + gmpi_state_destroy(st); + return NULL; + } + slurm_attr_destroy(&attr); + + env_array_overwrite_fmt(env, "GMPI_PORT", "%hu", port); + env_array_overwrite_fmt(env, "GMPI_MAGIC", "%u", job->jobid); + env_array_overwrite_fmt(env, "GMPI_NP", "%d", + job->step_layout->task_cnt); + env_array_overwrite_fmt(env, "GMPI_SHMEM", "1"); + /* FIXME for multi-board config. */ + env_array_overwrite_fmt(env, "GMPI_BOARD", "-1"); + + + /* For new MX version */ + env_array_overwrite_fmt(env, "MXMPI_PORT", "%hu", port); + env_array_overwrite_fmt(env, "MXMPI_MAGIC", "%u", job->jobid); + env_array_overwrite_fmt(env, "MXMPI_NP", "%d", + job->step_layout->task_cnt); + /* FIXME for multi-board config. */ + env_array_overwrite_fmt(env, "MXMPI_BOARD", "-1"); + + + /* for MACOSX to override default malloc */ + env_array_overwrite_fmt(env, "DYLD_FORCE_FLAT_NAMESPACE", "1"); + + + debug("Started GMPI master thread (%lu)", (unsigned long) st->tid); + + return st; +} + +extern int gmpi_thr_destroy(gmpi_state_t *st) +{ + if (st != NULL) { + if (st->tid != (pthread_t)-1) { + pthread_cancel(st->tid); + pthread_join(st->tid, NULL); + } + gmpi_state_destroy(st); + } + return SLURM_SUCCESS; +} diff --git a/src/plugins/mpi/mpichmx/mpichmx.h b/src/plugins/mpi/mpichmx/mpichmx.h new file mode 100644 index 0000000000000000000000000000000000000000..cdcade47ccee58ed6ce0c68b6ecde9a83ee1db0b --- /dev/null +++ b/src/plugins/mpi/mpichmx/mpichmx.h @@ -0,0 +1,50 @@ +/*****************************************************************************\ + ** mpichmx.h - Library routines for initiating jobs on with mpich/mx + ** based upon the code for mpich/gm + ***************************************************************************** + * Copyright (C) 2004 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Danny Auble <da@llnl.gov> + * UCRL-CODE-226842. + * + * This file is part of SLURM, a resource management program. + * For details, see <http://www.llnl.gov/linux/slurm/>. + * + * SLURM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * In addition, as a special exception, the copyright holders give permission + * to link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. You must obey the GNU + * General Public License in all respects for all of the code used other than + * OpenSSL. If you modify file(s) with this exception, you may extend this + * exception to your version of the file(s), but you are not obligated to do + * so. If you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files in + * the program, then also delete it here. + * + * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with SLURM; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +\*****************************************************************************/ +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "src/common/slurm_xlator.h" +#include "src/common/mpi.h" +#include "src/common/env.h" + +typedef struct gmpi_state gmpi_state_t; + +extern gmpi_state_t *gmpi_thr_create(const mpi_plugin_client_info_t *job, + char ***env); +extern int gmpi_thr_destroy(gmpi_state_t *state); diff --git a/src/salloc/opt.c b/src/salloc/opt.c index 59de3d16e2d62d2e1ed42a235fef92481d566ce9..ed20f603793cdc6e803b5c438edf321004993fde 100644 --- a/src/salloc/opt.c +++ b/src/salloc/opt.c @@ -1290,7 +1290,7 @@ static void _usage(void) " [[-c cpus-per-node] [-r n] [-p partition] [--hold] [-t minutes]\n" " [--immediate] [--no-kill]\n" " [--share] [-J jobname] [--jobid=id]\n" -" [--verbose]\n" +" [--verbose] [--gid=group] [--uid=user]\n" " [-W sec] [--minsockets=n] [--mincores=n] [--minthreads=n]\n" " [--contiguous] [--mincpus=n] [--mem=MB] [--tmp=MB] [-C list]\n" " [--account=name] [--dependency=jobid] [--comment=name]\n" @@ -1298,7 +1298,9 @@ static void _usage(void) " [--geometry=XxYxZ] [--conn-type=type] [--no-rotate] [ --reboot]\n" #endif " [--mail-type=type] [--mail-user=user][--nice[=value]]\n" -" [-w hosts...] [-x hosts...] executable [args...]\n"); +" [--bell] [--no-bell] [--kill-command[=signal]]\n" +" [--nodefile=file] [--nodelist=hosts] [--exclude=hosts]\n" +" executable [args...]\n"); } static void _help(void) @@ -1308,13 +1310,14 @@ static void _help(void) "\n" "Parallel run options:\n" " -N, --nodes=N number of nodes on which to run (N = min[-max])\n" -" -n, --procs=N number of processors required\n" +" -n, --tasks=N number of processors required\n" " -c, --cpus-per-task=ncpus number of cpus required per task\n" " -p, --partition=partition partition requested\n" " -H, --hold submit job in held state\n" " -t, --time=minutes time limit\n" " -I, --immediate exit if resources are not immediately available\n" " -k, --no-kill do not kill job on node failure\n" +" -K, --kill-command[=signal] signal to send terminating job\n" " -s, --share share nodes with other jobs\n" " -J, --job-name=jobname name of job\n" " --jobid=id specify jobid to use\n" @@ -1329,6 +1332,10 @@ static void _help(void) " --comment=name arbitrary comment\n" " --mail-type=type notify on state change: BEGIN, END, FAIL or ALL\n" " --mail-user=user who to send email notification for job state changes\n" +" --bell ring the terminal bell when the job is allocated\n" +" --no-bell do NOT ring the terminal bell\n" +" --gid=group_id group ID to run job as (user root only)\n" +" --uid=user_id user ID to run job as (user root only)\n" "\n" "Constraint options:\n" " --mincpus=n minimum number of cpus per node\n" @@ -1339,6 +1346,7 @@ static void _help(void) " --tmp=MB minimum amount of temporary disk\n" " --contiguous demand a contiguous range of nodes\n" " -C, --constraint=list specify a list of constraints\n" +" -F, --nodefile=filename request a specific list of hosts\n" " -w, --nodelist=hosts... request a specific list of hosts\n" " -x, --exclude=hosts... exclude a specific list of hosts\n" "\n" diff --git a/src/salloc/salloc.c b/src/salloc/salloc.c index e023f005f684451839c02e844d0dba04244d296a..cd9bc574437b4c1cbd529339ac17491d84e77342 100644 --- a/src/salloc/salloc.c +++ b/src/salloc/salloc.c @@ -301,8 +301,10 @@ static int fill_job_desc_from_opts(job_desc_msg_t *desc) static void ring_terminal_bell(void) { - fprintf(stdout, "\a"); - fflush(stdout); + if (isatty(STDOUT_FILENO)) { + fprintf(stdout, "\a"); + fflush(stdout); + } } /* returns the pid of the forked command, or <0 on error */ diff --git a/src/sbatch/opt.c b/src/sbatch/opt.c index 9efa3680cac0c749f550e02da30231e2d66f193f..c24bbf7e7b08534d24bfc54b763a5f33e45ec162 100644 --- a/src/sbatch/opt.c +++ b/src/sbatch/opt.c @@ -1611,8 +1611,8 @@ static void _usage(void) " [-c ncpus] [-r n] [-p partition] [--hold] [-t minutes]\n" " [-D path] [--immediate] [--no-kill]\n" " [--input file] [--output file] [--error file]\n" -" [--share] [-m dist] [-J jobname]\n" -" [--jobid=id] [--verbose]\n" +" [--workdir=directory] [--share] [-m dist] [-J jobname]\n" +" [--jobid=id] [--verbose] [--gid=group] [--uid=user]\n" " [-W sec] [--minsockets=n] [--mincores=n] [--minthreads=n]\n" " [--contiguous] [--mincpus=n] [--mem=MB] [--tmp=MB] [-C list]\n" " [--account=name] [--dependency=jobid] [--comment=name]\n" @@ -1623,7 +1623,8 @@ static void _usage(void) #endif " [--mail-type=type] [--mail-user=user][--nice[=value]]\n" " [--no-requeue] [--ntasks-per-node=n]\n" -" [-w hosts...] [-x hosts...] executable [args...]\n"); +" [--nodefile=file] [--nodelist=hosts] [--exclude=hosts]\n" +" executable [args...]\n"); } static void _help(void) @@ -1651,12 +1652,15 @@ static void _help(void) " -v, --verbose verbose mode (multiple -v's increase verbosity)\n" " -q, --quiet quiet mode (suppress informational messages)\n" " -d, --dependency=jobid defer job until specified jobid completes\n" +" -D, --workdir=directory set working directory for batch script\n" " --nice[=value] decrease secheduling priority by value\n" " -U, --account=name charge job to specified account\n" " --begin=time defer job until HH:MM DD/MM/YY\n" " --comment=name arbitrary comment\n" " --mail-type=type notify on state change: BEGIN, END, FAIL or ALL\n" " --mail-user=user who to send email notification for job state changes\n" +" --gid=group_id group ID to run job as (user root only)\n" +" --uid=user_id user ID to run job as (user root only)\n" " --get-user-env used by Moab. See srun man page.\n" " --no-requeue if set, do not permit the job to be requeued\n" "\n" @@ -1669,6 +1673,7 @@ static void _help(void) " --tmp=MB minimum amount of temporary disk\n" " --contiguous demand a contiguous range of nodes\n" " -C, --constraint=list specify a list of constraints\n" +" -F, --nodefile=filename request a specific list of hosts\n" " -w, --nodelist=hosts... request a specific list of hosts\n" " -x, --exclude=hosts... exclude a specific list of hosts\n" "\n" diff --git a/src/slurmctld/agent.c b/src/slurmctld/agent.c index 689dcd995be84a6b77afcd38691f0e3cfd618d1e..28aaa27bd190e18180fd935dcf8d54d83ec0c062 100644 --- a/src/slurmctld/agent.c +++ b/src/slurmctld/agent.c @@ -725,6 +725,26 @@ static inline int _comm_err(char *node_name) return rc; } +/* return a value for wihc WEXITSTATUS returns 1 */ +static int _wif_status(void) +{ + static int rc = 0; + int i; + + if (rc) + return rc; + + rc = 1; + for (i=0; i<64; i++) { + if (WEXITSTATUS(rc)) + return rc; + rc = rc << 1; + } + error("Could not identify WEXITSTATUS"); + rc = 1; + return rc; +} + /* * _thread_per_group_rpc - thread to issue an RPC for a group of nodes * sending message out to one and forwarding it to @@ -859,7 +879,7 @@ static void *_thread_per_group_rpc(void *args) thread_state = DSH_DONE; ret_data_info->err = thread_state; lock_slurmctld(job_write_lock); - job_complete(job_id, 0, false, 1); + job_complete(job_id, 0, false, _wif_status()); unlock_slurmctld(job_write_lock); continue; } diff --git a/src/slurmctld/node_scheduler.c b/src/slurmctld/node_scheduler.c index 49bf2fb753d4723c89ec4ede93386f4d61897d71..9900881a38d795616fbe14310cf54c82af63e441 100644 --- a/src/slurmctld/node_scheduler.c +++ b/src/slurmctld/node_scheduler.c @@ -63,7 +63,10 @@ #include "src/slurmctld/sched_plugin.h" #include "src/slurmctld/slurmctld.h" -#define MAX_RETRIES 10 +#define FEATURE_OP_OR 0 +#define FEATURE_OP_AND 1 +#define MAX_FEATURES 32 /* max exclusive features "[fs1|fs2]"=2 */ +#define MAX_RETRIES 10 struct node_set { /* set of nodes with same configuration */ uint32_t cpus_per_node; /* NOTE: This is the minimum count, @@ -74,7 +77,7 @@ struct node_set { /* set of nodes with same configuration */ uint32_t real_memory; uint32_t nodes; uint32_t weight; - int feature; + bitstr_t *feature_bits; bitstr_t *my_bitmap; }; @@ -104,7 +107,7 @@ static int _pick_best_nodes(struct node_set *node_set_ptr, struct part_record *part_ptr, uint32_t min_nodes, uint32_t max_nodes, uint32_t req_nodes); -static int _valid_features(char *requested, char *available); +static bitstr_t *_valid_features(char *requested, char *available); /* @@ -499,7 +502,8 @@ _pick_best_nodes(struct node_set *node_set_ptr, int node_set_size, job_ptr->details->job_max_memory = 0; } - debug3("Job %u in exclusive mode? %d cr_enabled %d CR type %d num_procs %d", + debug3("Job %u in exclusive mode? " + "%d cr_enabled %d CR type %d num_procs %d", job_ptr->job_id, job_ptr->details->shared ? 0 : 1, cr_enabled, @@ -617,21 +621,23 @@ _pick_best_nodes(struct node_set *node_set_ptr, int node_set_size, total_nodes = total_cpus = 0; /* reinitialize */ } - /* identify how many feature sets we have (e.g. "[fs1|fs2|fs3|fs4]" */ - max_feature = min_feature = node_set_ptr[0].feature; - for (i = 1; i < node_set_size; i++) { - if (node_set_ptr[i].feature > max_feature) - max_feature = node_set_ptr[i].feature; - if (node_set_ptr[i].feature < min_feature) - min_feature = node_set_ptr[i].feature; + /* identify the min and max feature values for exclusive OR */ + max_feature = -1; + min_feature = MAX_FEATURES; + for (i = 0; i < node_set_size; i++) { + j = bit_ffs(node_set_ptr[i].feature_bits); + if ((j >= 0) && (j < min_feature)) + min_feature = j; + j = bit_fls(node_set_ptr[i].feature_bits); + if ((j >= 0) && (j > max_feature)) + max_feature = j; } - + for (j = min_feature; j <= max_feature; j++) { for (i = 0; i < node_set_size; i++) { bool pick_light_load = false; - if (node_set_ptr[i].feature != j) + if (!bit_test(node_set_ptr[i].feature_bits, j)) continue; - if (!runable_ever) { int cr_disabled = 0; total_mem = 0; @@ -659,24 +665,9 @@ _pick_best_nodes(struct node_set *node_set_ptr, int node_set_size, /* shared needs to be checked before cr_enabled * to make sure that CR_MEMORY works correctly. */ if (shared) { -#ifdef HAVE_BG - /* If any nodes which can be used have jobs in - * COMPLETING state then do not schedule the - * job, this give time to insure Epilog - * completes before possibly scheduling another - * job to the same bgblock. We also want to - * route the job to the smallest usable block*/ - int ni; - bit_and(node_set_ptr[i].my_bitmap, - share_node_bitmap); - for (ni = 0; ni < node_record_count; ni++) { - if (node_record_table_ptr[ni]. - node_state & NODE_STATE_COMPLETING) - continue; - } -#else bit_and(node_set_ptr[i].my_bitmap, share_node_bitmap); +#ifndef HAVE_BG pick_light_load = true; #endif } else if (cr_enabled) { @@ -757,13 +748,14 @@ _pick_best_nodes(struct node_set *node_set_ptr, int node_set_size, FREE_NULL_BITMAP(avail_bitmap); avail_bitmap = backup_bitmap; } - } + } /* for (i = 0; i < node_set_size; i++) */ /* try to get req_nodes now for this feature */ - if ((req_nodes > min_nodes) && - (avail_nodes >= min_nodes) && - (avail_nodes < req_nodes) && - ((job_ptr->details->req_node_bitmap == NULL) || + if (avail_bitmap + && (req_nodes > min_nodes) + && (avail_nodes >= min_nodes) + && (avail_nodes < req_nodes) + && ((job_ptr->details->req_node_bitmap == NULL) || bit_super_set(job_ptr->details->req_node_bitmap, avail_bitmap))) { pick_code = select_g_job_test(job_ptr, avail_bitmap, @@ -785,12 +777,13 @@ _pick_best_nodes(struct node_set *node_set_ptr, int node_set_size, /* determine if job could possibly run (if all configured * nodes available) */ - if ((!runable_ever || !runable_avail) - && (total_nodes >= min_nodes) - && ((slurmctld_conf.fast_schedule == 0) || - (total_cpus >= job_ptr->num_procs)) - && ((job_ptr->details->req_node_bitmap == NULL) || - (bit_super_set(job_ptr->details->req_node_bitmap, + if (total_bitmap + && (!runable_ever || !runable_avail) + && (total_nodes >= min_nodes) + && ((slurmctld_conf.fast_schedule == 0) || + (total_cpus >= job_ptr->num_procs)) + && ((job_ptr->details->req_node_bitmap == NULL) || + (bit_super_set(job_ptr->details->req_node_bitmap, total_bitmap)))) { if (!runable_avail) { FREE_NULL_BITMAP(avail_bitmap); @@ -1169,8 +1162,10 @@ extern int select_nodes(struct job_record *job_ptr, bool test_only, else FREE_NULL_BITMAP(select_bitmap); if (node_set_ptr) { - for (i = 0; i < node_set_size; i++) + for (i = 0; i < node_set_size; i++) { FREE_NULL_BITMAP(node_set_ptr[i].my_bitmap); + FREE_NULL_BITMAP(node_set_ptr[i].feature_bits); + } xfree(node_set_ptr); } return error_code; @@ -1192,10 +1187,11 @@ static int _build_node_list(struct job_record *job_ptr, struct config_record *config_ptr; struct part_record *part_ptr = job_ptr->part_ptr; ListIterator config_iterator; - int tmp_feature, check_node_config, config_filter = 0; + int check_node_config, config_filter = 0; struct job_details *detail_ptr = job_ptr->details; bitstr_t *exc_node_mask = NULL; multi_core_data_t *mc_ptr = detail_ptr->mc_ptr; + bitstr_t *tmp_feature; node_set_inx = 0; node_set_ptr = (struct node_set *) @@ -1214,10 +1210,6 @@ static int _build_node_list(struct job_record *job_ptr, while ((config_ptr = (struct config_record *) list_next(config_iterator))) { - tmp_feature = _valid_features(job_ptr->details->features, - config_ptr->feature); - if (tmp_feature == 0) - continue; config_filter = 0; if ((detail_ptr->job_min_procs > config_ptr->cpus ) @@ -1246,32 +1238,42 @@ static int _build_node_list(struct job_record *job_ptr, check_node_config = 0; node_set_ptr[node_set_inx].my_bitmap = - bit_copy(config_ptr->node_bitmap); + bit_copy(config_ptr->node_bitmap); if (node_set_ptr[node_set_inx].my_bitmap == NULL) fatal("bit_copy malloc failure"); bit_and(node_set_ptr[node_set_inx].my_bitmap, part_ptr->node_bitmap); - if (exc_node_mask) + if (exc_node_mask) { bit_and(node_set_ptr[node_set_inx].my_bitmap, exc_node_mask); + } node_set_ptr[node_set_inx].nodes = bit_set_count(node_set_ptr[node_set_inx].my_bitmap); - if (check_node_config && - (node_set_ptr[node_set_inx].nodes != 0)) + if (check_node_config + && (node_set_ptr[node_set_inx].nodes != 0)) { _filter_nodes_in_set(&node_set_ptr[node_set_inx], detail_ptr); - + } if (node_set_ptr[node_set_inx].nodes == 0) { FREE_NULL_BITMAP(node_set_ptr[node_set_inx].my_bitmap); continue; } + + tmp_feature = _valid_features(job_ptr->details->features, + config_ptr->feature); + if (tmp_feature == NULL) { + FREE_NULL_BITMAP(node_set_ptr[node_set_inx].my_bitmap); + continue; + } + /* NOTE: Must bit_free(tmp_feature) to avoid memory leak */ + node_set_ptr[node_set_inx].cpus_per_node = config_ptr->cpus; node_set_ptr[node_set_inx].real_memory = config_ptr->real_memory; node_set_ptr[node_set_inx].weight = config_ptr->weight; - node_set_ptr[node_set_inx].feature = tmp_feature; + node_set_ptr[node_set_inx].feature_bits = tmp_feature; debug2("found %d usable nodes from config containing %s", node_set_ptr[node_set_inx].nodes, config_ptr->nodes); @@ -1283,6 +1285,7 @@ static int _build_node_list(struct job_record *job_ptr, list_iterator_destroy(config_iterator); /* eliminate last (incomplete) node_set record */ FREE_NULL_BITMAP(node_set_ptr[node_set_inx].my_bitmap); + FREE_NULL_BITMAP(node_set_ptr[node_set_inx].feature_bits); FREE_NULL_BITMAP(exc_node_mask); if (node_set_inx == 0) { @@ -1516,30 +1519,35 @@ extern void build_node_details(struct job_record *job_ptr) * slurm administrator and user guides for details. returns 1 if * requirements are satisfied without mutually exclusive feature list. */ -static int _valid_features(char *requested, char *available) +static bitstr_t *_valid_features(char *requested, char *available) { char *tmp_requested, *str_ptr1; - int bracket, found, i, option, position, result; + int bracket, found, i, position, result; int last_op; /* last operation 0 for or, 1 for and */ int save_op = 0, save_result = 0; /* for bracket support */ + bitstr_t *result_bits = (bitstr_t *) NULL; - if (requested == NULL) - return 1; /* no constraints */ - if (available == NULL) - return 0; /* no features */ + if (requested == NULL) { /* no constraints */ + result_bits = bit_alloc(MAX_FEATURES); + bit_set(result_bits, 0); + return result_bits; + } + if (available == NULL) /* no features */ + return result_bits; tmp_requested = xstrdup(requested); - bracket = option = position = 0; + bracket = position = 0; str_ptr1 = tmp_requested; /* start of feature name */ - result = last_op = 1; /* assume good for now */ - for (i = 0;; i++) { + result = 1; /* assume good for now */ + last_op = FEATURE_OP_AND; + for (i=0; ; i++) { if (tmp_requested[i] == (char) NULL) { if (strlen(str_ptr1) == 0) break; found = _match_feature(str_ptr1, available); - if (last_op == 1) /* and */ + if (last_op == FEATURE_OP_AND) result &= found; - else /* or */ + else /* FEATURE_OP_OR */ result |= found; break; } @@ -1553,53 +1561,67 @@ static int _valid_features(char *requested, char *available) } tmp_requested[i] = (char) NULL; found = _match_feature(str_ptr1, available); - if (last_op == 1) /* and */ + if (last_op == FEATURE_OP_AND) result &= found; - else /* or */ + else /* FEATURE_OP_OR */ result |= found; str_ptr1 = &tmp_requested[i + 1]; - last_op = 1; /* and */ + last_op = FEATURE_OP_AND; } else if (tmp_requested[i] == '|') { tmp_requested[i] = (char) NULL; found = _match_feature(str_ptr1, available); if (bracket != 0) { - if (found) - option = position; + if (found) { + if (!result_bits) + result_bits = bit_alloc(MAX_FEATURES); + if (position < MAX_FEATURES) + bit_set(result_bits, (position-1)); + else + error("_valid_features: overflow"); + } position++; } - if (last_op == 1) /* and */ + if (last_op == FEATURE_OP_AND) result &= found; - else /* or */ + else /* FEATURE_OP_OR */ result |= found; str_ptr1 = &tmp_requested[i + 1]; - last_op = 0; /* or */ + last_op = FEATURE_OP_OR; } else if (tmp_requested[i] == '[') { bracket++; position = 1; save_op = last_op; save_result = result; - last_op = result = 1; + last_op = FEATURE_OP_AND; + result = 1; str_ptr1 = &tmp_requested[i + 1]; } else if (tmp_requested[i] == ']') { tmp_requested[i] = (char) NULL; found = _match_feature(str_ptr1, available); - if (found) - option = position; + if (found) { + if (!result_bits) + result_bits = bit_alloc(MAX_FEATURES); + if (position < MAX_FEATURES) + bit_set(result_bits, (position-1)); + else + error("_valid_features: overflow"); + } + position++; result |= found; - if (save_op == 1) /* and */ + if (save_op == FEATURE_OP_AND) result &= save_result; - else /* or */ + else /* FEATURE_OP_OR */ result |= save_result; if ((tmp_requested[i + 1] == '&') && (bracket == 1)) { - last_op = 1; + last_op = FEATURE_OP_AND; str_ptr1 = &tmp_requested[i + 2]; } else if ((tmp_requested[i + 1] == '|') && (bracket == 1)) { - last_op = 0; + last_op = FEATURE_OP_OR; str_ptr1 = &tmp_requested[i + 2]; } else if ((tmp_requested[i + 1] == (char) NULL) && (bracket == 1)) { @@ -1613,11 +1635,18 @@ static int _valid_features(char *requested, char *available) bracket = 0; } } - - if (position) - result *= option; xfree(tmp_requested); - return result; + + if (result) { + if (!result_bits) { + result_bits = bit_alloc(MAX_FEATURES); + bit_set(result_bits, 0); + } + } else { + FREE_NULL_BITMAP(result_bits); + } + + return result_bits; } /*