/*
 * hello.c - test mpi program
 *
 * $Id: hello.c 326 2006-01-24 21:35:26Z pw $
 *
 * Copyright (C) 2000-6 Pete Wyckoff <pw@osc.edu>
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>

#ifdef __GNUC__
#  define ATTR_UNUSED   __attribute__ ((unused))
#else
#  define ATTR_UNUSED
#endif

static char hostname[1024];

/*
 * "Fake" the MPI calls to test comm=none.
 */
#if 0
const int MPI_COMM_WORLD = 0;
static void MPI_Init(int *x, char ***y) { }
static void MPI_Comm_size(int n, int *np) { *np = 1; }
static void MPI_Comm_rank(int n, int *np) { *np = 0; }
static void MPI_Finalize(void) { }
#else
#include "mpi.h"
#endif

static void
handle(int sig ATTR_UNUSED)
{
    const char *opts = getenv("GMPI_OPTS");
    unsigned long *ul = 0;

    printf("hello: %s %s MPI_Init did not finish\n", hostname,
      opts ? opts : "");
    sleep(2);
    *ul = 0;
    exit(1);
}

int
main(int argc, char *argv[])
{
    int myid, numproc;
    int readlines = 0, doze = 0, segv = -1, segvearly = 0;
    int abort = -1, mixup = 0;
    int *exitval = 0, numexitval = 0;
    struct sigaction act;
    char buf[1024];
    FILE *fp = stdout;
    int i;

    for (i=1; i<argc; i++) {
	if (!strcmp(argv[i], "-l"))
	    readlines = 1;
	else if (!strcmp(argv[i], "-sleep"))
	    doze = 1;
	else if (!strcmp(argv[i], "-stderr")) {
	    fp = stderr;
	    setlinebuf(fp);  /* else output will mix up and confuse tester */
	} else if (!strcmp(argv[i], "-segv")) {
	    segv = 0;
	    if (i+1 < argc) {
		char *cq;
		segv = strtol(argv[i+1], &cq, 10);
		if (cq != argv[i+1])  /* got digits, consume argument */
		    ++i;
	    }
	} else if (!strcmp(argv[i], "-segvearly"))
	    segvearly = 1;
	else if (!strcmp(argv[i], "-abort")) {
	    abort = 0;
	    if (i+1 < argc) {
		char *cq;
		abort = strtol(argv[i+1], &cq, 10);
		if (cq != argv[i+1])  /* got digits, consume argument */
		    ++i;
	    }
	} else if (!strcmp(argv[i], "-mixup"))
	    mixup = 1;
	else if (!strcmp(argv[i], "-exitval")) {
	    numexitval = argc - (i+1);
	    exitval = malloc(numexitval * sizeof(*exitval));
	    memset(exitval, 0, numexitval * sizeof(*exitval));
	    numexitval = 0;
	    while (i+1 < argc) {
		char *cq;
		exitval[numexitval] = strtol(argv[i+1], &cq, 10);
		if (cq == argv[i+1])  /* did not parse, give up on these */
		    break;
		++numexitval;
		++i;
	    }
	}
    }

    if (segvearly) {
	/* segv "early" before MPI initialization */
	unsigned long *ul = 0;
	*ul = 0;
    }

    /* MPI initialization */
    gethostname(hostname, sizeof(hostname));
    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask, SIGALRM);
    act.sa_flags = 0;
    act.sa_handler = handle;
    sigaction(SIGALRM, &act, 0);
    /* printf("to mpi init\n"); fflush(stdout); */
    /* sleep(30); */
    alarm(4 * 60 * 60);  /* 4 hours */
    MPI_Init(&argc, &argv);
    alarm(0);
    MPI_Comm_size(MPI_COMM_WORLD, &numproc);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);

#if 1
    /* Ensure fully connected.  This is required for mpich1/p4 otherwise
     * the MPI_Finalize will hang on some nodes oddly. */
    {
	int i, j;
	char buf[4];
	MPI_Status st;

	for (i=0; i<numproc; i++) {
	    for (j=0; j<numproc; j++) {
		if (i == j) continue;
		if (myid == i)
		    MPI_Send(buf, 4, MPI_BYTE, j, i * numproc + j,
		      MPI_COMM_WORLD);
		if (myid == j)
		    MPI_Recv(buf, 4, MPI_BYTE, i, i * numproc + j,
		      MPI_COMM_WORLD, &st);
	    }
	}
    }
#endif

    fprintf(fp, "hello from %d/%d hostname %s pid %d with %d args:",
      myid, numproc, hostname, getpid(), argc-1);
    while (++argv, --argc)
	fprintf(fp, " %s", *argv);
    fprintf(fp, "\n");
    fflush(fp);

#if 0
    /* keep things synchronized */
    { 
    int sleep_time = 2 + myid * 2;
    sleep(sleep_time);
    fprintf(fp, "hello from %d/%d name %s sleep %2d done.\n", myid, numproc,
      hostname, sleep_time);
    fflush(fp);
    }
#endif

#if 0
    /* display file descriptors */
    {
	int i;
	char s[1024];
	for (i=0; i<9; i++) {
	    sprintf(s, "/proc/%d/fd/%d", getpid(), i);
	    if (readlink(s, buf, sizeof(buf)) >= 0)
		printf("hello %d %s -> %s\n", myid, s, buf);
	}
    }
#endif

    if (mixup) {
	const char *mixstr = "The rain in spain falls mainly in the plain.\n";
	int len = strlen(mixstr);
	int pos = 0, top;
	srand48(time(0) + myid);
	for (i=0; i<40; i++) {
	    do {
		top = (int)(drand48() * len / 3);
		top += pos;
		top %= len;
	    } while (pos == top);
#if 0
	    /* add text of who says what */
	    putchar('<');
	    if (myid < 10)
		putchar(myid + '0');
	    else if (myid < 10 + 26)
		putchar(myid - 10 + 'A');
	    else
		putchar('|');
#endif
	    while (pos != top) {
		putchar(mixstr[pos]);
		if (++pos == len)
		    pos = 0;
	    }
	    usleep((int)(1000000. * drand48()));
	}
	while (pos != 0) {
	    putchar(mixstr[pos]);
	    if (++pos == len)
		pos = 0;
	}
    }

    if (readlines)
	while (fgets(buf, sizeof(buf), stdin))
	    fprintf(fp, "hello %d got line: %s", myid, buf);

    if (abort == myid) {
	sleep(2);
	MPI_Abort(MPI_COMM_WORLD, 4269);
    }

    if (doze) {
	/* close everything and wait awhile */
	(void) close(0);
	(void) close(1);
	(void) close(2);
	sleep(6);
    }

    if (segv == myid) {
	unsigned long *ul = 0;
	sleep(2);
	*ul = 0;
    }

    MPI_Finalize();
    if (myid < numexitval)
	return exitval[myid];
    else
	return 0;
}



syntax highlighted by Code2HTML, v. 0.9.1