/*
* Copyright (c) 2001-2003 The Trustees of Indiana University.
* All rights reserved.
* Copyright (c) 1998-2001 University of Notre Dame.
* All rights reserved.
* Copyright (c) 1994-1998 The Ohio State University.
* All rights reserved.
*
* This file is part of the LAM/MPI software package. For license
* information, see the LICENSE file in the top level directory of the
* LAM/MPI source distribution.
*
* $HEADER$
*
* $Id: parse_id.c,v 6.12 2003/03/19 19:15:36 jsquyres Exp $
*
* Function: - identifier parsing package
* - id_range() based in part on Trollius 2.0,
* Copyright 1990 The Ohio State University and Cornell
* Research Foundation
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <all_list.h>
#include <net.h>
#include <portable.h>
#include <preq.h>
#include <rreq.h>
#include <terror.h>
#include <typical.h>
#include <args.h>
#define NEW 1
#define ONE 2
#define MANY 3
/*
* local variables
*/
static LIST *nodelist = 0; /* node ID list */
static LIST *proclist = 0; /* process ID list */
static char fmt_str[16]; /* more than 16 long ain't mnemonic! */
struct id {
int4 id_value; /* ID itself */
int4 id_flags; /* descriptive flags */
int4 id_count; /* # IDs actually represented */
int4 id_index; /* position in list (legacy) */
};
/*
* local functions
*/
static int nid_cast(int4 type, int4 mask, int is_node, int *ixp);
static int id_range(char *s, int4 flags, int is_node, int *ixp, LIST *lp);
static void id_get (int4 *ixp, int4 *idp, int4* flp, LIST *lp);
static int resolve_cpu(int cpuid);
/*
* nid_parse
*
* Functions: - parses node identifier mnemonics
* - rewrites arg vector with non-identifier args
* - argc, argv are undefined in case of ERROR
* Accepts: - command line arguments
* Returns: - 0 or ERROR
*/
int
nid_parse(int *argc, char **argv)
{
int index = 0; /* current index */
int othersc; /* left over count */
char **othersv; /* left over arguments */
struct id newid; /* new list element */
/*
* Initialize the list.
*/
if (nodelist == 0) {
nodelist = al_init(sizeof(struct id), 0);
if (nodelist == 0) return(LAMERROR);
}
/*
* Pass argument 0 through.
*/
othersc = 1;
othersv = argv++;
++othersv;
--*argc;
/*
* Loop through all the arguments.
*/
while (*argc) {
/*
* Is it a generic node identifier?
*/
if ((**argv == 'n') && isdigit((int) *(*argv + 1))) {
if (id_range(*argv + 1, 0, 1, &index, nodelist))
return(LAMERROR);
}
/*
* Is it a generic CPU identifier?
*/
else if ((**argv == 'c') && isdigit((int) *((*argv + 1)))) {
if (id_range(*argv + 1, 0, 0, &index, nodelist)) {
return(LAMERROR);
}
}
/*
* Is it the local host identifier (h)?
*/
else if ((**argv == 'h') && (*(*argv + 1) == '\0')) {
newid.id_value = LOCAL;
newid.id_flags = NT_ME;
newid.id_count = 1;
newid.id_index = index++;
if (al_append(nodelist, &newid) == 0) return(LAMERROR);
}
/*
* Is it the origin host identifier (o)?
*/
else if ((**argv == 'o') && (*(*argv + 1) == '\0')) {
newid.id_value = getorigin();
newid.id_flags = NT_ORIGIN;
newid.id_count = 1;
newid.id_index = index++;
if (al_append(nodelist, &newid) == 0) return(LAMERROR);
}
/*
* Is it a multicast destination?
*/
/*
* The "C" notation has been redfined from its original OTB definition
* -- it now means "one per CPU".
*/
else if ((**argv == 'C') && (*(*argv + 1) == '\0')) {
if (nid_cast(0, NT_WASTE | NT_CAST, 0, &index))
return(LAMERROR);
}
else if ((**argv == 'N') && (*(*argv + 1) == '\0')) {
if (nid_cast(0, NT_WASTE | NT_CAST, 1, &index))
return(LAMERROR);
}
/*
* Bump the non-nodeid pointer and counter.
*/
else {
*(othersv++) = *argv;
++othersc;
}
--*argc;
++argv;
}
*argc = othersc;
return (0);
}
/*
* pid_parse
*
* Functions: - parses process identifier mnemonics
* - rewrites arg vector with non-identifier args
* - argc, argv are undefined in case of ERROR
* Accepts: - command line arguments
* Returns: - 0 or ERROR
*/
int
pid_parse(int *argc, char **argv)
{
int index = 0; /* current index */
int othersc; /* left over count */
char **othersv; /* left over arguments */
/*
* Initialize the list.
*/
if (proclist == 0) {
proclist = al_init(sizeof(struct id), 0);
if (proclist == 0) return(LAMERROR);
}
/*
* Pass argument 0 through.
*/
othersc = 1;
othersv = argv++;
++othersv;
--*argc;
/*
* Loop through all the arguments.
*/
while (*argc) {
/*
* Is it a process identifier?
*/
if ((**argv == 'p') && isdigit((int) *(*argv + 1))) {
if (id_range(*argv + 1, SELECT_PID, 1, &index,
proclist))
return(LAMERROR);
}
/*
* Is it an index identifier?
*/
else if (((**argv == '%') || (**argv == 'i')) &&
isdigit((int) *(argv[0] + 1))) {
if (id_range(*argv + 1, SELECT_INDEX, 1, &index,
proclist)) return(LAMERROR);
}
/*
* Bump the non-id pointer and counter.
*/
else {
*(othersv++) = *argv;
++othersc;
}
--*argc;
++argv;
}
*argc = othersc;
return (0);
}
/*
* nid_free
*
* Function: - frees the node ID list
*/
void
nid_free()
{
if (!nodelist) return;
al_free(nodelist);
nodelist = 0;
}
/*
* pid_free
*
* Function: - frees the process ID list
*/
void
pid_free()
{
if (!proclist) return;
al_free(proclist);
proclist = 0;
}
/*
* nid_get
*
* Function: - gets next node identifier
* Accepts: - value returned index ptr
* (-1 is returned if empty list)
* - value returned identifier ptr
* - value returned flags ptr
*/
void
nid_get (int4 *ixp, int4 *idp, int4 *flp)
{
id_get(ixp, idp, flp, nodelist);
}
/*
* pid_get
*
* Function: - gets next process identifier
* Accepts: - value returned index ptr
* (-1 is returned if empty list)
* - value returned identifier ptr
* - value returned flags ptr
*/
void
pid_get (int4 *ixp, int4 *idp, int4 *flp)
{
id_get(ixp, idp, flp, proclist);
}
/*
* nid_count
*
* Returns: - count of current node identifier
*/
int4
nid_count()
{
struct id *p;
if (nodelist == 0) {
return(0);
} else {
p = (struct id *) al_top(nodelist);
return(p ? p->id_count : 0);
}
}
/*
* nid_fmt
*
* Function: - translates a node identifier into a mnemonic string
* Accepts: - node identifier
* Returns: - mnemonic string
*/
char *
nid_fmt(int4 node)
{
if (node == NOTNODEID) {
strcpy(fmt_str, "?");
} else if (node == LOCAL) {
strcpy(fmt_str, "local");
} else if (node == HOST2COMPNODE) {
strcpy(fmt_str, "N");
/*
* The "C" notation has been redfined from its original OTB definition
* -- it now means "one per CPU".
*/
} else if (node == HOST2COMPCPU) {
strcpy(fmt_str, "C");
} else if (node == getorigin()) {
sprintf(fmt_str, "n%d (o)", node);
} else {
sprintf(fmt_str, "n%d", node);
}
return(fmt_str);
}
/*
* nid_parse1
*
* Function: - parses one node identifier
* Accepts: - mnemonic string
* Returns: - node identifier
*/
int4
nid_parse1(char *s)
{
int4 node;
if (strcmp(s, "h") == 0) {
node = LOCAL;
} else if (strcmp(s, "o") == 0) {
node = getorigin();
} else if (strcmp(s, "local") == 0) {
node = LOCAL;
} else if (strcmp(s, "N") == 0) {
node = HOST2COMPNODE;
/*
* The "C" notation has been redfined from its original OTB definition
* -- it now means "one per CPU".
*/
} else if (strcmp(s, "C") == 0) {
node = HOST2COMPCPU;
}
else if (sscanf(s, " n%d", &node) == 1) {
}
else if (sscanf(s, " c%d", &node) == 1) {
}
else {
node = NOTNODEID;
}
return(node);
}
/*
* nid_usage
*
* Function: - prints a nodespec usage message
*/
void
nid_usage()
{
printf("\nNodes: n<list>, eg., n0-3,5,0xa,12-15\n");
printf("\nCPUs: c<list>, eg., c0-3,5,0xa,12-15\n");
}
/*
* nid_cast
*
* Function: - establish a cast of nodes
* - LAM version
* - Trollius version registers with castd
* Accepts: - node type
* - node mask
* - whether CPUs or nodes
* - current index ptr
* Returns: - 0 or ERROR
*/
static int
nid_cast(int4 type, int4 mask, int is_node, int *ixp)
{
int4 nnodes; /* node array size */
int4 *pnodes; /* node array */
int i, j;
struct id newid; /* new list element */
struct route r; /* route entry */
nnodes = getntype(type, mask);
if (nnodes < 0) return(LAMERROR);
if (nnodes == 0) return(0);
pnodes = (int4 *) malloc((unsigned) (nnodes * sizeof(int4)));
if (pnodes == 0) return(LAMERROR);
if (getnodes(pnodes, nnodes, type, mask)) return(LAMERROR);
for (i = 0; i < nnodes; ++i) {
newid.id_value = pnodes[i];
newid.id_flags = 0;
newid.id_count = 1;
newid.id_index = (*ixp)++;
if (al_append(nodelist, &newid) == 0)
return(LAMERROR);
if (!is_node) {
r.r_nodeid = pnodes[i];
getrent(&r);
for (j = 1; j < r.r_ncpus; j++) {
newid.id_index = (*ixp)++;
if (al_append(nodelist, &newid) == 0)
return(LAMERROR);
}
}
}
return(0);
}
/*
* id_get
*
* Function: - gets next identifier from given list
* - rotates it to bottom of list
* Accepts: - value returned index ptr
* (-1 is returned if empty list)
* - value returned identifier ptr
* - value returned flags ptr
* - list descriptor ptr
*/
static void
id_get (int4 *ixp, int4 *idp, int4* flp, LIST *lp)
{
struct id *p;
struct id newid;
if (nodelist == 0) {
*ixp = -1;
} else {
p = (struct id *) al_top(lp);
if (p == 0) {
*ixp = -1;
} else {
*ixp = p->id_index;
*idp = p->id_value;
*flp = p->id_flags;
memcpy((char *) &newid, (char *) p, sizeof(newid));
al_delete(lp, p);
al_append(lp, &newid);
}
}
}
/*
* id_range
*
* Function: - parses the ID range format
* - example: 1,3-5,7
* Accepts: - range string
* - flags to use with every value found
* - current index ptr
* - list descriptor ptr
* Returns: - 0 or ERROR
*/
static int
id_range(char *s, int4 flags, int is_node, int *ixp, LIST *lp)
{
int c; /* current character */
int4 id; /* current identifier */
int4 oldid = 0; /* previous identifier */
int mode; /* parsing state */
struct id newid; /* new list entry */
mode = NEW;
while ((c = *s) != '\0') {
if (c == ',') {
if (mode == NEW) {
errno = EBADIDSPEC;
return(LAMERROR);
}
++s;
mode = NEW;
}
else if (c == '-') {
if (mode != ONE) {
errno = EBADIDSPEC;
return(LAMERROR);
}
++s;
mode = MANY;
}
else {
if (xtoi(&s, &id)) {
if (errno == EBADASCIINUMB) {
errno = EBADIDSPEC;
}
return(LAMERROR);
}
if (mode == NEW) {
if (is_node)
newid.id_value = id;
else
newid.id_value = resolve_cpu(id);
newid.id_flags = flags;
newid.id_count = 1;
newid.id_index = (*ixp)++;
if (al_append(lp, &newid) == 0)
return(LAMERROR);
oldid = id;
mode = ONE;
}
else if (mode == MANY) {
if (id < oldid) {
errno = EBADIDSPEC;
return(LAMERROR);
}
while (++oldid <= id) {
if (is_node)
newid.id_value = oldid;
else
newid.id_value = resolve_cpu(oldid);
newid.id_flags = flags;
newid.id_count = 1;
newid.id_index = (*ixp)++;
if (al_append(lp, &newid) == 0)
return(LAMERROR);
}
}
else {
errno = EIMPOSSIBLE;
return(LAMERROR);
}
}
} /* while() */
return (0);
}
/*
* resolve_cpu
*
* Function: - resolves a CPU id to a node ID
* Accepts: - cpu ID
* Returns: - nid or LAMERROR
*/
static int
resolve_cpu(int cpuid)
{
int i, ncpus;
int nnodes;
int *nodes;
struct route *r;
/*
* Find out how many CPUs we have
*/
nnodes = getntype(0, NT_CAST);
nodes = (int *) malloc(sizeof(int) * nnodes);
if (nodes == NULL)
return (LAMERROR);
r = (struct route*) malloc(sizeof(struct route) * nnodes);
if (r == NULL)
return (LAMERROR);
getnodes(nodes, nnodes, 0, NT_CAST);
for (ncpus = i = 0; i < nnodes; i++) {
r[i].r_nodeid = nodes[i];
getrent(&r[i]);
ncpus += r[i].r_ncpus;
}
if (cpuid < 0 || cpuid >= ncpus) {
free(r);
free(nodes);
return (LAMERROR);
}
/*
* Map the CPU id to an nid
*/
for (ncpus = i = 0; i < nnodes; i++) {
if (cpuid < (ncpus + r[i].r_ncpus))
break;
ncpus += r[i].r_ncpus;
}
free(r);
free(nodes);
return i;
}
#if 0
/*
* backwards compatibility
*/
/* Down with internal backwards compatability... */
int parse_nodes(int *ac, char **av) { return(nid_parse(ac, av)); }
int parse_procs(ac, av) int *ac; char **av; { return(pid_parse(ac, av)); }
void getnode(ixp, idp, flp) int4 *ixp, *idp, *flp; { nid_get(ixp, idp, flp); }
void getproc(ixp, idp, flp) int4 *ixp, *idp, *flp; { pid_get(ixp, idp, flp); }
char *mnemonic(node) int4 node; { return(nid_fmt(node)); }
int mnnodeid(s) char *s; { return(nid_parse1(s)); }
void mnusage() { nid_usage(); }
#endif
syntax highlighted by Code2HTML, v. 0.9.1