
/*
 *         PVM version 3.3:  Parallel Virtual Machine System
 *               University of Tennessee, Knoxville TN.
 *           Oak Ridge National Laboratory, Oak Ridge TN.
 *                   Emory University, Atlanta GA.
 *      Authors:  A. L. Beguelin, J. J. Dongarra, G. A. Geist,
 *    W. C. Jiang, R. J. Manchek, B. K. Moore, and V. S. Sunderam
 *                   (C) 1992 All Rights Reserved
 *
 *                              NOTICE
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted
 * provided that the above copyright notice appear in all copies and
 * that both the copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * Neither the Institutions (Emory University, Oak Ridge National
 * Laboratory, and University of Tennessee) nor the Authors make any
 * representations about the suitability of this software for any
 * purpose.  This software is provided ``as is'' without express or
 * implied warranty.
 *
 * PVM version 3 was funded in part by the U.S. Department of Energy,
 * the National Science Foundation and the State of Tennessee.
 */

/*
 *	job.c
 *
 *	Job descriptor / output gathering code.
 *
$Log: job.c,v $
 * Revision 1.2  1994/06/03  20:01:52  manchek
 * version 3.3.0
 *
 * Revision 1.1  1993/08/30  23:30:32  manchek
 * Initial revision
 *
 */


#include <stdio.h>
#ifdef	SYSVSTR
#include <string.h>
#define	CINDEX(s,c)	strchr(s,c)
#else
#include <strings.h>
#define	CINDEX(s,c)	index(s,c)
#endif
#include <pvm3.h>
#include <pvmtev.h>
#include "myalloc.h"
#include "job.h"
#include "tevfmt.h"
#include "../src/listmac.h"
#include "../src/bfunc.h"

extern char *pvm_errlist[];
extern int pvm_nerr;

extern int mytid;						/* from cons.c */

struct job *joblist = 0;
int nextjob = 1;

static char rcsid[] = "$Id: job.c,v 1.2 1994/06/03 20:01:52 manchek Exp $";


struct job *
job_new(jid)
	int jid;
{
	struct job *jp = joblist->j_link;
	struct job *jp2;
	struct obuf *op;

	while (jp != joblist && jp->j_jid < jid)
		jp = jp->j_link;
	if (jp->j_jid != jid) {
		jp2 = TALLOC(1, struct job, "job");
		BZERO((char*)jp2, sizeof(struct job));
		jp2->j_jid = jid;
		op = TALLOC(1, struct obuf, "obuf");
		BZERO((char*)op, sizeof(struct obuf));
		op->o_link = op->o_rlink = op;
		jp2->j_obufs = op;
		LISTPUTBEFORE(jp, jp2, j_link, j_rlink);
		jp = jp2;
	}
	return jp;
}


job_init()
{
	if (!joblist) {
		joblist = TALLOC(1, struct job, "job");
		BZERO((char*)joblist, sizeof(struct job));
		joblist->j_link = joblist->j_rlink = joblist;
	}
}


struct job *
job_find(jid)
	int jid;
{
	struct job *jp = joblist->j_link;

	while (jp != joblist && jp->j_jid < jid)
		jp = jp->j_link;
	if (jp->j_jid == jid)
		return jp;
	return (struct job*)0;
}


job_free(jp)
	struct job *jp;
{
	LISTDELETE(jp, j_link, j_rlink);
	if (jp->j_obufs)
		MY_FREE(jp->j_obufs);
	if (jp->j_ff)
		(void)fclose(jp->j_ff);
	MY_FREE(jp);
	return 0;
}


struct obuf *
obuf_find(jp, tid)
	struct job *jp;
	int tid;
{
	struct obuf *op = jp->j_obufs->o_link;

	while (op != jp->j_obufs && op->o_tid < tid)
		op = op->o_link;
	if (op->o_tid == tid)
		return op;
	return (struct obuf*)0;
}


struct obuf *
obuf_new(jp, tid)
	struct job *jp;
	int tid;
{
	struct obuf *op = jp->j_obufs->o_link;
	struct obuf *op2;

	while (op != jp->j_obufs && op->o_tid < tid)
		op = op->o_link;
	if (op->o_tid != tid) {
		op2 = TALLOC(1, struct obuf, "obuf");
		BZERO((char*)op2, sizeof(struct obuf));
		op2->o_tid = tid;
		LISTPUTBEFORE(op, op2, o_link, o_rlink);
		op = op2;
	}
	return op;
}


obuf_free(jp, op)
	struct job *jp;
	struct obuf *op;
{
	LISTDELETE(op, o_link, o_rlink);
	if (op->o_buf)
		MY_FREE(op->o_buf);
	MY_FREE(op);
	if (jp->j_obufs->o_link == jp->j_obufs) {
		printf("[%d] finished\n", jp->j_jid);
		job_free(jp);
	}
	return 0;
}


obuf_dump(jp)
	struct job *jp;
{
	struct obuf *op;

	for (op = jp->j_obufs->o_link; op != jp->j_obufs; op = op->o_link) {
		printf("obuf_dump() t%x\n", op->o_tid);
	}
	return 0;
}


checkoutput(jp, cc, len, cod, src)
	struct job *jp;
	int cc;					/* message mid */
	int len;
	int cod;
	int src;
{
	int tid;					/* task */
	int n;						/* length or event code */
	char *p;
	int ptid;
	struct obuf *op;

	if (jp->j_flag & JOB_TRACE) {
		checktrace(jp, cc, len, cod, src);
		return 0;
	}

	pvm_upkint(&tid, 1, 1);
	pvm_upkint(&n, 1, 1);

	if (n > 0) {
		if (!(op = obuf_find(jp, tid))) {
			printf("Bogus message, job %d has no task t%x\n",
					jp->j_jid, tid);
			goto hork;
		}
		if (n + op->o_len >= op->o_maxl) {
			op->o_maxl = op->o_len + n + 1;
/*
			printf("REALLOC t%x buf to %d\n", tid, op->o_maxl);
*/
			if (op->o_buf)
				op->o_buf = TREALLOC(op->o_buf, op->o_maxl, char);
			else
				op->o_buf = TALLOC(op->o_maxl, char, "");
		}
		pvm_upkbyte(op->o_buf + op->o_len, n, 1);
		op->o_buf[op->o_len + n] = 0;
/*
		printf("UNPACK t%x {%s}\n", tid, op->o_buf + op->o_len);
*/
		p = op->o_buf + op->o_len;
		op->o_len += n;
		while (p = CINDEX(p, '\n')) {
			*p++ = 0;
			fprintf((jp->j_ff ? jp->j_ff : stdout),
					"[%d:t%x] %s\n", jp->j_jid, tid, op->o_buf);
			op->o_len -= p - op->o_buf;
			BCOPY(p, op->o_buf, op->o_len);
			p = op->o_buf;
		}

	} else {
		switch (n) {

		case 0:
			if (!(op = obuf_find(jp, tid))) {
				printf("Bogus message, job %d has no task t%x\n",
						jp->j_jid, tid);
				goto hork;
			}
			if (op->o_len > 0) {
				fprintf((jp->j_ff ? jp->j_ff : stdout),
						"[%d:t%x] %s\n", jp->j_jid, tid, op->o_buf);
				op->o_len = 0;
			}
			op->o_flag |= GOTEOF;
			if (op->o_flag == (GOTSPAWN|GOTEOF)) {
				fprintf((jp->j_ff ? jp->j_ff : stdout),
						"[%d:t%x] EOF\n", jp->j_jid, tid);
				obuf_free(jp, op);
			}
			break;

		case -1:
			if (!(op = obuf_find(jp, tid)))
				op = obuf_new(jp, tid);
/*
			pvm_upkint(&ptid, 1, 1);
*/
			op->o_flag |= GOTSPAWN;
			if (op->o_flag == (GOTSPAWN|GOTEOF)) {
				fprintf((jp->j_ff ? jp->j_ff : stdout),
						"[%d:t%x] EOF\n", jp->j_jid, tid);
				obuf_free(jp, op);
			}

			break;

		case -2:
			if (!(op = obuf_find(jp, tid)))
				op = obuf_new(jp, tid);
/*
			pvm_upkint(&ptid, 1, 1);
*/
			break;

		default:
			printf("Bogus message from job %d task t%x\n", jp->j_jid, tid);
			break;
		}
	}

hork:
	pvm_freebuf(cc);
	return 0;
}


checktrace(jp, cc, len, cod, src)
	struct job *jp;
	int cc;					/* message mid */
	int len;
	int cod;
	int src;
{
	int tid;					/* task */
	int kind;					/* length or event code */
	int sec, usec;
	char *p;
	int ptid;
	struct obuf *op;

	pvm_upkint(&sec, 1, 1);
	pvm_upkint(&usec, 1, 1);
	pvm_upkint(&tid, 1, 1);
	pvm_upkint(&kind, 1, 1);

	if (kind >= 0 && kind <= TEV_MAX) {
		{
			if (!(op = obuf_find(jp, tid)))
				op = obuf_new(jp, tid);
			op->o_flag |= GOTSPAWN;
		}
		if (!(op = obuf_find(jp, tid))) {
			printf("Bogus message, job %d has no task t%x\n",
					jp->j_jid, tid);
			goto hork;
		}
		fprintf((jp->j_ff ? jp->j_ff : stdout), "[T%d:t%x] %d.%06d ",
				jp->j_jid, tid, sec, usec);
		wuff_trace((jp->j_ff ? jp->j_ff : stdout), kind);
		fprintf((jp->j_ff ? jp->j_ff : stdout), "\n");

		switch (kind) {

		case TEV_ENDTASK:	/* EOF */
			if (!(op = obuf_find(jp, tid))) {
				printf("Bogus message, job %d has no task t%x\n",
						jp->j_jid, tid);
				goto hork;
			}
			op->o_flag |= GOTEOF;
			if (op->o_flag == (GOTSPAWN|GOTEOF)) {
				fprintf((jp->j_ff ? jp->j_ff : stdout),
						"[T%d:t%x] END\n", jp->j_jid, tid);
				obuf_free(jp, op);
			}
			break;

		case TEV_SPNTASK:	/* tm_spawn */
			if (!(op = obuf_find(jp, tid)))
				op = obuf_new(jp, tid);
			op->o_flag |= GOTSPAWN;
			if (op->o_flag == (GOTSPAWN|GOTEOF)) {
				fprintf((jp->j_ff ? jp->j_ff : stdout),
						"[T%d:t%x] END\n", jp->j_jid, tid);
				obuf_free(jp, op);
			}

			break;

		case TEV_NEWTASK:	/* dm_exec */
			if (!(op = obuf_find(jp, tid)))
				op = obuf_new(jp, tid);
			break;

		default:
			break;
		}

	} else {
		printf("Bogus message from job %d task t%x\n", jp->j_jid, tid);
	}

hork:
	pvm_freebuf(cc);
	return 0;
}


