root/ompi/mca/io/romio321/romio/adio/common/cb_config_list.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ADIOI_cb_bcast_rank_map
  2. ADIOI_cb_gather_name_array
  3. ADIOI_cb_config_list_parse
  4. ADIOI_cb_copy_name_array
  5. ADIOI_cb_delete_name_array
  6. match_procs
  7. match_this_proc
  8. find_name
  9. get_max_procs
  10. cb_config_list_lex

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
   2 /* 
   3  *
   4  *   Copyright (C) 2001 University of Chicago. 
   5  *   See COPYRIGHT notice in top-level directory.
   6  */
   7 
   8 /* cb_config_list.c
   9  *
  10  * The important, externally used functions from this file are:
  11  * ADIOI_cb_bcast_rank_map()
  12  * ADIOI_cb_gather_name_array()
  13  * ADIOI_cb_config_list_parse()
  14  * ADIOI_cb_copy_name_array()
  15  * ADIOI_cb_delete_name_array()
  16  *
  17  * Prototypes for these are in adio/include/adio_cb_config_list.h
  18  */
  19 
  20 #include "adio.h"
  21 #include "mpi.h"
  22 #include "adio_cb_config_list.h"
  23 #include <stdio.h>
  24 #include <string.h>
  25 #include <stdlib.h>
  26 
  27 /* token types */
  28 #define AGG_WILDCARD 1
  29 #define AGG_STRING   2
  30 #define AGG_COMMA    3
  31 #define AGG_COLON    4
  32 #define AGG_ERROR   -1
  33 #define AGG_EOS      0
  34 
  35 #undef CB_CONFIG_LIST_DEBUG
  36 
  37 /* a couple of globals keep things simple */
  38 int ADIOI_cb_config_list_keyval = MPI_KEYVAL_INVALID;
  39 static char *yylval;
  40 static char *token_ptr;
  41 
  42 /* internal stuff */
  43 static int get_max_procs(int cb_nodes);
  44 static int match_procs(char *name, int max_per_proc, char *procnames[], 
  45                        char used_procnames[],
  46                        int nr_procnames, int ranks[], int nr_ranks, 
  47                        int *nr_ranks_allocated);
  48 static int match_this_proc(char *name, int cur_proc, int max_matches,
  49                            char *procnames[], char used_procnames[],
  50                            int nr_procnames, int ranks[], 
  51                            int nr_ranks, int nr_ranks_allocated);
  52 static int find_name(char *name, char *procnames[], char used_procnames[], 
  53                      int nr_procnames, int start_ind);
  54 static int cb_config_list_lex(void);
  55 
  56 
  57 /* ADIOI_cb_bcast_rank_map() - broadcast the rank array
  58  *
  59  * Parameters:
  60  * fd - ADIO_File for which update is occurring.  cb_nodes and ranklist
  61  * parameters must be up-to-date on rank 0 of the fd->comm.
  62  *
  63  * should probably be a void fn.
  64  */
  65 int ADIOI_cb_bcast_rank_map(ADIO_File fd)
  66 {
  67     int my_rank;
  68     char *value;
  69         int error_code = MPI_SUCCESS;
  70         static char myname[] = "ADIOI_cb_bcast_rank_map";
  71     char *p;
  72     int i;
  73 
  74     MPI_Bcast(&(fd->hints->cb_nodes), 1, MPI_INT, 0, fd->comm);
  75     if (fd->hints->cb_nodes > 0) {
  76         MPI_Comm_rank(fd->comm, &my_rank);
  77         if (my_rank != 0) {
  78             fd->hints->ranklist = ADIOI_Malloc(fd->hints->cb_nodes*sizeof(int));
  79             if (fd->hints->ranklist == NULL) {
  80                 error_code = MPIO_Err_create_code(error_code,
  81                                                   MPIR_ERR_RECOVERABLE,
  82                                                   myname,
  83                                                   __LINE__,
  84                                                   MPI_ERR_OTHER,
  85                                                   "**nomem2",0);
  86                 return error_code;
  87             }
  88         }
  89         MPI_Bcast(fd->hints->ranklist, fd->hints->cb_nodes, MPI_INT, 0, 
  90                   fd->comm);
  91     }
  92     /* TEMPORARY -- REMOVE WHEN NO LONGER UPDATING INFO FOR
  93      * FS-INDEP. */
  94     value = (char *) ADIOI_Malloc((MPI_MAX_INFO_VAL+1)*sizeof(char));
  95     ADIOI_Snprintf(value, MPI_MAX_INFO_VAL+1, "%d", fd->hints->cb_nodes);
  96     ADIOI_Info_set(fd->info, "cb_nodes", value);
  97     p = value;
  98     /* the (by MPI rank) list of aggregators can be larger than
  99      * MPI_MAX_INFO_VAL, so we will simply truncate when we reach capacity. I
 100      * wasn't clever enough to figure out how to rewind and put '...' at the
 101      * end in the truncate case */
 102     for (i=0; i< fd->hints->cb_nodes; i++) {
 103         int incr, remain = (MPI_MAX_INFO_VAL) - (p-value);
 104         incr = ADIOI_Snprintf(p, remain, "%d ", fd->hints->ranklist[i]);
 105     if (incr >= remain) break;
 106         p += incr;
 107     }
 108     ADIOI_Info_set(fd->info, "romio_aggregator_list", value);
 109     ADIOI_Free(value);
 110 
 111     return 0;
 112 }
 113 
 114 /* ADIOI_cb_gather_name_array() - gather a list of processor names from all processes
 115  *                          in a communicator and store them on rank 0.
 116  *
 117  * This is a collective call on the communicator(s) passed in.
 118  *
 119  * Obtains a rank-ordered list of processor names from the processes in
 120  * "dupcomm".
 121  *
 122  * Returns 0 on success, -1 on failure.
 123  *
 124  * NOTE: Needs some work to cleanly handle out of memory cases!  
 125  */
 126 int ADIOI_cb_gather_name_array(MPI_Comm comm,
 127                                MPI_Comm dupcomm,
 128                                ADIO_cb_name_array *arrayp)
 129 {
 130     char my_procname[MPI_MAX_PROCESSOR_NAME], **procname = 0;
 131     int *procname_len = NULL, my_procname_len, *disp = NULL, i;
 132     int commsize, commrank, found;
 133     ADIO_cb_name_array array = NULL;
 134     int alloc_size;
 135 
 136     if (ADIOI_cb_config_list_keyval == MPI_KEYVAL_INVALID) {
 137         /* cleaned up by ADIOI_End_call */
 138         MPI_Comm_create_keyval((MPI_Comm_copy_attr_function *) ADIOI_cb_copy_name_array, 
 139                           (MPI_Comm_delete_attr_function *) ADIOI_cb_delete_name_array,
 140                           &ADIOI_cb_config_list_keyval, NULL);
 141     }
 142     else {
 143         MPI_Comm_get_attr(comm, ADIOI_cb_config_list_keyval, (void *) &array, &found);
 144         if (found) {
 145             ADIOI_Assert(array != NULL);
 146             *arrayp = array;
 147             return 0;
 148         }
 149     }
 150 
 151     MPI_Comm_size(dupcomm, &commsize);
 152     MPI_Comm_rank(dupcomm, &commrank);
 153 
 154     MPI_Get_processor_name(my_procname, &my_procname_len);
 155 
 156     /* allocate space for everything */
 157     array = (ADIO_cb_name_array) ADIOI_Malloc(sizeof(*array));
 158     if (array == NULL) {
 159         return -1;
 160     }
 161     array->refct = 2; /* we're going to associate this with two comms */
 162 
 163     if (commrank == 0) {
 164         /* process 0 keeps the real list */
 165         array->namect = commsize;
 166 
 167         array->names = (char **) ADIOI_Malloc(sizeof(char *) * commsize);
 168         if (array->names == NULL) {
 169             return -1;
 170         }
 171         procname = array->names; /* simpler to read */
 172 
 173         procname_len = (int *) ADIOI_Malloc(commsize * sizeof(int));
 174         if (procname_len == NULL) { 
 175             return -1;
 176         }
 177     }
 178     else {
 179         /* everyone else just keeps an empty list as a placeholder */
 180         array->namect = 0;
 181         array->names = NULL;
 182     }
 183     /* gather lengths first */
 184     MPI_Gather(&my_procname_len, 1, MPI_INT, 
 185                procname_len, 1, MPI_INT, 0, dupcomm);
 186 
 187     if (commrank == 0) {
 188 #ifdef CB_CONFIG_LIST_DEBUG
 189         for (i=0; i < commsize; i++) {
 190             FPRINTF(stderr, "len[%d] = %d\n", i, procname_len[i]);
 191         }
 192 #endif
 193 
 194         alloc_size = 0;
 195         for (i=0; i < commsize; i++) {
 196             /* add one to the lengths because we need to count the
 197              * terminator, and we are going to use this list of lengths
 198              * again in the gatherv.  
 199              */
 200             alloc_size += ++procname_len[i];
 201         }
 202         
 203         procname[0] = ADIOI_Malloc(alloc_size);
 204         if (procname[0] == NULL) {
 205             ADIOI_Free(array);
 206             return -1;
 207         }
 208 
 209         for (i=1; i < commsize; i++) {
 210             procname[i] = procname[i-1] + procname_len[i-1];
 211         }
 212         
 213         /* create our list of displacements for the gatherv.  we're going
 214          * to do everything relative to the start of the region allocated
 215          * for procname[0]
 216          */
 217         disp = ADIOI_Malloc(commsize * sizeof(int));
 218         disp[0] = 0;
 219         for (i=1; i < commsize; i++) {
 220             disp[i] = (int) (procname[i] - procname[0]);
 221         }
 222 
 223     }
 224 
 225     /* now gather strings */
 226     if (commrank == 0) {
 227         MPI_Gatherv(my_procname, my_procname_len + 1, MPI_CHAR, 
 228                     procname[0], procname_len, disp, MPI_CHAR,
 229                     0, dupcomm);
 230     }
 231     else {
 232         /* if we didn't do this, we would need to allocate procname[]
 233          * on all processes...which seems a little silly.
 234          */
 235         MPI_Gatherv(my_procname, my_procname_len + 1, MPI_CHAR, 
 236                     NULL, NULL, NULL, MPI_CHAR, 0, dupcomm);
 237     }
 238 
 239     if (commrank == 0) {
 240         /* no longer need the displacements or lengths */
 241         ADIOI_Free(disp);
 242         ADIOI_Free(procname_len);
 243 
 244 #ifdef CB_CONFIG_LIST_DEBUG
 245         for (i=0; i < commsize; i++) {
 246             FPRINTF(stderr, "name[%d] = %s\n", i, procname[i]);
 247         }
 248 #endif
 249     }
 250 
 251     /* store the attribute; we want to store SOMETHING on all processes
 252      * so that they can all tell if we have gone through this procedure 
 253      * or not for the given communicator.
 254      *
 255      * specifically we put it on both the original comm, so we can find
 256      * it next time an open is performed on this same comm, and on the
 257      * dupcomm, so we can use it in I/O operations.
 258      */
 259     MPI_Comm_set_attr (comm, ADIOI_cb_config_list_keyval, array);
 260     MPI_Comm_set_attr (dupcomm, ADIOI_cb_config_list_keyval, array);
 261     *arrayp = array;
 262     return 0;
 263 }
 264 
 265 
 266 /* ADIOI_cb_config_list_parse() - parse the cb_config_list and build the 
 267  * ranklist
 268  *
 269  * Parameters:
 270  * (pretty self explanatory)
 271  *
 272  * Returns number of ranks allocated in parsing, -1 on error.
 273  */
 274 int ADIOI_cb_config_list_parse(char *config_list, 
 275                          ADIO_cb_name_array array,
 276                          int ranklist[], 
 277                          int cb_nodes)
 278 {
 279     int token, max_procs, cur_rank = 0, nr_procnames;
 280     char *cur_procname, *cur_procname_p, **procnames;
 281     char *used_procnames;
 282 
 283     nr_procnames = array->namect;
 284     procnames = array->names;
 285 
 286     /* nothing big goes on the stack */
 287     /* we use info val here and for yylval because we know the string
 288      * cannot be any bigger than this.
 289      */
 290     cur_procname = ADIOI_Malloc((MPI_MAX_INFO_VAL+1) * sizeof(char));
 291     if (cur_procname == NULL) {
 292         return -1;
 293     }
 294 
 295     yylval = ADIOI_Malloc((MPI_MAX_INFO_VAL+1) * sizeof(char));
 296     if (yylval == NULL) {
 297         ADIOI_Free(cur_procname);
 298         return -1;
 299     }
 300 
 301     token_ptr = config_list;
 302 
 303     /* right away let's make sure cb_nodes isn't too big */
 304     if (cb_nodes > nr_procnames) cb_nodes = nr_procnames;
 305 
 306     /* used_procnames is used as a mask so that we don't have to destroy
 307      * our procnames array
 308      */
 309     used_procnames = ADIOI_Malloc(array->namect * sizeof(char));
 310     if (used_procnames == NULL) {
 311         ADIOI_Free(cur_procname);
 312         ADIOI_Free(yylval);
 313         yylval = NULL;
 314         return -1;
 315     }
 316     memset(used_procnames, 0, array->namect);
 317 
 318     /* optimization for "*:*"; arguably this could be done before we
 319      * build the list of processor names...but that would make things
 320      * messy.
 321      */
 322     if (strcmp(config_list, "*:*") == 0) {
 323         for (cur_rank = 0; cur_rank < cb_nodes; cur_rank++) {
 324             ranklist[cur_rank] = cur_rank;
 325         }
 326         ADIOI_Free(cur_procname);
 327         ADIOI_Free(yylval);
 328         yylval = NULL;
 329         ADIOI_Free(used_procnames);
 330         return cb_nodes;
 331     }
 332 
 333     while (cur_rank < cb_nodes) {
 334         token = cb_config_list_lex();
 335 
 336         if (token == AGG_EOS) {
 337             ADIOI_Free(cur_procname);
 338             ADIOI_Free(yylval);
 339             yylval = NULL;
 340             ADIOI_Free(used_procnames);
 341             return cur_rank;
 342         }
 343 
 344         if (token != AGG_WILDCARD && token != AGG_STRING) {
 345             /* maybe ignore and try to keep going? */
 346             FPRINTF(stderr, "error parsing config list\n");
 347             ADIOI_Free(cur_procname);
 348             ADIOI_Free(yylval);
 349             yylval = NULL;
 350             ADIOI_Free(used_procnames);
 351             return cur_rank;
 352         }
 353         
 354         if (token == AGG_WILDCARD) {
 355             cur_procname_p = NULL;
 356         }
 357         else {
 358             /* AGG_STRING is the only remaining case */
 359             /* save procname (for now) */
 360             ADIOI_Strncpy(cur_procname, yylval, MPI_MAX_INFO_VAL+1);
 361             cur_procname_p = cur_procname;
 362         }
 363 
 364         /* after we have saved the current procname, we can grab max_procs */
 365         max_procs = get_max_procs(cb_nodes);
 366 
 367 #ifdef CB_CONFIG_LIST_DEBUG
 368         if (token == AGG_WILDCARD) {
 369             FPRINTF(stderr, "looking for *:%d\n", max_procs);
 370         }
 371         else {
 372             FPRINTF(stderr, "looking for %s:%d\n", cur_procname, max_procs);
 373         }
 374 #endif
 375 
 376         /* do the matching for this piece of the cb_config_list */
 377         match_procs(cur_procname_p, max_procs, procnames, used_procnames,
 378                     nr_procnames, ranklist, cb_nodes, &cur_rank);
 379     }
 380     ADIOI_Free(cur_procname);
 381     ADIOI_Free(yylval);
 382     yylval = NULL;
 383     ADIOI_Free(used_procnames);
 384     return cur_rank;
 385 }
 386 
 387 /* ADIOI_cb_copy_name_array() - attribute copy routine
 388  */
 389 int ADIOI_cb_copy_name_array(MPI_Comm comm, 
 390                        int keyval, 
 391                        void *extra, 
 392                        void *attr_in,
 393                        void **attr_out, 
 394                        int *flag)
 395 {
 396     ADIO_cb_name_array array;
 397 
 398     ADIOI_UNREFERENCED_ARG(comm);
 399     ADIOI_UNREFERENCED_ARG(keyval); 
 400     ADIOI_UNREFERENCED_ARG(extra);
 401 
 402     array = (ADIO_cb_name_array) attr_in;
 403     if (array != NULL) array->refct++;
 404 
 405     *attr_out = attr_in;
 406     *flag = 1; /* make a copy in the new communicator */
 407     
 408     return MPI_SUCCESS;
 409 }
 410 
 411 /* ADIOI_cb_delete_name_array() - attribute destructor
 412  */
 413 int ADIOI_cb_delete_name_array(MPI_Comm comm, 
 414                          int keyval, 
 415                          void *attr_val, 
 416                          void *extra)
 417 {
 418     ADIO_cb_name_array array;
 419 
 420     ADIOI_UNREFERENCED_ARG(comm);
 421     ADIOI_UNREFERENCED_ARG(extra);
 422 
 423     array = (ADIO_cb_name_array) attr_val;
 424     ADIOI_Assert(array != NULL);
 425     array->refct--;
 426 
 427     if (array->refct <= 0) {
 428         /* time to free the structures (names, array of ptrs to names, struct)
 429          */
 430         if (array->namect) {
 431             /* Note that array->names[i], where i > 0, 
 432              * are just pointers into the allocated region array->names[0]
 433              */
 434             ADIOI_Free(array->names[0]);
 435         }
 436         if (array->names != NULL) ADIOI_Free(array->names);
 437         ADIOI_Free(array);
 438     }
 439     return MPI_SUCCESS;
 440 }
 441 
 442 /* match_procs() - given a name (or NULL for wildcard) and a max. number
 443  *                 of aggregator processes (per processor name), this 
 444  *                 matches in the procnames[] array and puts appropriate
 445  *                 ranks in the ranks array.
 446  *
 447  * Parameters:
 448  * name - processor name (or NULL for wildcard)
 449  * max_per_proc - maximum # of processes to use for aggregation from a
 450  *                single processor
 451  * procnames - array of processor names
 452  * nr_procnames - length of procnames array
 453  * ranks - array of process ranks
 454  * nr_ranks - length of process ranks array (also max. # of aggregators)
 455  * nr_ranks_allocated - # of array entries which have been filled in,
 456  *                      which is also the index to the first empty entry
 457  *
 458  * Returns number of matches.
 459  */
 460 static int match_procs(char *name, 
 461                        int max_per_proc, 
 462                        char *procnames[],
 463                        char used_procnames[],
 464                        int nr_procnames,
 465                        int ranks[],
 466                        int nr_ranks,
 467                        int *nr_ranks_allocated)
 468 {
 469     int wildcard_proc, cur_proc, old_nr_allocated, ret;
 470     
 471     /* save this so we can report on progress */
 472     old_nr_allocated = *nr_ranks_allocated;
 473 
 474     if (name == NULL) {
 475         /* wildcard case */
 476 
 477         /* optimize for *:0 case */
 478         if (max_per_proc == 0) {
 479             /* loop through procnames and mark them all as used */
 480             for (cur_proc = 0; cur_proc < nr_procnames; cur_proc++) {
 481                 used_procnames[cur_proc] = 1;
 482             }
 483             return 0;
 484         }
 485 
 486         /* the plan here is to start at the beginning of the procnames
 487          * array looking for processor names to apply the wildcard to.
 488          *
 489          * we set wildcard_proc to 0 here but do the search inside the
 490          * while loop so that we aren't starting our search from the
 491          * beginning of the procnames array each time.
 492          */
 493         wildcard_proc = 0;
 494 
 495         while (nr_ranks - *nr_ranks_allocated > 0) {
 496             /* find a name */
 497             while ((wildcard_proc < nr_procnames) && 
 498                    (used_procnames[wildcard_proc] != 0)) 
 499             {
 500                 wildcard_proc++;
 501             }
 502 
 503             if (wildcard_proc == nr_procnames) {
 504                 /* we have used up the entire procnames list */
 505                 return *nr_ranks_allocated - old_nr_allocated;
 506             }
 507 
 508 #ifdef CB_CONFIG_LIST_DEBUG
 509             FPRINTF(stderr, "performing wildcard match (*:%d) starting with %s (%d)\n", 
 510                    max_per_proc, procnames[wildcard_proc], wildcard_proc);
 511 #endif
 512 
 513             cur_proc = wildcard_proc;
 514 
 515 #ifdef CB_CONFIG_LIST_DEBUG
 516             FPRINTF(stderr, "  assigning name %s (%d) to rank %d in mapping\n",
 517                    procnames[cur_proc], cur_proc, *nr_ranks_allocated);
 518 #endif
 519 
 520             /* alloc max_per_proc from this host; cur_proc points to
 521              * the first one.  We want to save this name for use in
 522              * our while loop.
 523              */
 524             ranks[*nr_ranks_allocated] = cur_proc;
 525             *nr_ranks_allocated = *nr_ranks_allocated + 1;          
 526             cur_proc++;
 527 
 528             /* so, to accomplish this we use the match_this_proc() to
 529              * alloc max_per_proc-1.  we increment cur_proc so that the
 530              * procnames[] entry doesn't get trashed.  then AFTER the call
 531              * we clean up the first instance of the name.
 532              */
 533             ret = match_this_proc(procnames[wildcard_proc],  cur_proc,
 534                                   max_per_proc-1, procnames, used_procnames,
 535                                   nr_procnames,
 536                                   ranks, nr_ranks, *nr_ranks_allocated);
 537             if (ret > 0) *nr_ranks_allocated = *nr_ranks_allocated + ret;
 538     
 539             /* clean up and point wildcard_proc to the next entry, since
 540              * we know that this one is NULL now.
 541              */
 542             used_procnames[wildcard_proc] = 1;
 543             wildcard_proc++;
 544         }
 545     }
 546     else {
 547         /* specific host was specified; this one is easy */
 548 #ifdef CB_CONFIG_LIST_DEBUG
 549         FPRINTF(stderr, "performing name match (%s:%d)\n", name, max_per_proc);
 550 #endif
 551 
 552         ret = match_this_proc(name, 0, max_per_proc, procnames, used_procnames,
 553                               nr_procnames, ranks, nr_ranks,
 554                               *nr_ranks_allocated);
 555         if (ret > 0) *nr_ranks_allocated = *nr_ranks_allocated + ret;
 556     }
 557     return *nr_ranks_allocated - old_nr_allocated;
 558 }
 559 
 560 /* match_this_proc() - find each instance of processor name "name" in 
 561  *                     the "procnames" array, starting with index "cur_proc"
 562  *                     and add the first "max_matches" into the "ranks"
 563  *                     array.  remove all instances of "name" from
 564  *                     "procnames".
 565  *
 566  * Parameters:
 567  * name - processor name to match
 568  * cur_proc - index into procnames[] at which to start matching
 569  * procnames - array of processor names
 570  * used_procnames - array of values indicating if a given procname has
 571  *                  been allocated or removed already
 572  * nr_procnames - length of procnames array
 573  * ranks - array of processor ranks
 574  * nr_ranks - length of ranks array
 575  * nr_ranks_allocated - number of ranks already filled in, or the next
 576  *                      entry to fill in (equivalent)
 577  *
 578  * Returns number of ranks filled in (allocated).
 579  */
 580 static int match_this_proc(char *name,
 581                            int cur_proc,
 582                            int max_matches,
 583                            char *procnames[],
 584                            char used_procnames[],
 585                            int nr_procnames, 
 586                            int ranks[], 
 587                            int nr_ranks,
 588                            int nr_ranks_allocated)
 589 {
 590     int ranks_remaining, nr_to_alloc, old_nr_allocated;
 591 
 592     old_nr_allocated = nr_ranks_allocated;
 593 
 594     /* calculate how many ranks we want to allocate */
 595     ranks_remaining = nr_ranks - nr_ranks_allocated;
 596     nr_to_alloc = (max_matches < ranks_remaining) ? 
 597         max_matches : ranks_remaining;
 598 
 599     while (nr_to_alloc > 0) {
 600         cur_proc = find_name(name, procnames, used_procnames, nr_procnames, 
 601                              cur_proc);
 602         if (cur_proc < 0) {
 603             /* didn't find it */
 604             return nr_ranks_allocated - old_nr_allocated;
 605         }
 606 
 607         /* need bounds checking on ranks */
 608 #ifdef CB_CONFIG_LIST_DEBUG
 609         FPRINTF(stderr, "  assigning name %s (%d) to rank %d in mapping\n",
 610                procnames[cur_proc], cur_proc, nr_ranks_allocated);
 611 #endif
 612 
 613         ranks[nr_ranks_allocated] = cur_proc;
 614         nr_ranks_allocated++;
 615         used_procnames[cur_proc] = 1;
 616             
 617         cur_proc++;
 618         nr_to_alloc--;
 619     }
 620         
 621     /* take all other instances of this host out of the list */
 622     while (cur_proc >= 0) {
 623         cur_proc = find_name(name, procnames, used_procnames, nr_procnames, 
 624                              cur_proc);
 625         if (cur_proc >= 0) {
 626 #ifdef CB_CONFIG_LIST_DEBUG
 627             FPRINTF(stderr, "  taking name %s (%d) out of procnames\n",
 628                    procnames[cur_proc], cur_proc);
 629 #endif
 630             used_procnames[cur_proc] = 1;
 631             cur_proc++;
 632         }
 633     }
 634     return nr_ranks_allocated - old_nr_allocated;
 635 }
 636   
 637 
 638 /* find_name() - finds the first entry in procnames[] which matches name,
 639  *               starting at index start_ind
 640  *
 641  * Returns an index [0..nr_procnames-1] on success, -1 if not found.
 642  */
 643 static int find_name(char *name, 
 644                      char *procnames[], 
 645                      char used_procnames[],
 646                      int nr_procnames, 
 647                      int start_ind)
 648 {
 649     int i;
 650 
 651     for (i=start_ind; i < nr_procnames; i++) {
 652         if (!used_procnames[i] && !strcmp(name, procnames[i])) break;
 653     }
 654 
 655     if (i < nr_procnames) return i;
 656     else return -1;
 657 }
 658 
 659 /* get_max_procs() - grab the maximum number of processes to use out of
 660  *                   the cb_config_list string
 661  *
 662  * Parameters:
 663  * cb_nodes - cb_nodes value.  this is returned when a "*" is encountered
 664  *            as the max_procs value.
 665  *
 666  * Returns # of processes, or -1 on error.
 667  */
 668 static int get_max_procs(int cb_nodes)
 669 {
 670     int token, max_procs = -1;
 671     char *errptr;
 672 
 673     token = cb_config_list_lex();
 674 
 675     switch(token) {
 676     case AGG_EOS:
 677     case AGG_COMMA:
 678         return 1;
 679     case AGG_COLON:
 680         token = cb_config_list_lex();
 681         if (token != AGG_WILDCARD && token != AGG_STRING) return -1;
 682         if (token == AGG_WILDCARD) max_procs = cb_nodes;
 683         else if (token == AGG_STRING) {
 684             max_procs = (int)strtol(yylval, &errptr, 10);
 685             if (*errptr != '\0') {
 686                 /* some garbage value; default to 1 */
 687                 max_procs = 1;
 688             }
 689         }
 690         /* strip off next comma (if there is one) */
 691         token = cb_config_list_lex();
 692         if (token != AGG_COMMA && token != AGG_EOS) return -1;
 693         
 694         /* return max_procs */
 695         if (max_procs < 0) return -1;
 696         else return max_procs;
 697     }
 698     return -1;
 699 }
 700 
 701 
 702 /* cb_config_list_lex() - lexical analyzer for cb_config_list language
 703  *
 704  * Returns a token of types defined at top of this file.
 705  */
 706 #if defined(BGQPLATFORM)
 707 /* On BlueGene, the ',' character shows up in get_processor_name, so we have to
 708  * use a different delimiter */
 709 #define COLON ':'
 710 #define COMMA ';'
 711 #define DELIMS ":;"
 712 #else 
 713 /* these tokens work for every other platform */
 714 #define COLON ':'
 715 #define COMMA ','
 716 #define DELIMS ":,"
 717 #endif
 718 
 719 static int cb_config_list_lex(void)
 720 {
 721     int slen;
 722 
 723     if (*token_ptr == '\0') return AGG_EOS;
 724 
 725     slen = (int)strcspn(token_ptr, DELIMS);
 726 
 727     if (*token_ptr == COLON) {
 728         token_ptr++;
 729         return AGG_COLON;
 730     }
 731     if (*token_ptr == COMMA) {
 732         token_ptr++;
 733         return AGG_COMMA;
 734     }
 735 
 736     if (*token_ptr == '*') {
 737         /* make sure that we don't have characters after the '*' */
 738         if (slen == 1) {
 739             token_ptr++;
 740             return AGG_WILDCARD;
 741         }
 742         else return AGG_ERROR;
 743     }
 744 
 745     /* last case: some kind of string.  for now we copy the string. */
 746 
 747     /* it would be a good idea to look at the string and make sure that
 748      * it doesn't have any illegal characters in it.  in particular we
 749      * should ensure that no one tries to use wildcards with strings 
 750      * (e.g. "ccn*").
 751      */
 752     ADIOI_Strncpy(yylval, token_ptr, slen);
 753     yylval[slen] = '\0';
 754     token_ptr += slen;
 755     return AGG_STRING;
 756 }

/* [<][>][^][v][top][bottom][index][help] */