
static char rcsid[] =
	"$Id: lpvmgen.c,v 1.99 2004/02/17 18:01:29 pvmsrc Exp $";

/*
 *         PVM version 3.4:  Parallel Virtual Machine System
 *               University of Tennessee, Knoxville TN.
 *           Oak Ridge National Laboratory, Oak Ridge TN.
 *                   Emory University, Atlanta GA.
 *      Authors:  J. J. Dongarra, G. E. Fagg, M. Fischer
 *          G. A. Geist, J. A. Kohl, R. J. Manchek, P. Mucci,
 *         P. M. Papadopoulos, S. L. Scott, and V. S. Sunderam
 *                   (C) 1997 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.
 */

/*
 *	lpvmgen.c
 *
 *	Libpvm generic functions.
 *
 * $Log: lpvmgen.c,v $
 * Revision 1.99  2004/02/17 18:01:29  pvmsrc
 * False alarm, removed debug output for AMD64.
 * (Spanker=kohl)
 *
 * Revision 1.98  2004/02/09 17:21:13  pvmsrc
 * Oops...  typo...
 * (Spanker=kohl)
 *
 * Revision 1.97  2004/02/09 17:17:01  pvmsrc
 * Added pvmlogperror debug output for AMD64...
 * 	- the arch that wouldn't die...  er, run without seg faulting...  :)
 * (Spanker=kohl)
 *
 * Revision 1.96  2004/02/03 21:40:57  pvmsrc
 * Added check for NULL strerror() return...
 * 	- to chase down AMD64 problem...
 * (Spanker=kohl)
 *
 * Revision 1.95  2004/01/14 19:12:34  pvmsrc
 * Added (char *) cast to strerror() assignment...
 * (Spanker=kohl)
 *
 * Revision 1.94  2004/01/14 18:50:56  pvmsrc
 * Added new AIX5* arches.
 * (Spanker=kohl)
 *
 * Revision 1.93  2001/09/26 23:35:43  pvmsrc
 * Removed stuffing of PVM_VMID env var when spawning remote tasks.
 * 	- first, each host can have it's own local vmid (why not?),
 * 		so we shouldn't stomp that on the spawn.
 * 	- second, each local pvmd sets its PVM_VMID env var on startup
 * 		if the option is passed to it, so there's no need to
 * 		additionally set the vmid on the spawn.
 * (Spanker=kohl)
 *
 * Revision 1.92  2001/09/26 21:22:34  pvmsrc
 * Added Handling for Optional Virtual Machine ID.
 * 	- append PVM_VMID env var to spawn env for tasks (if set).
 * (Spanker=kohl)
 *
 * Revision 1.91  2001/06/28 16:45:29  pvmsrc
 * D-Oh!  Better set context around message handler functions.
 * 	- if message comes in with a particular context, reply should
 * 		probably be in same context!  :-]
 * (Spanker=kohl)
 *
 * Revision 1.90  2001/05/11 18:58:11  pvmsrc
 * Added use of new "USESTRERROR" define.
 * 	- uses strerror() function instead of sys_errlist/sys_nerr
 * 		(which aren't public globals on some new operating systems).
 * (Spanker=kohl)
 *
 * Revision 1.89  2001/02/07 23:14:06  pvmsrc
 * First Half of CYGWIN Check-ins...
 * (Spanker=kohl)
 *
 * Revision 1.88  2000/06/15 17:51:50  pvmsrc
 * Fixed bug in WIN32 direct routing.
 * 	- stupid #endif in the wrong place, pvm_fd_add() call whacked.
 * 	- turned back on direct routing default and setopt.
 * (Spanker=kohl)
 *
 * Revision 1.87  2000/02/17 23:12:12  pvmsrc
 * *** Changes for new BEOLIN port ***
 * 	- MPP-like, similar to SP2, etc.
 * 	- submitted by Paul Springer <pls@smokeymt.jpl.nasa.gov>.
 * 	- format-checked & cleaned up by Jeembo...  :-)
 * (Spanker=kohl)
 *
 * Revision 1.86  2000/02/16 21:59:43  pvmsrc
 * Fixed up #include <sys/types.h> stuff...
 * 	- use <bsd/sys/types.h> for IMA_TITN...
 * 	- #include before any NEEDMENDIAN #includes...
 * (Spanker=kohl)
 *
 * Revision 1.85  1999/11/08 17:44:32  pvmsrc
 * SGI compiler cleanup.
 * (Spanker=kohl)
 *
 * Revision 1.84  1999/10/27 18:49:00  pvmsrc
 * Fixed (hopefully) the function header declaration for pvm_recvf().
 * 	- should work on all platforms now (using __ProtoGlarp__())...
 * (Spanker=kohl)
 *
 * Revision 1.83  1999/07/08 18:59:56  kohl
 * Fixed "Log" keyword placement.
 * 	- indent with " * " for new CVS.
 *
 * Revision 1.82  1999/03/12 20:55:33  pvmsrc
 * Don't allow direct routing in WIN32 until we fix it.  Shit.
 * (Spanker=kohl)
 * 
 * Revision 1.81  1999/01/29  17:02:50  pvmsrc
 * Implemented pvm_archcode() for 3.4 data signature handling.
 * 	- backwards compat.
 * (Spanker=kohl)
 *
 * Revision 1.80  1999/01/14  19:10:25  pvmsrc
 * More mbox fixes:
 * 	- make sure pvm_errno gets set in mbox and old insert/lookup/delete
 * 		calls, even if lpvmerr() isn't called because of an accepted
 * 		error code.
 * 	- modified old 3.3 interface to create persistent mboxes...
 * 	- gutted pvm_lookup() to snag the returned index for -1/firstavail
 * 		queries, as pvm_recvinfo() doesn't ever return the index value.
 * 		D-Oh...  Too late to fix it now...
 * (Spanker=kohl)
 *
 * Revision 1.79  1999/01/13  00:04:46  pvmsrc
 * Filled in backwards compat guts:
 * 	- to pvm_insert(), pvm_lookup() & pvm_delete().
 * 	- use mbox stuff, no more #ifdef PVM33COMPAT...
 * 	- modified mbox pvm_putinfo() stuff to pass in -1 instead of 0
 * 		for the internal index value...
 * (Spanker=kohl)
 *
 * Revision 1.78  1998/11/20  20:04:04  pvmsrc
 * Changes so that win32 will compile & build. Also, common
 * Changes so that compiles & builds on NT. Also
 * common source on win32 & unix.
 * (Spanker=sscott)
 *
 * Revision 1.77  1998/10/12  21:16:28  pvmsrc
 * Damn.  Typo - should be pvmsbuf->m_mid, not pvmsbuf...  D-Oh!
 * (Spanker=kohl)
 *
 * Revision 1.76  1998/10/12  21:08:57  pvmsrc
 * Fixed pvmtrcsbfsave fiasco in pvm_send/mcast().
 * 	- as used for message number of bytes trace data.
 * 	- if not using PvmTraceFull tracing option, pvmtrcsbfsave will not
 * 		be set / swapped with pvmsbuf...
 * 	- check for non-NULL pvmtrcsbfsave, if not use pvmsbuf instead.
 * (Spanker=kohl)
 *
 * Revision 1.75  1998/10/02  15:44:01  pvmsrc
 * Single source code merge of Win32 and Unix code.
 * (Spanker=sscott)
 *
 * Revision 1.74  1998/09/02  14:07:05  pvmsrc
 * Fixed bug in pvm_siblings().
 * 	- incorrect handling of PvmParentNotSet case...
 * (Spanker=kohl)
 *
 * Revision 1.73  1998/08/27  15:16:53  pvmsrc
 * Plugged memory leak in pvm_recvinfo().
 * 	- pvmrbuf is freed O.K., but the wrapper message from the pvmd
 * 		(the one with the mbox message in it :-) was not being freed.
 * (Spanker=kohl)
 *
 * Revision 1.72  1998/06/26  15:26:28  pvmsrc
 * Fixed pvm_trecv():
 * 	- if timeout is 0, could return without ever probing...
 * 	- make sure mroute() is called at least once before timing
 * 		out in the 0 case.
 * (Spanker=kohl)
 *
 * Revision 1.71  1998/02/23  22:51:33  pvmsrc
 * Added AIX4SP2 stuff.
 * (Spanker=kohl)
 *
 * Revision 1.70  1998/01/28  20:08:56  pvmsrc
 * Added new -DSYSERRISCONST define.
 * 	- for const char *sys_errlist...
 * (Spanker=kohl)
 *
 * Revision 1.69  1998/01/28  19:13:52  pvmsrc
 * Added new IMA_LINUXHPPA to #if cases...
 * (Spanker=kohl)
 *
 * Revision 1.68  1997/12/31  22:14:25  pvmsrc
 * Renamed TEV_REMOVE -> TEV_DELINFO.  D-Oh.
 * (Spanker=kohl)
 *
 * Revision 1.67  1997/12/31  20:51:29  pvmsrc
 * Added saving / resetting of current send / recv buffer around mhf.
 * 	- so each message handler doesn't have to do it.
 * 	- while we're at it, might as well set rbuf to mhf message, too.
 * Removed TEV_DID_MRF trace event element for pvm_addmhf() entry event.
 * 	- seemed like a good idea at the time, but no way to avoid the
 * 		compiler warnings on SGIs when trying to cast funct ptr to
 * 		int ptr for packing into trace message...  :-Q
 * (Spanker=kohl)
 *
 * Revision 1.66  1997/12/29  19:41:21  pvmsrc
 * 	Changed char *em to const char *em.
 * 	For Redhat 4.2/5.0 compatibility under LINUX.
 * (Spanker=phil)
 *
 * Revision 1.65  1997/12/23  20:23:53  pvmsrc
 * Added new TEV_MHF_INVOKE trace event.
 * 	- include message handler src/tag/ctx settings.
 * 	- include actual message bufid, len, and src/tag/ctx.
 * 	- use new TEV_PUSHTOP, TEV_AMPUSHED and TEV_POPTOP macros to
 * 		fake top level tracing for PVM calls in message handler.
 * (Spanker=kohl)
 *
 * Revision 1.64  1997/12/17  22:16:51  pvmsrc
 * Added tracing instrumentation to pvm_addmhf() and pvm_delmhf().
 * 	- rewrote as necessary to capture return code.
 * (Spanker=kohl)
 *
 * Revision 1.63  1997/11/04  23:20:39  pvmsrc
 * Added IMA_LINUXALPHA to const char * error log stuff.
 * (Spanker=kohl)
 *
 * Revision 1.62  1997/10/24  15:17:52  pvmsrc
 * Added TEV_DID_RCX to trace events for Receive Message Context.
 * 	- in pvm_recv(), pvm_trecv(), pvm_nrecv(), and pvm_precv().
 * (Spanker=kohl)
 *
 * Revision 1.61  1997/10/24  14:29:27  pvmsrc
 * Added TEV_DID_MCX / pvmmyctx trace event info to:
 * 	- pvm_send(), pvm_mcast(), pvm_recv(), pvm_trecv(), pvm_nrecv().
 * 	- pvm_psend(), pvm_precv().
 * (Spanker=kohl)
 *
 * Revision 1.60  1997/09/22  21:13:30  pvmsrc
 * Added new pvmsettaskname() linkage (for shell-spawned tasks only!).
 * 	- call pvmsettaskname() before joining PVM, sends task name
 * 		(stored in new char *pvmmytaskname global) to pvmd in
 * 		TM_CONN2 message.
 * 	- appears in trace events and console ps.
 * (Spanker=kohl)
 *
 * Revision 1.59  1997/09/10  21:36:12  pvmsrc
 * changing socket startup to pvmbeatask --> pvm_parent did not
 * enroll correctly. Markus
 * (Spanker=fischer)
 *
 * Revision 1.58  1997/08/29  13:35:10  pvmsrc
 * OS2 Port Submitted by Bohumir Horeni, horeni@login.cz.
 * (Spanker=kohl)
 *
 * Revision 1.57  1997/08/27  20:19:44  pvmsrc
 * Fixed bug in tracing - message number of bytes for pvm_send/mcast().
 * 	- "pvmsbuf" is really "pvmtrcbuf" inside tracing scope...  D-Oh!
 * 	- use saved "pvmtrcsbfsave" buffer id for pvm_bufinfo() instead.
 * (Spanker=kohl)
 *
 * Revision 1.56  1997/08/25  21:46:21  pvmsrc
 * Fixed call to enc_trc_fin() in pvm_send().
 * 	- for user-defined trace events, pvmsbuf arg was missing...
 * (Spanker=kohl)
 *
 * Revision 1.55  1997/08/06  22:43:16  pvmsrc
 * Added new SGI6 and SGIMP6 arches.
 *
 * Revision 1.54  1997/07/21  19:08:31  pvmsrc
 * Well slap SScott around the next time you see him.  :-)
 * 	- fixed pvm_delmhf() to handle boundary case where deleted
 * 		entry is at end of list (can't copy last entry to the
 * 		deleted slot if you're already there... :-).
 * 	- fixed up mesg_input() to check for wildcarded handler tag
 * 		like everything else...
 *
 * Revision 1.53  1997/07/08  15:29:53  pvmsrc
 * 	Don't let routing option be changed on PGON and SP2MPI.
 *
 * Revision 1.52  1997/06/27  21:02:29  pvmsrc
 * removed working debug statments from pvm_delmhf()
 *
 * Revision 1.51  1997/06/27  18:04:58  pvmsrc
 * Integrated WIN32 changes.
 *
 * Revision 1.50  1997/06/26  19:38:05  pvmsrc
 * pvm_siblings now waits for siblings to come from spawning parent
 * 	even when PvmNoParent is set.
 *
 * Also, if a task is run from the command line, pvm_siblings returns
 * 	a sibling set of size 1 and with tid = pvmmytid
 *
 * Revision 1.49  1997/06/26  15:03:03  pvmsrc
 * Awwwwwww Crap.  Beat me with a shovel.  F---ing Typo.
 *
 * Revision 1.48  1997/06/26  14:56:48  pvmsrc
 * Forget something Steve?  D-Oh, D-Oh, D-Oh...
 * 	- how about setting the handles[].f field when you create a
 * 		message handler -- it comes in handy when you actually
 * 		want to HANDLE a message...  :-/~
 *
 * Revision 1.47  1997/06/26  13:41:34  pvmsrc
 * Added default return value to pvm_delmhf().
 * 	- SGI compiler warning (and incorrect (missing) return case,
 * 		PvmOk).
 * 	- text formatting...  (broke up SScott's 200 character long lines :)
 *
 * Revision 1.46  1997/06/25  18:02:58  pvmsrc
 * pvm_addmhf() complete rewrite
 * pvm_delmhf() complete rewrite
 * pvm_exit() reversed removal sequence of message handlers.
 * pvmdisplaymhfinfo() new internal function for testing message handlers
 *
 * Revision 1.45  1997/06/23  18:36:04  pvmsrc
 * Oops...  pvm_reg_rm() should add itself to PVMRMCLASS.
 * 	- not PVMTASKERCLASS...  typo...  D-Oh...
 *
 * Revision 1.44  1997/06/12  20:10:41  pvmsrc
 * Made sure all communications for TC_* task control messages
 * 	use the SYSCTX_TC system context.
 * 	- some messages being sent in default context...  D-Oh...
 *
 * Revision 1.43  1997/05/21  16:01:47  pvmsrc
 * Updated ifdefs to include AIX4MP arch type.
 *
 * Revision 1.42  1997/05/07  21:22:09  pvmsrc
 * AAAIIIEEEEEEEEE!!!!
 * 	- removed all static-limited string unpacking:
 * 		* replaced with use of:
 * 			upkstralloc() / PVM_FREE() (for pvmd stuff).
 * 			new pvmupkstralloc() / PVM_FREE() (for lpvm stuff).
 * 		* manual allocation of local buffers for sprintf() & packing.
 * 		* alternate static string arrays to replace fixed-length cases.
 * 		* I hope this shit works...  :-Q
 *
 * Revision 1.41  1997/05/02  19:48:06  pvmsrc
 * 	Fix precv on SP2MPI -- needed to be added to an ifdef.
 *
 * Revision 1.40  1997/05/02  14:54:16  pvmsrc
 * Implemented guts of pvm_getmboxinfo():
 * 	- user library side sends pattern & receives back / allocs array.
 * 	- at pvmd side mb_names() searches class list for matching pattern,
 * 		count up # of entries, and pack up struct info.
 * 		(Note:  does not yet use GNU regex stuff...)
 *
 * Revision 1.39  1997/05/02  13:44:32  pvmsrc
 * 	Support for SP2MPI. Comment references to mpierrcode.
 *
 * Revision 1.38  1997/05/01  20:17:39  pvmsrc
 * Renamed TEV_MBOXINFO -> TEV_GETMBOXINFO.
 *
 * Revision 1.37  1997/04/30  21:26:02  pvmsrc
 * SGI Compiler Warning Cleanup.
 *
 * Revision 1.36  1997/04/24  21:05:54  pvmsrc
 * Short circuiting on pvm_precv for mpps
 *
 * Revision 1.35  1997/04/21  14:46:28  pvmsrc
 * pvm_addmhf() ifdefs for SCO
 *
 * Revision 1.34  1997/04/17  12:54:25  pvmsrc
 * rename of pvm_mboxinfo() to include word "get"
 *
 * Revision 1.33  1997/04/14  14:28:42  pvmsrc
 * pvm_exit() now removes all message handlers
 *
 * Revision 1.32  1997/04/10  20:32:46  pvmsrc
 * Typo...
 *
 * Revision 1.31  1997/04/10  20:14:20  pvmsrc
 * (Partially) replaced pvm_getnames() with new pvm_mboxinfo().
 * 	- needs actual implementation details...  ha ha ha...
 *
 * Revision 1.30  1997/04/09  20:10:52  pvmsrc
 * Memory spank - freeing static mem...  D-Oh...
 *
 * Revision 1.29  1997/04/09  19:37:58  pvmsrc
 * Added class name and index args to pvmreset() routine:
 * 	- allow systematic elimination of leftover persistents...
 * 	- heh, heh, heh...
 * In dm_db(), check for name (class) and req (index) match
 * 	for TMDB_RESET case (""/-1 for all, resp).
 *
 * Revision 1.28  1997/04/09  18:31:13  pvmsrc
 * Added "killtasks" arg tp pvmreset():
 * 	- allow for only resetting of mboxes, w/o task kill...
 * 	- otherwise, too painful to clean up mbox db...
 *
 * Revision 1.27  1997/04/08  17:23:31  pvmsrc
 * Damn, Damn, Damn...
 * 	- pvmreset() must be in library side only, pvmds use different
 * 		message buffer mgt, packing and sending routines...  :-Q
 *
 * Revision 1.26  1997/04/07  21:07:57  pvmsrc
 * pvm_addmhf() - new paramter interface
 *
 * pvm_addmhf() and pvm_delmhf() now maintain a "free-list" from which
 * new entries are first filled before allocating new space.
 *
 * Revision 1.25  1997/04/07  19:55:26  pvmsrc
 * Nope, changed my mind.  pvm_getnoresets() saves tidlist in static,
 * 	reuse allocated mem on next call, a la pcm_tasks()...
 *
 * Revision 1.24  1997/04/07  19:39:58  pvmsrc
 * Plugged memory leak in pvm_getnoresets().
 * 	- if no return tids ptr provided, just free tidlist array.
 *
 * Revision 1.23  1997/04/04  15:44:35  pvmsrc
 * New pvm_addmhf() and pvm_delmhf()
 *
 * Revision 1.22  1997/04/03  19:25:02  pvmsrc
 * Added context for TM_xxx messages SM_xxx messages use the
 * PvmBaseContext for compatibility
 *
 * Revision 1.21  1997/04/01  21:28:14  pvmsrc
 * Damn Damn Damn.
 * 	- pvm_recvinfo() returns a bufid, not an index.  Damn.
 *
 * Revision 1.20  1997/03/31  21:39:08  pvmsrc
 * *** Changed syntax of mbox routines.
 * 	- pvm_putinfo() dropped index arg, changed flags semantics.
 * 	- pvm_getinfo() -> pvm_recvinfo(), a la pvm_recv()...
 * 	- added PvmMboxDefault for flags usage.
 * 	- changed routines & calls.
 * 	- extension of sscott submission...
 *
 * Revision 1.19  1997/03/27  19:56:15  pvmsrc
 * In pvm_reg_tracer():
 * 	- added packing of other assundry trace settings in tracer mailbox.
 * 	- for shell-spawned tasks to get tmask, topt, etc...
 *
 * Revision 1.18  1997/03/06  21:07:38  pvmsrc
 * 		- added include to pvmmimd.h
 * 		- test properly on mpps when trying to set pvmfrgsize
 *
 * Revision 1.17  1997/03/04  22:47:25  pvmsrc
 * Added stuffing of message mailboxes for:
 * 	- Resource Managers, Hosters, Taskers and Tracers.
 * 	- done by registered task, for auto-cleanup on exit.
 * 	- delete info on unregister...
 *
 * Revision 1.16  1997/02/17  20:50:58  pvmsrc
 * D-Oh! D-Oh! D-Oh!  A stupid Jim typo:
 * 	* PvmFirstAvail & PvmLock  ->  PvmFirstAvail | PvmLock.
 * 	* D-Oh!
 *
 * Revision 1.15  1997/02/17  19:43:41  pvmsrc
 * Added check in pvm_setopt() / PvmNoReset for pvmmytid > 0.
 *
 * Revision 1.14  1997/02/17  18:47:26  pvmsrc
 * Oops...  must pass ptr to tids array for pvm_getnoresets().
 *
 * Revision 1.13  1997/02/17  16:29:44  pvmsrc
 * Added new pvm_getnoresets() routine.
 *
 * Revision 1.12  1997/02/13  23:35:44  pvmsrc
 * Added new PvmNoReset setopt/getopt option.
 * 	- added new pvmnoreset, pvmnoresetindex globals in lpvm.[ch].
 * 	- to set use pvm_putinfo() -> PVMNORESETCLASS first avail w/lock,
 * 		save index in pvmnoresetindex.
 * 	- to unset use pvm_delinfo().
 *
 * Revision 1.11  1997/02/13  15:10:43  pvmsrc
 * Fixed Bob Bug in pvm_exit():
 * 	- "=" -> "=="...  Ooooo...
 *
 * Revision 1.10  1997/01/28  19:26:26  pvmsrc
 * New Copyright Notice & Authors.
 *
 * Revision 1.9  1996/12/19  19:59:15  pvmsrc
 * Fixed pvm log messages for pvm_tc_*() routines.
 * 	- stuff no longer in pvmmctl()...
 *
 * Revision 1.8  1996/12/19  15:06:45  pvmsrc
 * Added missing decls for error globals (#ifndef HASERRORVARS).
 * 	- errno, sys_errlist[] & sys_nerr.
 *
 * Revision 1.7  1996/12/18  22:27:46  pvmsrc
 * Extracted duplicate versions of routines from lpvm/mimd/shmem.c,
 * 	inserted into shared lpvmgen.c:
 * 	- pvmbailout().
 * 	- pvmlogerror().
 * 	- vpvmlogprintf(), pvmlogprintf().  (hope these work on MPP & shmem)
 * 	- pvmlogperror().
 *
 * Revision 1.6  1996/10/31  20:44:20  pvmsrc
 * Added a static char version variable in pvm_version() to avoid
 * stack corruption.
 *
 * Revision 1.5  1996/10/25  13:57:24  pvmsrc
 * Replaced old #includes for protocol headers:
 * 	- <pvmsdpro.h>, "ddpro.h", "tdpro.h"
 * With #include of new combined header:
 * 	- <pvmproto.h>
 *
 * Revision 1.4  1996/10/24  22:26:55  pvmsrc
 * Moved #include "global.h" below other #include's for typing.
 * Added #include of new "lpvm.h" header to replace explicit externs.
 * Extracted common message handler routines from lpvm*.c:
 * 	- pvm_tc_noop(), pvm_tc_settrace(), pvm_tc_settrcbuf(),
 * 		pvm_tc_settrcopt(), pvm_tc_settmask(), and pvm_tc_siblings().
 * Extracted PVM option routines from lpvm*.c:
 * 	- pvm_getopt() & pvm_setopt().
 * 	- merged special mimd / shmem cases into generic routine.
 * 	- added new tracing options PvmTraceBuffer, PvmTraceOptions,
 * 		PvmSelfTraceBuffer & PvmSelfTraceOptions.
 * Modified trace event generation for message / packing routines:
 * 	- replaced old TEV_*[01] constants with new TEV_EVENT_ENTRY/EXIT.
 * 	- replaced standard pvm_pk*() calls with new TEV_PACK_*() macro
 * 		calls and TEV_DID_* identification.
 * 	- in pvm_send(), check for user-defined message destination
 * 		and handle proper finishing and sending of user-defined
 * 		trace event.
 * 	- in pvm_spawn(), use new Pvmtracer structure info in place of
 * 		old globals, pass along new PVMTRCBUF & PVMTRCOPT env vars.
 * Added new pvm_reg_tracer() routine for registering a task as a tracer.
 *
 * Revision 1.3  1996/10/11  17:03:10  pvmsrc
 * Replaced references to pvm_remove() with pvm_delinfo():  renamed.
 *
 * Revision 1.2  1996/10/08  18:32:21  pvmsrc
 * Renamed routines:
 * 	- pvm_put() -> pvm_putinfo().
 * 	- pvm_get() -> pvm_getinfo().
 *
 * Revision 1.1  1996/09/23  23:44:14  pvmsrc
 * Initial revision
 *
 * Revision 1.10  1995/11/02  16:09:32  manchek
 * added NEEDSENDIAN switch.
 * pass environment through spawn on PGON
 *
 * Revision 1.9  1995/07/28  16:04:05  manchek
 * switch endian includes on flag, not arch name
 *
 * Revision 1.8  1995/06/12  15:46:46  manchek
 * pvm_recvf now returns pointer to default matcher instead of 0
 *
 * Revision 1.7  1995/02/01  21:10:33  manchek
 * pvm_hostsync didn't free its message buffers
 *
 * Revision 1.6  1994/11/07  21:36:33  manchek
 * flush messages on pvm_exit.
 * function prototype for SCO
 *
 * Revision 1.5  1994/10/15  19:12:35  manchek
 * check for system error in TM_SPAWN reply (cc != count)
 *
 * Revision 1.4  1994/06/03  20:38:16  manchek
 * version 3.3.0
 *
 * Revision 1.3  1993/11/30  15:52:42  manchek
 * implemented case autoerr == 2 in lpvmerr()
 *
 * Revision 1.2  1993/09/16  21:37:39  manchek
 * pvm_send() missing a return before lpvmerr()
 *
 * Revision 1.1  1993/08/30  23:26:48  manchek
 * Initial revision
 *
 */


#include <stdio.h>
#ifdef NEEDMENDIAN
#include <sys/types.h>
#include <machine/endian.h>
#endif
#ifdef NEEDENDIAN
#include <endian.h>
#endif
#ifdef NEEDSENDIAN
#include <sys/endian.h>
#endif

#include <pvm3.h>

#if defined(WIN32) || defined(CYGWIN)
#include "..\xdr\types.h"
#include "..\xdr\xdr.h"
#else
#include <rpc/types.h>
#include <rpc/xdr.h>
#endif

#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 <errno.h>
#include <signal.h>

#ifdef	__STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#include <pvmproto.h>
#include "pvmalloc.h"
#include "pmsg.h"
#include "listmac.h"
#include "bfunc.h"
#include "tvdefs.h"
#include "lpvm.h"
#include <pvmtev.h>
#include "tevmac.h"
#include "host.h"
#include "waitc.h"
#include "global.h"

#if defined(IMA_PGON) || defined(IMA_SP2MPI) || defined(IMA_AIX4SP2) \
	|| defined(IMA_AIX5SP2) || defined(IMA_BEOLIN)
#include "pvmmimd.h"
#include "lmsg.h"
extern struct msgid *pvm_inprecv;
#endif

#ifndef HASERRORVARS
extern int errno;						/* from libc */
#ifndef USESTRERROR
extern char *sys_errlist[];
extern int sys_nerr;
#endif
#endif

#ifdef WIN32
#ifndef SOCK_DEFINES
extern WSADATA WSAData;
int nAlert=SO_SYNCHRONOUS_NONALERT;
#define SOCK_DEFINES
#endif
#endif

struct mhandler {
	int mhid;					/* unique message handler id */
	struct pvmminfo header;		/* source, tag, context */
	int (*f)();					/* handler function */
};

struct dhandler {
	int mhid;		/* message handler id - used for free list links */
	int handle;		/* index of associated handles[] entry */
};


/***************
 **  Globals  **
 **           **
 ***************/

char *getenv();

struct pmsg *midtobuf();


/***************
 **  Private  **
 **           **
 ***************/

static int def_match();
static int (*recv_match)() = def_match;

/* handles[] contains structures with message handler info */
static struct mhandler *handles = 0;

/* element count for handles[] array - all of these are active */
static int nhandles = 0;

/* pointer to the dhandles[] array */
static struct dhandler *dhandles = 0;

/* element count for dhandles[] array - not all active though */
static int ndhandles = 0;

/* free list dhandles; -1 indicates empty list */
static int fl_dhandles = -1;


/**************************
 **  Internal Functions  **
 **                      **
 **************************/


/*
*	Function: pvmdisplaymhfinfo
*
*  function displays message handler data structure information
*
*/
void
pvmdisplaymhfinfo(who, msg, tid)
	char *who;			/* who made this call */
	char *msg;			/* message from caller */
	int tid;			/* tid of caller */
{	char *me = "pvmdisplaymhfinfo";
	int i;
	int head;

	printf("\n%s t%x: Display Message Handler Information: ",
		who, tid );
	printf("ndhandles = %d\tnhandles = %d\tfl_dhandles = %d", 
		ndhandles, nhandles, fl_dhandles);

	printf("\n%s: free list.  head <-", me);
	head = fl_dhandles;
	while (head != -1){
		printf(" %d", head);
		head = dhandles[head].mhid;
	}
	printf(" -< tail");

	printf("\n%s t%x: %s\n", who, tid, msg);
	for (i = 0; i < ndhandles; i++ ) {
		printf("%s t%x: dhandles[%2d].mhid = %2d  .handle = %2d     ",
			who, tid, i, dhandles[i].mhid, dhandles[i].handle);
		printf("handles[%2d].mhid = %2d  .header.src = t%-8x  ",
			i, handles[i].mhid, handles[i].header.src);
		printf(".header.ctx = %8d  .header.tag= %8d\n",
			handles[i].header.ctx, handles[i].header.tag);
	}
	printf("\n\n"); fflush(stdout);
} /* pvmdisplaymhfinfo */


static int
def_match(mid, tid, tag)
	int mid;
	int tid;
	int tag;
{
	struct pmsg *up;

	if (!(up = midtobuf(mid)))
		return PvmNoSuchBuf;
	return ((tid == -1 || tid == up->m_src)
			&& (tag == -1 || tag == up->m_tag)
			&& (pvmmyctx == -1 || pvmmyctx == up->m_ctx)) ? 1 : 0;
}


/*	pvmbailout()
*
*	Called by low-level stuff in f.e. pvmfrag.c.  Don't really want to
*	bail in libpvm.
*/

void
pvmbailout(n)
	int n;
{
	n = n;	/* ayn rand was here */
}


/*	pvmlogerror()
*
*	Log a libpvm error message.  Prepends a string identifying the task.
*/

int
pvmlogerror(s)
	char *s;
{
	if (pvmmytid == -1)
		fprintf(stderr, "libpvm [pid%d]: %s", pvmmyupid, s);
#ifdef LOG
	else if (logfp)
	{
		fprintf(logfp, "libpvm [t%x]: %s", pvmmytid, s);
		fflush(logfp);
	}
#endif
	else
		fprintf(stderr, "libpvm [t%x]: %s", pvmmytid, s);
	return 0;
}


int
vpvmlogprintf(fmt, ap)
	char *fmt;
	va_list ap;
{
	static int newline = 1;
	int cc;

	if (newline) {
		if (pvmmytid == -1)
			fprintf(stderr, "libpvm [pid%d] ", pvmmyupid);
		else
			fprintf(stderr, "libpvm [t%x] ", pvmmytid);
	}
	cc = vfprintf(stderr, fmt, ap);
	newline = (fmt[strlen(fmt) - 1] == '\n') ? 1 : 0;
	fflush(stderr);
	return(cc);
}


/*	pvmlogprintf()
*
*	Log a libpvm error message.  Prepends the task id.  Takes
*	printf-like args.
*/

int
#ifdef __STDC__
pvmlogprintf(const char *fmt, ...)
#else
pvmlogprintf(va_alist)
	va_dcl
#endif
{
	va_list ap;
	int cc;

#ifdef __STDC__
	va_start(ap, fmt);
#else
	char    *fmt;

	va_start(ap);
	fmt = va_arg(ap, char *);
#endif

	cc = vpvmlogprintf(fmt, ap);
	va_end(ap);

	return cc;
}


/*	pvmlogperror()
*
*	Log a libpvm error message.  Prepends a string identifying the
*	task and appends the system error string for _errno.
*/

int
pvmlogperror(s)
	char *s;
{
#ifdef SYSERRISCONST
	const char *em;
#else
	char *em;
#endif

#if defined(IMA_SP2MPI) || defined(IMA_AIX4SP2) || defined(IMA_AIX5SP2)
	int l;

	/* if (mpierrcode) {
		MPI_Error_string(mpierrcode, pvmtxt, &l);
		em = pvmtxt;
	} else */
#ifdef USESTRERROR
		em = strerror( errno );
#else
		em = ((errno >= 0 && errno < sys_nerr)
			? sys_errlist[errno] : "Unknown Error");
#endif
#else

#ifdef IMA_CM5
	errno = CMMD_get_errno();
#endif

#ifdef USESTRERROR
	em = (char *) strerror( errno );
#else
	em = ((errno >= 0 && errno < sys_nerr)
		? sys_errlist[errno] : "Unknown Error");
#endif

#endif /*IMA_SP2MPI*/

	pvmlogprintf("%s: %s\n", s, em);

	return 0;
}


/*	lpvmerr()
*
*	Error has occurred in libpvm function.
*	Action determined by pvmautoerr (set by setopt):
*		0	Do nothing
*		1	Print error message
*		2	Print error message, exit program with error code
*		3	Print error message, abort program
*/

int
lpvmerr(f, n)
	char *f;		/* error location */
	int n;			/* error code */
{
	char buf[128];

	pvm_errno = n;
	if (pvmautoerr) {
		buf[0] = 0;
		strncat(buf, f, sizeof(buf)-4);
		strcat(buf, "()");
		pvm_perror(buf);
		fflush(stderr);
		if (pvmautoerr == 3)
			abort();
		if (pvmautoerr == 2) {
			pvmautoerr = 1;
			pvm_exit();
			exit(n);
		}
	}
	return n;
}


/*	mesg_input()
*
*	Receive message into task.  All received messages go through this function.
*	If a handler was specified for this tag, call it.
*	Otherwise, put the message on rxlist.
*/

int
mesg_input(up)
	struct pmsg *up;
{
	int savesbuf;
	int saverbuf;
	int savectx;
	int i;
	TEV_DECLS

	if (pvmdebmask & PDMMESSAGE)
		pvmlogprintf("mesg_input() src t%x ctx %d tag %s len %d\n",
				up->m_src, up->m_ctx,
				pvmnametag(up->m_tag, (int *)0), up->m_len);
	for (i = nhandles; i-- > 0; ) {
		if ( (handles[i].header.tag == -1
				|| handles[i].header.tag == up->m_tag)
			&& (handles[i].header.ctx == -1
				|| handles[i].header.ctx == up->m_ctx)
			&& (handles[i].header.src == -1
				|| handles[i].header.src == up->m_src) )
		{
			if (TEV_DO_TRACE(TEV_MHF_INVOKE,TEV_EVENT_ENTRY)) {

				TEV_PACK_INT( TEV_DID_RST, TEV_DATA_SCALAR,
						&(handles[i].header.src), 1, 1 );
				TEV_PACK_INT( TEV_DID_RMC, TEV_DATA_SCALAR,
						&(handles[i].header.tag), 1, 1 );
				TEV_PACK_INT( TEV_DID_RCX, TEV_DATA_SCALAR,
						&(handles[i].header.ctx), 1, 1 );

				TEV_PACK_INT( TEV_DID_MB, TEV_DATA_SCALAR,
						&(up->m_mid), 1, 1 );
				TEV_PACK_INT( TEV_DID_MNB, TEV_DATA_SCALAR,
						&(up->m_len), 1, 1 );
				TEV_PACK_INT( TEV_DID_MC, TEV_DATA_SCALAR,
						&(up->m_tag), 1, 1 );
				TEV_PACK_INT( TEV_DID_MCX, TEV_DATA_SCALAR,
						&(up->m_ctx), 1, 1 );
				TEV_PACK_INT( TEV_DID_SRC, TEV_DATA_SCALAR,
						&(up->m_src), 1, 1 );

				TEV_FIN;

				TEV_PUSHTOP;
			}

			savesbuf = pvm_setsbuf( 0 );
			saverbuf = pvm_setrbuf( up->m_mid );
			savectx = pvm_setcontext( up->m_ctx );

			(handles[i].f)(up->m_mid);

			pvm_setcontext( savectx );
			pvm_freebuf( pvm_setsbuf( savesbuf ) );
			pvm_freebuf( pvm_setrbuf( saverbuf ) );

			if ( TEV_AMPUSHED )
				TEV_POPTOP;

			return 0;
		}
	}
	LISTPUTBEFORE(pvmrxlist, up, m_link, m_rlink);
	return 0;
}


/************************
 **  Message Handlers  **
 **                    **
 ************************/

/*	pvm_tc_noop()
*
*	Process a NO-OP message.  Har.
*/

int
pvm_tc_noop(mid)
	int mid;
{
	int src;

	pvm_bufinfo(mid, (int *)0, (int *)0, &src);

	if (pvmdebmask) {
		pvmlogprintf("pvm_tc_noop() NOOP from t%x\n", src);
	}
	pvm_freebuf(mid);
	return 0;
}


/*	pvm_tc_settrace()
*
*	Set our tracing on the fly
*
*	TC_SETTRACE() {
*		int trctid			// task id for tracing
*		int trcctx			// message context for trace messages
*		int trctag			// message tag for trace messages
*		int outtid			// task id for stdout output
*		int outctx			// message context for output messages
*		int outtag			// message tag for output messages
*		string mask			// new trace mask
*		int tbuf			// trace buffer size
*		int topt			// trace options
*	}
*/

int
pvm_tc_settrace(mid)
	int mid;
{
	int trctid;
	int trcctx;
	int trctag;
	int outtid;
	int outctx;
	int outtag;
	char buf[256];
	int tbuf;
	int topt;

	pvm_upkint(&trctid, 1, 1);
	pvm_upkint(&trcctx, 1, 1);
	pvm_upkint(&trctag, 1, 1);
	pvm_upkint(&outtid, 1, 1);
	pvm_upkint(&outctx, 1, 1);
	pvm_upkint(&outtag, 1, 1);
	pvm_upkstr(buf);
	pvm_upkint(&tbuf, 1, 1);
	pvm_upkint(&topt, 1, 1);

	if (trctid) {
		/* cheat on trcctx & trctag to avoid race */
		pvmtrc.trcctx = trcctx;
		pvmtrc.trctag = trctag;
		pvm_setopt( PvmSelfTraceTid, trctid );
		if (strlen(buf) + 1 == TEV_MASK_LENGTH)
			BCOPY(buf, pvmtrc.tmask, TEV_MASK_LENGTH);
		else {
			TEV_MASK_INIT(pvmtrc.tmask);
			pvmlogerror("pvm_tc_settrace() bogus trace mask\n");
		}
		BCOPY(pvmtrc.tmask, pvmctrc.tmask, TEV_MASK_LENGTH);
		if (tbuf >= 0)
			pvmtrc.trcbuf = tbuf;
		else {
			pvmtrc.trcbuf = 0;
			pvmlogerror("pvm_tc_settrace() bogus trace buffering\n");
		}
		if (topt >= 0)
			pvmtrc.trcopt = topt;
		else {
			pvmtrc.trcopt = 0;
			pvmlogerror("pvm_tc_settrace() bogus trace options\n");
		}
	}

	if (outtid) {
		/* cheat on outctx & outtag to avoid race */
		pvmtrc.outctx = outctx;
		pvmtrc.outtag = outtag;
		pvm_setopt( PvmSelfOutputTid, outtid );
	}

	pvm_freebuf(mid);
	return 0;
}


/*	pvm_tc_settrcbuf()
*
*	Set our trace buffering on the fly
*
*	TC_SETTRCBUF() {
*		int buf				// new trace buffer size
*	}
*/

int
pvm_tc_settrcbuf(mid)
	int mid;
{
	int tbuf;

	pvm_upkint(&tbuf,1,1);

	if (tbuf >= 0)
		pvmtrc.trcbuf = tbuf;
	else {
		pvmtrc.trcbuf = 0;
		pvmlogerror("pvm_tc_settrcbuf() bogus trace buffering\n");
	}

	pvm_freebuf(mid);
	return 0;
}


/*	pvm_tc_settrcopt()
*
*	Set our trace options on the fly
*
*	TC_SETTRCOPT() {
*		int opt				// new trace options
*	}
*/

int
pvm_tc_settrcopt(mid)
	int mid;
{
	int topt;

	pvm_upkint(&topt,1,1);

	if (topt >= 0)
		pvmtrc.trcopt = topt;
	else {
		pvmtrc.trcopt = 0;
		pvmlogerror("pvm_tc_settrcopt() bogus trace options\n");
	}

	pvm_freebuf(mid);
	return 0;
}


/*	pvm_tc_settmask()
*
*	Set our trace mask on the fly
*
*	TC_SETTMASK() {
*		string mask				// new trace mask
*	}
*/

int
pvm_tc_settmask(mid)
	int mid;
{
	char buf[256];

	pvm_upkstr(buf);
	if (strlen(buf) + 1 == TEV_MASK_LENGTH)
		BCOPY(buf, pvmtrc.tmask, TEV_MASK_LENGTH);
	else
		pvmlogerror("pvm_tc_settmask() bogus trace mask\n");

	pvm_freebuf(mid);
	return 0;
}


/*	pvm_tc_siblings()
*
*	Parent task announces our spawn group.
*
*	TC_SIBLINGS() {
*		int length
*		int tids[length]		// sibling tids
*	}
*/

int
pvm_tc_siblings(mid)
	int mid;
{
	pvm_upkint(&pvmnsibs, 1, 1);
	if (pvmnsibs > 0) {
		pvmsibtids = TALLOC(pvmnsibs, int, "sibs");
		pvm_upkint(pvmsibtids, pvmnsibs, 1);
	}
	pvm_freebuf(mid);
	return 0;
}


/************************
 **  Libpvm Functions  **
 **                    **
 ************************/

int
pvm_getopt(what)
	int what;
{
	int rc = 0;
	int err = 0;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (pvmmytid != -1
				&& TEV_DO_TRACE(TEV_GETOPT,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_OPT, TEV_DATA_SCALAR, &what, 1, 1 );
			TEV_FIN;
		}
	}

	switch (what) {
	case PvmRoute:
		rc = pvmrouteopt;
		break;

	case PvmDebugMask:
		rc = pvmdebmask;
		break;

	case PvmAutoErr:
		rc = pvmautoerr;
		break;

	case PvmOutputTid:
		rc = pvmctrc.outtid;
		break;

	case PvmOutputContext:
		rc = pvmctrc.outctx;
		break;

	case PvmOutputCode:
		rc = pvmctrc.outtag;
		break;

	case PvmTraceTid:
		rc = pvmctrc.trctid;
		break;

	case PvmTraceContext:
		rc = pvmctrc.trcctx;
		break;

	case PvmTraceCode:
		rc = pvmctrc.trctag;
		break;

	case PvmTraceBuffer:
		rc = pvmctrc.trcbuf;
		break;

	case PvmTraceOptions:
		rc = pvmctrc.trcopt;
		break;

	case PvmFragSize:
		rc = pvmfrgsiz;
		break;

	case PvmResvTids:
		rc = pvmrescode;
		break;

	case PvmSelfOutputTid:
		rc = pvmtrc.outtid;
		break;

	case PvmSelfOutputContext:
		rc = pvmtrc.outctx;
		break;

	case PvmSelfOutputCode:
		rc = pvmtrc.outtag;
		break;

	case PvmSelfTraceTid:
		rc = pvmtrc.trctid;
		break;

	case PvmSelfTraceContext:
		rc = pvmtrc.trcctx;
		break;

	case PvmSelfTraceCode:
		rc = pvmtrc.trctag;
		break;

	case PvmSelfTraceBuffer:
		rc = pvmtrc.trcbuf;
		break;

	case PvmSelfTraceOptions:
		rc = pvmtrc.trcopt;
		break;

	case PvmShowTids:
		rc = pvmshowtaskid;
		break;

	case PvmNoReset:
		rc = pvmnoreset;
		break;

#if defined(IMA_AIX4MP) || defined(IMA_AIX5MP) \
	|| defined(IMA_ALPHAMP) || defined(IMA_CSPP) \
	|| defined(IMA_HPPAMP) || defined(IMA_RS6KMP) \
	|| defined(IMA_SGIMP) || defined(IMA_SGIMP6) \
	|| defined(IMA_SGIMP64) || defined(IMA_SUNMP)

	case PvmPollTime:
		rc = pvmpolltime;
		break;
	
	case PvmPollType:
		rc = pvmpolltype;
		break;

#else /* SHMEM */

	case PvmPollTime:
	case PvmPollType:
		rc = PvmNotImpl;
		err = 1;
		break;

#endif /* SHMEM */

	default:
		err = 1;
		break;
	}

	if (TEV_AMEXCL) {
		if (pvmmytid != -1
				&& TEV_DO_TRACE(TEV_GETOPT,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_OPV, TEV_DATA_SCALAR, &rc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (err)
		return lpvmerr("pvm_getopt", PvmBadParam);
	return rc;
}


int
pvm_setopt(what, val)
	int what;
	int val;
{
	int rc = 0;
	int err = 0;
	int sbf, rbf;
	char buf[16];
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (pvmmytid != -1
				&& TEV_DO_TRACE(TEV_SETOPT,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_OPT, TEV_DATA_SCALAR, &what, 1, 1 );
			TEV_PACK_INT( TEV_DID_OPV, TEV_DATA_SCALAR, &val, 1, 1 );
			TEV_FIN;
		}
	}

	switch (what) {
	case PvmRoute:
		switch (val) {
		case PvmDontRoute:
		case PvmAllowDirect:
		case PvmRouteDirect:
			rc = pvmrouteopt;
#if (!defined(IMA_PGON)) && (!defined(IMA_SP2MPI)) \
		&& (!defined(IMA_AIX4SP2)) && (!defined(IMA_AIX5SP2))
			pvmrouteopt = val;
#endif
			break;

		default:
			rc = PvmBadParam;
			err = 1;
			break;
		}
		break;

	case PvmDebugMask:
		rc = pvmdebmask;
		pvmdebmask = val;
		break;

	case PvmAutoErr:
		rc = pvmautoerr;
		pvmautoerr = val;
		break;

	case PvmOutputTid:
		if (val && val != pvmmytid
		&& (val != pvmtrc.outtid || pvmctrc.outtag != pvmtrc.outtag)) {
			rc = PvmBadParam;
			err = 1;

		} else {
			rc = pvmctrc.outtid;
			pvmctrc.outtid = val;
		}
		break;

	case PvmOutputContext:
		if (pvmctrc.outtid > 0 && pvmctrc.outtid != pvmmytid
		&& val != pvmtrc.outctx) {
			rc = PvmBadParam;
			err = 1;

		} else {
			rc = pvmctrc.outctx;
			pvmctrc.outctx = val;
		}
		break;

	case PvmOutputCode:
		if (pvmctrc.outtid > 0 && pvmctrc.outtid != pvmmytid
		&& val != pvmtrc.outtag) {
			rc = PvmBadParam;
			err = 1;

		} else {
			rc = pvmctrc.outtag;
			pvmctrc.outtag = val;
		}
		break;

	case PvmTraceTid:
		if (val && val != pvmmytid
		&& (val != pvmtrc.trctid || pvmctrc.trctag != pvmtrc.trctag)) {
			rc = PvmBadParam;
			err = 1;

		} else {
			rc = pvmctrc.trctid;
			pvmctrc.trctid = val;
		}
		break;

	case PvmTraceContext:
		if (pvmctrc.trctid > 0 && pvmctrc.trctid != pvmmytid
		&& val != pvmtrc.trcctx) {
			rc = PvmBadParam;
			err = 1;

		} else {
			rc = pvmctrc.trcctx;
			pvmctrc.trcctx = val;
		}
		break;

	case PvmTraceCode:
		if (pvmctrc.trctid > 0 && pvmctrc.trctid != pvmmytid
		&& val != pvmtrc.trctag) {
			rc = PvmBadParam;
			err = 1;

		} else {
			rc = pvmctrc.trctag;
			pvmctrc.trctag = val;
		}
		break;

	case PvmTraceBuffer:
		rc = pvmctrc.trcbuf;
		pvmctrc.trcbuf = val;
		break;

	case PvmTraceOptions:
		switch (val) {
		case PvmTraceFull:
		case PvmTraceTime:
		case PvmTraceCount:
			rc = pvmctrc.trcopt;
			pvmctrc.trcopt = val;
			break;
		
		default:
			rc = PvmBadParam;
			err = 1;
			break;
		}
		break;

	case PvmFragSize:

#if defined(IMA_AIX4MP) || defined(IMA_AIX5MP) \
	|| defined(IMA_ALPHAMP) || defined(IMA_CSPP) \
	|| defined(IMA_HPPAMP) || defined(IMA_RS6KMP) \
	|| defined(IMA_SGIMP) || defined(IMA_SGIMP6) \
	|| defined(IMA_SGIMP64) || defined(IMA_SUNMP)

		rc = PvmBadParam;
		err = 1;

#else /* SHMEM */

#if defined(IMA_CM5) || defined(IMA_CUBE) || defined(IMA_I860) \
	|| defined(IMA_PGON) || defined(IMA_SP2MPI) \
	|| defined(IMA_AIX4SP2) || defined(IMA_AIX5SP2) \
	|| defined(IMA_BEOLIN)
		/* if (val < TDFRAGHDR + TTMSGHDR + 4 || val > 1048576) */
		if (val < TDFRAGHDR + MSGHDRLEN + 4 || val > MAXFRAGSIZE)
#else
		if (val < TDFRAGHDR + MSGHDRLEN + 4 || val > 1048576)
#endif

		{
			rc = PvmBadParam;
			err = 1;

		} else {
			rc = pvmfrgsiz;
			pvmfrgsiz = val;
		}

#endif /* SHMEM */

		break;

	case PvmResvTids:
		rc = pvmrescode;
		pvmrescode = val;
		break;

	case PvmSelfOutputTid:
		if (pvmtrc.outtid > 0 || val > 0) {
			if (rc = BEATASK)
				err = 1;
			else {
				sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
				rbf = pvm_setrbuf(0);
				what = TS_OUTTID;
				pvm_pkint(&what, 1, 1);
				sprintf(buf, "%x", 0xffffffff & val);
				pvm_pkstr(buf);
				if ((rc = msendrecv(TIDPVMD, TM_SETOPT, SYSCTX_TM)) > 0) {
					pvm_freebuf(pvm_setrbuf(rbf));
					rc = pvmtrc.outtid;
					pvmtrc.outtid = val;
					pvmctrc.outtid = pvmtrc.outtid;
					pvmctrc.outctx = pvmtrc.outctx;
					pvmctrc.outtag = pvmtrc.outtag;

				} else {
					pvm_setrbuf(rbf);
					err = 1;
				}
				pvm_freebuf(pvm_setsbuf(sbf));
			}
		}
		else {
			rc = pvmtrc.outtid;
			pvmtrc.outtid = val;
			pvmctrc.outtid = pvmtrc.outtid;
			pvmctrc.outctx = pvmtrc.outctx;
			pvmctrc.outtag = pvmtrc.outtag;
		}
		break;

	case PvmSelfOutputContext:
		rc = PvmNotImpl;
		err = 1;
		break;

	case PvmSelfOutputCode:
		if (pvmtrc.outtid <= 0 || (rc = BEATASK))
			err = 1;
		else {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			what = TS_OUTTAG;
			pvm_pkint(&what, 1, 1);
			sprintf(buf, "%x", 0xffffffff & val);
			pvm_pkstr(buf);
			if ((rc = msendrecv(TIDPVMD, TM_SETOPT, SYSCTX_TM)) > 0) {
				pvm_freebuf(pvm_setrbuf(rbf));
				rc = pvmtrc.outtag;
				pvmtrc.outtag = val;
				pvmctrc.outtid = pvmtrc.outtid;
				pvmctrc.outctx = pvmtrc.outctx;
				pvmctrc.outtag = pvmtrc.outtag;

			} else {
				pvm_setrbuf(rbf);
				err = 1;
			}
			pvm_freebuf(pvm_setsbuf(sbf));
		}
		break;

	case PvmSelfTraceTid:
		if ( pvmtrc.trctid > 0 || val > 0 ) {
			if (rc = BEATASK)
				err = 1;
			else {
				sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
				rbf = pvm_setrbuf(0);
				what = TS_TRCTID;
				pvm_pkint(&what, 1, 1);
				sprintf(buf, "%x", 0xffffffff & val);
				pvm_pkstr(buf);
				if ((rc = msendrecv(TIDPVMD, TM_SETOPT, SYSCTX_TM)) > 0) {
					pvm_freebuf(pvm_setrbuf(rbf));
					rc = pvmtrc.trctid;
					pvmtrc.trctid = val;
					pvmctrc.trctid = pvmtrc.trctid;
					pvmctrc.trcctx = pvmtrc.trcctx;
					pvmctrc.trctag = pvmtrc.trctag;

				} else {
					pvm_setrbuf(rbf);
					err = 1;
				}
				pvm_freebuf(pvm_setsbuf(sbf));
			}
		}
		else {
			rc = pvmtrc.trctid;
			pvmtrc.trctid = val;
			pvmctrc.trctid = pvmtrc.trctid;
			pvmctrc.trcctx = pvmtrc.trcctx;
			pvmctrc.trctag = pvmtrc.trctag;
		}
		break;

	case PvmSelfTraceContext:
		rc = PvmNotImpl;
		err = 1;
		break;

	case PvmSelfTraceCode:
		if (pvmtrc.trctid <= 0 || (rc = BEATASK))
			err = 1;
		else {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			what = TS_TRCTAG;
			pvm_pkint(&what, 1, 1);
			sprintf(buf, "%x", 0xffffffff & val);
			pvm_pkstr(buf);
			if ((rc = msendrecv(TIDPVMD, TM_SETOPT, SYSCTX_TM)) > 0) {
				pvm_freebuf(pvm_setrbuf(rbf));
				rc = pvmtrc.trctag;
				pvmtrc.trctag = val;
				pvmctrc.trctid = pvmtrc.trctid;
				pvmctrc.trcctx = pvmtrc.trcctx;
				pvmctrc.trctag = pvmtrc.trctag;

			} else {
				pvm_setrbuf(rbf);
				err = 1;
			}
			pvm_freebuf(pvm_setsbuf(sbf));
		}
		break;

	case PvmSelfTraceBuffer:
		tev_flush( 1 );
		rc = pvmtrc.trcbuf;
		pvmtrc.trcbuf = val;
		break;

	case PvmSelfTraceOptions:
		tev_flush( 1 );
		switch (val) {
		case PvmTraceFull:
		case PvmTraceTime:
		case PvmTraceCount:
			rc = pvmtrc.trcopt;
			pvmtrc.trcopt = val;
			break;

		default:
			rc = PvmBadParam;
			err = 1;
			break;
		}
		break;

	case PvmShowTids:
		rc = pvmshowtaskid;
		pvmshowtaskid = val;
		break;

	case PvmNoReset:
		if ( pvmmytid < 0 ) {
			rc = PvmBadParam;
			lpvmerr("pvm_setopt: PvmNoReset task not initialized", rc);
			err = 1;
		} else {
			rc = pvmnoreset;
			if ( val && !pvmnoreset ) {
				sbf = pvm_setsbuf(pvm_mkbuf(PvmDataDefault));
				pvm_pkint( &pvmmytid, 1, 1 );
				if ( pvmnoresetindex = pvm_putinfo( PVMNORESETCLASS,
						pvm_getsbuf(), PvmMboxMultiInstance ) < 0 ) {
					rc = PvmSysErr;
					err = 1;
					val = 0;
				}
				pvm_freebuf(pvm_setsbuf(sbf));
			}
			else if ( !val && pvmnoreset && pvmnoresetindex >= 0 ) {
				if ( pvm_delinfo( PVMNORESETCLASS, pvmnoresetindex,
						PvmMboxDefault ) < 0 ) {
					rc = PvmSysErr;
					err = 1;
					val = 0;
				}
				pvmnoresetindex = -1;
			}
			pvmnoreset = val;
		}
		break;

#if defined(IMA_AIX4MP) || defined(IMA_AIX5MP) \
	|| defined(IMA_ALPHAMP) || defined(IMA_CSPP) \
	|| defined(IMA_HPPAMP) || defined(IMA_RS6KMP) \
	|| defined(IMA_SGIMP) || defined(IMA_SGIMP6) \
	|| defined(IMA_SGIMP64) || defined(IMA_SUNMP)

	case PvmPollTime:
		rc = pvmpolltime;
		if (val < 0) {
			rc = PvmBadParam;
			err = 1;
			break;
		}
		pvmpolltime = val;
		break;

	case PvmPollType:
		rc = pvmpolltype;
		if ((val != PvmPollConstant) && (val != PvmPollSleep)) {
			rc = PvmBadParam;
			err = 1;
			break;
		}
		pvmpolltype = val;
		break;

#else /* SHMEM */

	case PvmPollTime:
	case PvmPollType:
		rc = PvmNotImpl;
		err = 1;
		break;

#endif /* SHMEM */

	default:
		rc = PvmBadParam;
		err = 1;
		break;
	}

	if (TEV_AMEXCL) {
		if (pvmmytid != -1
				&& TEV_DO_TRACE(TEV_SETOPT,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_OPV, TEV_DATA_SCALAR, &rc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (err)
		return lpvmerr("pvm_setopt", rc);
	return rc;
}


int
pvmsettaskname( name )
	char *name;
{
	if ( name == NULL )
		return lpvmerr( "pvmsettaskname", PvmBadParam );

	if ( pvmmytid != -1 )
		return lpvmerr( "pvmsettaskname", PvmExists );

	if ( pvmmytaskname != NULL )
	{
		PVM_FREE( pvmmytaskname );
		pvmmytaskname = (char *) NULL;
	}

	pvmmytaskname = STRALLOC( name );

	return 0;
}


int
pvm_getnoresets( tids, ntids )
	int **tids;
	int *ntids;
{
	static int *tidlist = (int *) NULL;
	static int num = 0;

	int index;
	int done;
	int save;
	int mid;
	int cnt;

	/* Allocate Initial Tids List */

	if ( !tidlist )
	{
		num = 16;
		tidlist = TALLOC( num, int, "int" );
	}

	/* Save Receive Buffer */

	save = pvm_setrbuf( 0 );

	/* Search for No Resets */

	index = 0;
	done = 0;
	cnt = 0;

	while ( !done )
	{
		if ( pvm_recvinfo( PVMNORESETCLASS, index, PvmMboxFirstAvail )
				<= 0 )
		{
			done++;
		}

		else
		{
			if ( cnt >= num )
			{
				num *= 2;

				tidlist = TREALLOC( tidlist, num, int );
			}

			pvm_upkint( &(tidlist[cnt++]), 1, 1 );

			index++;
		}
	}

	/* Restore Receive Buffer */

	pvm_setrbuf( save );

	/* Set Return Values */

	if ( tids != NULL )
		*tids = tidlist;

	if ( ntids != NULL )
		*ntids = cnt;

	return( PvmOk );
}


int
pvm_addhosts(names, count, svp)
	char **names;	/* host name vector */
	int count;		/* length of names */
	int *svp;		/* status vector return */
{
	int sbf, rbf;
	int cc;
	int i;
	int *sv;		/* status vector */
	char *buf;
	int tmp;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_ADDHOSTS,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_HNL, TEV_DATA_ARRAY,
				names, count, 1 );
			TEV_FIN;
		}
	}

	if (count < 1 || count > (TIDHOST >> (ffs(TIDHOST) - 1))) {
		cc = PvmBadParam;

	} else {
		if (!(cc = BEATASK)) {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			pvm_pkint(&count, 1, 1);
			for (i = 0; i < count; i++)
				pvm_pkstr(names[i]);

			if (pvmschedtid)
				cc = msendrecv(pvmschedtid, SM_ADDHOST, PvmBaseContext);
			else
				cc = msendrecv(TIDPVMD, TM_ADDHOST, SYSCTX_TM);
			if (cc > 0) {
				pvm_upkint(&cc, 1, 1);
				if (cc >= 0) {
					if (cc == count) {
						pvm_upkint(&cc, 1, 1);	/* toss narches */
						sv = TALLOC(count, int, "sv1");
						cc = 0;
						for (i = 0; i < count; i++) {
							pvm_upkint(&sv[i], 1, 1);
							/* toss name, arch, speed, ds */
							pvmupkstralloc(&buf);	PVM_FREE(buf);
							pvmupkstralloc(&buf);	PVM_FREE(buf);
							pvm_upkint(&tmp, 1, 1);
							pvm_upkint(&tmp, 1, 1);
							if (sv[i] >= 0)
								cc++;
						}
						if (svp)
							BCOPY((char*)sv, (char*)svp, count * sizeof(int));
						PVM_FREE(sv);

					} else {
						pvmlogprintf("pvm_addhosts() sent count %d received count %d\n",
								count, cc);
						cc = PvmOutOfRes;
					}
				}
				pvm_freebuf(pvm_setrbuf(rbf));

			} else
				pvm_setrbuf(rbf);
			pvm_freebuf(pvm_setsbuf(sbf));
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_ADDHOSTS,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_addhosts", cc);
	return cc;
}


int
pvm_config(nhostp, narchp, hostp)
	int *nhostp;
	int *narchp;
	struct pvmhostinfo **hostp;
{
	int sbf, rbf, cc;
	static int nhost = 0;
	static int narch = 0;
	static struct pvmhostinfo *hlist = 0;
	int i;
	/* char buf[256]; XXX static limit, argh (Not Any More! :-) JAK */
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_CONFIG,TEV_EVENT_ENTRY))
			TEV_FIN;
	}

	if (hlist) {
		while (nhost-- > 0) {
			PVM_FREE(hlist[nhost].hi_name);
			PVM_FREE(hlist[nhost].hi_arch);
		}
		PVM_FREE(hlist);
		hlist = 0;
		nhost = 0;
	}
	if (!(cc = BEATASK)) {
		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);
		if (pvmschedtid)
			cc = msendrecv(pvmschedtid, SM_CONFIG, PvmBaseContext);
		else
			cc = msendrecv(TIDPVMD, TM_CONFIG, SYSCTX_TM);
		if (cc > 0) {
			pvm_upkint(&nhost, 1, 1);
			pvm_upkint(&narch, 1, 1);
			hlist = TALLOC(nhost, struct pvmhostinfo, "hi");
			for (i = 0; i < nhost; i++) {
				pvm_upkint(&hlist[i].hi_tid, 1, 1);
				pvmupkstralloc(&(hlist[i].hi_name));
				pvmupkstralloc(&(hlist[i].hi_arch));
				pvm_upkint(&hlist[i].hi_speed, 1, 1);
				pvm_upkint(&hlist[i].hi_dsig, 1, 1);
			}
			pvm_freebuf(pvm_setrbuf(rbf));
			if (nhostp)
				*nhostp = nhost;
			if (narchp)
				*narchp = narch;
			if (hostp)
				*hostp = hlist;
			cc = 0;
		}
		pvm_freebuf(pvm_setsbuf(sbf));
		pvm_setrbuf(rbf);
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_CONFIG,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_NH, TEV_DATA_SCALAR, &nhost, 1, 1 );
			TEV_PACK_INT( TEV_DID_NA, TEV_DATA_SCALAR, &narch, 1, 1 );
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_config", cc);
	return cc;
}


int
pvm_delhosts(names, count, svp)
	char **names;
	int count;
	int *svp;		/* status vector return */
{
	int sbf, rbf;
	int cc;
	int i;
	int *sv;		/* return values */
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_DELHOSTS,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_HNL, TEV_DATA_ARRAY,
				names, count, 1 );
			TEV_FIN;
		}
	}

	if (count < 1 || count > (TIDHOST >> (ffs(TIDHOST) - 1))) {
		cc = PvmBadParam;

	} else {
		if (!(cc = BEATASK)) {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			pvm_pkint(&count, 1, 1);
			for (i = 0; i < count; i++)
				pvm_pkstr(names[i]);

			if (pvmschedtid)
				cc = msendrecv(pvmschedtid, SM_DELHOST, PvmBaseContext);
			else
				cc = msendrecv(TIDPVMD, TM_DELHOST, SYSCTX_TM);
			if (cc > 0) {
				pvm_upkint(&cc, 1, 1);
				if (cc >= 0) {
					if (cc == count) {
						sv = TALLOC(count, int, "sv2");
						pvm_upkint(sv, count, 1);
						cc = 0;
						for (i = count; i-- > 0; )
							if (sv[i] >= 0)
								cc++;
						if (svp)
							BCOPY((char*)sv, (char*)svp, count * sizeof(int));
						PVM_FREE(sv);

					} else {
						pvmlogprintf("pvm_delhosts() sent count %d received count %d\n",
								count, cc);
						cc = PvmOutOfRes;
					}
				}
				pvm_freebuf(pvm_setrbuf(rbf));

			} else
				pvm_setrbuf(rbf);
			pvm_freebuf(pvm_setsbuf(sbf));
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_DELHOSTS,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_delhosts", cc);
	return cc;
}


int
pvm_exit()
{
	int i, lndh;
	int sbf, rbf;
	int cc = 0;
	struct waitc *wp, *wp2;
	struct pmsg *up;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_EXIT,TEV_EVENT_ENTRY))
			TEV_FIN;
	}

	if (pvmmytid != -1) {
		wp = waitlist->wa_link;
		while (wp != waitlist) {
			wp2 = wp->wa_link;
			if (wp->wa_kind == WT_TASKX) {
				up = wp->wa_mesg;
				wp->wa_mesg = 0;
				mesg_input(up);
				LISTDELETE(wp, wa_link, wa_rlink);
			}
			wp = wp2;
		}

		while (pvm_nrecv(-1, -1) > 0) ;		/* XXX attempt to flush messages */

		fflush(stderr);
		fflush(stdout);

		tev_flush( 1 );

		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);
		if ((cc = msendrecv(TIDPVMD, TM_EXIT, SYSCTX_TM)) > 0) {
			pvm_freebuf(pvm_setrbuf(rbf));
			cc = 0;

		} else
			pvm_setrbuf(rbf);
		pvm_freebuf(pvm_setsbuf(sbf));

		/*
		*  remove all task's message handler functions
		*/
		lndh = ndhandles - 1;
		for (i = lndh; i >= 0; i--){
			pvm_delmhf(i);
		}

		pvmendtask();
	}

	if (TEV_AMEXCL) {
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_exit", cc);
	return cc;
}


int
pvm_halt()
{
	int cc, sbf, rbf;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_HALT,TEV_EVENT_ENTRY))
			TEV_FIN;
	}

	if (!(cc = BEATASK)) {
		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);
		cc = (msendrecv(TIDPVMD, TM_HALT, SYSCTX_TM) < 0) ? 0 : PvmSysErr;
		pvm_freebuf(pvm_setsbuf(sbf));
		pvm_setrbuf(rbf);
	}

	if (TEV_AMEXCL) {
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_halt", cc);
	return cc;
}


int
pvm_kill(tid)
	int tid;
{
	int cc;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_KILL,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_TT, TEV_DATA_SCALAR, &tid, 1, 1 );
			TEV_FIN;
		}
	}

	cc = pvm_sendsig(tid, SIGTERM);

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_KILL,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}
	if (cc < 0)
		lpvmerr("pvm_kill", cc);
	return cc;
}


int
pvm_mcast(tids, count, tag)
	int *tids;		/* dest tasks */
	int count;		/* number of tids */
	int tag;		/* message type tag */
{
	int cc;			/* for return codes */
	int i;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_MCAST,TEV_EVENT_ENTRY)) {
			int nb = -1;
			pvm_bufinfo(
					( pvmtrcsbfsave ) ? pvmtrcsbfsave : pvmsbuf->m_mid,
					&nb, (int *) NULL, (int *) NULL );
			TEV_PACK_INT( TEV_DID_MNB, TEV_DATA_SCALAR, &nb, 1, 1 );
			TEV_PACK_INT( TEV_DID_MC, TEV_DATA_SCALAR, &tag, 1, 1 );
			TEV_PACK_INT( TEV_DID_MCX, TEV_DATA_SCALAR,
					&pvmmyctx, 1, 1 );
			TEV_PACK_INT( TEV_DID_MDL, TEV_DATA_ARRAY, tids, count, 1 );
			TEV_FIN;
		}
	}

	/* sanity check args and sendable message */

	if (!(cc = BEATASK)) {
		if (!pvmsbuf)
			cc = PvmNoBuf;
		else if (count < 0 || (!pvmrescode && (tag & ~0x7fffffff)))
				cc = PvmBadParam;
		else if (!pvmrescode)
			for (i = count; i-- > 0; )
				if (!TIDISTASK(tids[i])) {
					cc = PvmBadParam;
					break;
				}

	}

	if (!cc && count > 0)
		cc = pvmmcast(pvmsbuf->m_mid, tids, count, tag);

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_MCAST,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_mcast", cc);
	return cc;
}

#ifdef WIN32
#ifndef IMA_WIN32_WATCOM
extern char **environ;
#endif
#endif

int
pvm_mytid()
{
	int cc;
	char **ep=0;

	TEV_DECLS;



	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_MYTID,TEV_EVENT_ENTRY))
			TEV_FIN;
	}

	if (!(cc = BEATASK))
		cc = pvmmytid;

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_MYTID,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_MT, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_mytid", cc);
	return cc;
}


int
pvm_mstat(host)
	char *host;
{
	int sbf, rbf, cc;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_MSTAT,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_HN, TEV_DATA_SCALAR,
				host ? host : "", 1, 1 );
			TEV_FIN;
		}
	}
	if (!host || !*host) {
		cc = PvmBadParam;

	} else {
		if (!(cc = BEATASK)) {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			pvm_pkstr(host);
			if ((cc = msendrecv(TIDPVMD, TM_MSTAT, SYSCTX_TM)) > 0) {
				pvm_upkint(&cc, 1, 1);
				pvm_freebuf(pvm_setrbuf(rbf));

			} else
				pvm_setrbuf(rbf);
			pvm_freebuf(pvm_setsbuf(sbf));
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_MSTAT,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_HS, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0 && cc != PvmNoHost && cc != PvmHostFail)
		lpvmerr("pvm_mstat", cc);
	return cc;
}


int
pvm_notify(what, code, count, vals)
	int what;
	int code;
	int count;
	int *vals;
{
	static struct timeval ztv = { 0, 0 };

	int sbf;
	int cc;
	int numtid;
	int dosend = 0;
	struct waitc *wp;
	int flags;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_NOTIFY,TEV_EVENT_ENTRY)) {
			int tevcount;
			TEV_PACK_INT( TEV_DID_NE, TEV_DATA_SCALAR, &what, 1, 1 );
			TEV_PACK_INT( TEV_DID_NMC, TEV_DATA_SCALAR, &code, 1, 1 );
			tevcount = ( what != PvmHostAdd ) ? count : 0;
			TEV_PACK_INT( TEV_DID_NTL, TEV_DATA_ARRAY,
				vals, tevcount, 1 );
			TEV_FIN;
		}
	}

	flags = what;
	what &= ~PvmNotifyCancel;

	if (!(cc = BEATASK)) {
		if (!pvmrescode && (code & ~0x7fffffff)) {
			cc = PvmBadParam;

		} else {
			switch (what) {

			case PvmHostDelete:
				if (count < 1)
					cc = PvmBadParam;
				else {
					numtid = count;
					dosend = 1;
				}
				break;

			case PvmTaskExit:
				if (count < 1)
					cc = PvmBadParam;
				else
					for (numtid = count; numtid-- > 0; )
						if (!TIDISTASK(vals[numtid])) {
							cc = PvmBadParam;
							break;
						}
				if (!cc) {
					for (numtid = count; numtid-- > 0; )
						if (vals[numtid] == pvmmytid) {
							wp = wait_new(WT_TASKX);
							wp->wa_tid = pvmmytid;
							wp->wa_on = pvmmytid;
							sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
							pvm_pkint(&pvmmytid, 1, 1);
							sbf = pvm_setsbuf(sbf);
							wp->wa_mesg = midtobuf(sbf);
							wp->wa_mesg->m_ctx = pvmmyctx;
							wp->wa_mesg->m_tag = code;
						}
					numtid = count;
					dosend = 1;
				}
				break;

			case PvmHostAdd:
				numtid = 0;
				vals = &numtid;
				dosend = 1;
				break;

			case PvmRouteAdd:
				FORLIST (wp, waitlist, wa_link)
					if (wp->wa_kind == WT_ROUTEA
					&& wp->wa_mesg->m_ctx == pvmmyctx
					&& wp->wa_mesg->m_tag == code)
						break;

				if (count == 0 || (flags & PvmNotifyCancel)) {
					if (wp != waitlist)
						wait_delete(wp);

				} else {
					if (wp == waitlist) {
						wp = wait_new(WT_ROUTEA);
						wp->wa_tid = pvmmytid;
						wp->wa_on = pvmmytid;
						sbf = pvm_mkbuf(PvmDataFoo);
						wp->wa_mesg = midtobuf(sbf);
						wp->wa_mesg->m_ctx = pvmmyctx;
						wp->wa_mesg->m_tag = code;
					}
					wp->wa_count = count;
				}
				break;

			case PvmRouteDelete:
				if (count < 1)
					cc = PvmBadParam;
				else
					for (numtid = count; numtid-- > 0; )
						if (!TIDISTASK(vals[numtid])) {
							cc = PvmBadParam;
							break;
						}
				if (!cc) {
					for (numtid = count; numtid-- > 0; )
						post_routedelete(vals[numtid], pvmmyctx, code);
				}
				break;

			default:
				cc = PvmBadParam;
				break;
			}

			if (dosend) {
				sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
				pvm_pkint(&flags, 1, 1);
				pvm_pkint(&pvmmyctx, 1, 1);
				pvm_pkint(&code, 1, 1);
				pvm_pkint(&count, 1, 1);
				pvm_pkint(vals, numtid, 1);

				if (pvmschedtid)
					cc = mroute(pvmsbuf->m_mid, pvmschedtid, SM_NOTIFY, &ztv);
				else
					cc = mroute(pvmsbuf->m_mid, TIDPVMD, TM_NOTIFY, &ztv);
				pvm_freebuf(pvm_setsbuf(sbf));
				if (cc > 0)
					cc = 0;
			}
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_NOTIFY,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_notify", cc);
	return cc;
}


int
pvm_nrecv(tid, tag)
	int tid;
	int tag;
{
	struct pmsg *up;
	struct pmsg *bestup;
	int bestcc = 0;
	int cc;
	int alrdy = 0;
	TEV_DECLS
	static struct timeval ztv = { 0, 0 };

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_NRECV,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_RST, TEV_DATA_SCALAR, &tid, 1, 1 );
			TEV_PACK_INT( TEV_DID_RMC, TEV_DATA_SCALAR, &tag, 1, 1 );
			TEV_PACK_INT( TEV_DID_RCX, TEV_DATA_SCALAR,
					&pvmmyctx, 1, 1 );
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		if (pvmrbuf)
			umbuf_free(pvmrbuf);
		pvmrbuf = 0;

		for (up = pvmrxlist->m_link; 1; up = up->m_link) {
			if (up == pvmrxlist && bestcc)
				break;
			while (up == pvmrxlist) {
				if (alrdy) {
					cc = 0;
					goto done;
				}
				up = up->m_rlink;
				if ((cc = mroute(0, 0, 0, &ztv)) < 0)
					goto done;
				up = up->m_link;
				alrdy = 1;
			}

			if ((cc = recv_match(up->m_mid, tid, tag)) < 0)
				goto done;
			if (cc == 1) {
				bestup = up;
				break;
			}
			if (cc > bestcc) {
				bestcc = cc;
				bestup = up;
			}
		}

		LISTDELETE(bestup, m_link, m_rlink);
		bestup->m_flag &= ~MM_UPACK;
		if (!(cc = pvm_setrbuf(bestup->m_mid)))
			cc = bestup->m_mid;
	}

done:
	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_NRECV,TEV_EVENT_EXIT)) {
			int nb, mc, src;
			TEV_PACK_INT( TEV_DID_MB, TEV_DATA_SCALAR, &cc, 1, 1 );
			if (cc > 0)
				pvm_bufinfo(cc, &nb, &mc, &src);
			else
				nb = mc = src = -1;
			TEV_PACK_INT( TEV_DID_MNB, TEV_DATA_SCALAR, &nb, 1, 1 );
			TEV_PACK_INT( TEV_DID_MC, TEV_DATA_SCALAR, &mc, 1, 1 );
			TEV_PACK_INT( TEV_DID_MCX, TEV_DATA_SCALAR,
					&pvmmyctx, 1, 1 );
			TEV_PACK_INT( TEV_DID_SRC, TEV_DATA_SCALAR, &src, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_nrecv", cc);
	return cc;
}


int
pvm_parent()
{
	int cc;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_PARENT,TEV_EVENT_ENTRY))
			TEV_FIN;
	}

	if (!(cc = BEATASK))
		cc = pvmmyptid ? pvmmyptid : PvmNoParent;

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_PARENT,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_PT, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0 && cc != PvmNoParent && cc != PvmParentNotSet )
		lpvmerr("pvm_parent", cc);
	return cc;
}


int
pvm_probe(tid, tag)
	int tid;
	int tag;
{
	struct pmsg *up;
	struct pmsg *bestup;
	int bestcc = 0;
	int cc;
	int alrdy = 0;
	TEV_DECLS
	static struct timeval ztv = { 0, 0 };

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_PROBE,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_RST, TEV_DATA_SCALAR, &tid, 1, 1 );
			TEV_PACK_INT( TEV_DID_RMC, TEV_DATA_SCALAR, &tag, 1, 1 );
			TEV_PACK_INT( TEV_DID_RCX, TEV_DATA_SCALAR,
					&pvmmyctx, 1, 1 );
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		for (up = pvmrxlist->m_link; 1; up = up->m_link) {
			if (up == pvmrxlist && bestcc)
				break;
			while (up == pvmrxlist) {
				if (alrdy) {
					cc = 0;
					goto done;
				}
				up = up->m_rlink;
				if ((cc = mroute(0, 0, 0, &ztv)) < 0)
					goto done;
				up = up->m_link;
				alrdy = 1;
			}

			if ((cc = recv_match(up->m_mid, tid, tag)) < 0)
				goto done;
			if (cc == 1) {
				bestup = up;
				break;
			}
			if (cc > bestcc) {
				bestcc = cc;
				bestup = up;
			}
		}
		bestup->m_flag &= ~MM_UPACK;
		cc = bestup->m_mid;
	}

done:
	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_PROBE,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_probe", cc);
	return cc;
}


int
pvm_pstat(tid)
	int tid;	/* task */
{
	int sbf, rbf;
	int cc;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_PSTAT,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_TT, TEV_DATA_SCALAR, &tid, 1, 1 );
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		if (!TIDISTASK(tid))
			cc = PvmBadParam;

		else {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			pvm_pkint(&tid, 1, 1);
			if ((cc = msendrecv(TIDPVMD, TM_PSTAT, SYSCTX_TM)) > 0) {
				pvm_upkint(&cc, 1, 1);
				pvm_freebuf(pvm_setrbuf(rbf));

			} else
				pvm_setrbuf(rbf);
			pvm_freebuf(pvm_setsbuf(sbf));
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_PSTAT,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_TST, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0 && cc != PvmNoTask)
		lpvmerr("pvm_pstat", cc);
	return cc;
}


int
pvm_recv(tid, tag)
	int tid;
	int tag;
{
	struct pmsg *up;
	struct pmsg *bestup;
	int bestcc = 0;
	int cc;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_RECV,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_RST, TEV_DATA_SCALAR, &tid, 1, 1 );
			TEV_PACK_INT( TEV_DID_RMC, TEV_DATA_SCALAR, &tag, 1, 1 );
			TEV_PACK_INT( TEV_DID_RCX, TEV_DATA_SCALAR,
					&pvmmyctx, 1, 1 );
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		if (pvmrbuf)
			umbuf_free(pvmrbuf);
		pvmrbuf = 0;

		for (up = pvmrxlist->m_link; 1; up = up->m_link) {
			if (up == pvmrxlist && bestcc)
				break;
			while (up == pvmrxlist) {
				up = up->m_rlink;
				if ((cc = mroute(0, 0, 0, (struct timeval *)0)) < 0)
					goto done;
#if defined(IMA_PGON) || defined(IMA_SP2MPI) || defined(IMA_AIX4SP2) \
		|| defined(IMA_AIX5SP2)
			/* bypass matching of messages when in a precv that completed */
				if (pvm_inprecv && pvm_inprecv->complete)
					return 0;
#endif
				up = up->m_link;
			}


			if ((cc = recv_match(up->m_mid, tid, tag)) < 0)
				goto done;
			if (cc == 1) {
				bestup = up;
				break;
			}
			if (cc > bestcc) {
				bestcc = cc;
				bestup = up;
			}
		}

		LISTDELETE(bestup, m_link, m_rlink);
		bestup->m_flag &= ~MM_UPACK;
		if (!(cc = pvm_setrbuf(bestup->m_mid)))
			cc = bestup->m_mid;
	}

done:
	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_RECV,TEV_EVENT_EXIT)) {
			int nb, mc, src;
			TEV_PACK_INT( TEV_DID_MB, TEV_DATA_SCALAR, &cc, 1, 1 );
			if (cc > 0)
				pvm_bufinfo(cc, &nb, &mc, &src);
			else
				nb = mc = src = -1;
			TEV_PACK_INT( TEV_DID_MNB, TEV_DATA_SCALAR, &nb, 1, 1 );
			TEV_PACK_INT( TEV_DID_MC, TEV_DATA_SCALAR, &mc, 1, 1 );
			TEV_PACK_INT( TEV_DID_MCX, TEV_DATA_SCALAR,
					&pvmmyctx, 1, 1 );
			TEV_PACK_INT( TEV_DID_SRC, TEV_DATA_SCALAR, &src, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_recv", cc);
	return cc;
}


int (*
pvm_recvf(new))()
	int (*new)__ProtoGlarp__((int,int,int));
{
	int (*old)() = recv_match;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_RECVF,TEV_EVENT_ENTRY))
			TEV_FIN;
	}

	recv_match = new ? new : def_match;

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_RECVF,TEV_EVENT_EXIT))
			TEV_FIN;
		TEV_ENDEXCL;
	}

	return old;
}


int
pvm_send(tid, tag)
	int tid;	/* dest task */
	int tag;	/* type code */
{
	static struct timeval ztv = { 0, 0 };

	int tmp;
	int cc;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_SEND,TEV_EVENT_ENTRY)) {
			int nb = -1;
			pvm_bufinfo(
					( pvmtrcsbfsave ) ? pvmtrcsbfsave : pvmsbuf->m_mid,
					&nb, (int *) NULL, (int *) NULL );
			TEV_PACK_INT( TEV_DID_MNB, TEV_DATA_SCALAR, &nb, 1, 1 );
			TEV_PACK_INT( TEV_DID_DST, TEV_DATA_SCALAR, &tid, 1, 1 );
			TEV_PACK_INT( TEV_DID_MC, TEV_DATA_SCALAR, &tag, 1, 1 );
			TEV_PACK_INT( TEV_DID_MCX, TEV_DATA_SCALAR,
					&pvmmyctx, 1, 1 );
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		if ( tid == PVM_TRACE_TID && tag == PVM_TRACE_CODE ) {
			if ( TEV_MASK_CHECK( pvmtrc.tmask, TEV_USER_DEFINED ) ) {
				/* Schlopp In End of Event Marker */
				enc_trc_fin(pvmsbuf);
				/* Send to Proper Tracer Destination */
				pvmsbuf->m_ctx = pvmtrc.trcctx;
				if ((cc = mroute(pvmsbuf->m_mid, pvmtrc.trctid,
						pvmtrc.trctag, &ztv)) > 0)
					cc = 0;
			}
			else
				cc = 0;
		}
		else if (!pvmrescode
				&& (!TIDISTASK(tid) || (tag & ~0x7fffffff)))
			cc = PvmBadParam;
		else
			if (!pvmsbuf)
				cc = PvmNoBuf;
			else {

/* XXX short-ckt to us should go here.  maybe can inc frag chain
   XXX count and make new message, put on pvmrxlist. */
				pvmsbuf->m_ctx = pvmmyctx;
				if ((cc = mroute(pvmsbuf->m_mid, tid, tag, &ztv)) > 0)
					cc = 0;
			}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_SEND,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_send", cc);
	return cc;
}


int
pvm_sendsig(tid, signum)
	int tid;
	int signum;
{
	int cc;
	int sbf, rbf;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_SENDSIG,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_TT, TEV_DATA_SCALAR, &tid, 1, 1 );
			TEV_PACK_INT( TEV_DID_SN, TEV_DATA_SCALAR, &signum, 1, 1 );
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		if (!TIDISTASK(tid))
			cc = PvmBadParam;

		else {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);

			pvm_pkint(&tid, 1, 1);
			pvm_pkint(&signum, 1, 1);
			if ((cc = msendrecv(TIDPVMD, TM_SENDSIG, SYSCTX_TM)) > 0) {
				pvm_freebuf(pvm_setrbuf(rbf));
				cc = 0;

			} else
				pvm_setrbuf(rbf);
			pvm_freebuf(pvm_setsbuf(sbf));
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_SENDSIG,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_sendsig", cc);
	return cc;
}


/*	bubble()
*
*	Move nonnegative els to head of array, negative ones to end.
*	Returns number of nonnegative els.
*/

static int
bubble(n, a)
	int n;			/* length of a */
	int *a;
{
	int r, w, t;

	for (w = r = 0; r < n; r++) {
		if (a[w] < 0) {
			if (a[r] >= 0) {
				t = a[w];
				a[w] = a[r];
				a[r] = t;
				w++;
			}

		} else {
			w++;
		}
	}
	return w;
}


#if	defined(IMA_I860) || defined(IMA_CM5)
static int
pvmgetenvars(ep)
	char ***ep;
{
	return 0;
}

#else	/*defined(IMA_I860) || defined(IMA_CM5)*/
static int
pvmgetenvars(ep)
	char ***ep;
{
	char **xpl;			/* vars to export */
	int mxpl;			/* cur length of xpl */
	int nxpl;			/* num vars found */
	char buf[200];
	char *p, *q;
	int n;

	if (p = getenv("PVM_EXPORT")) {
		mxpl = 5;
		xpl = TALLOC(mxpl, char *, "env");
		xpl[0] = p - 11;
		nxpl = 1;
		while (1) {
			while (*p == ':')
				p++;
			if (!*p)
				break;
			n = (q = CINDEX(p, ':')) ? q - p : strlen(p);
			strncpy(buf, p, n);
			buf[n] = 0;
			if (q = getenv(buf)) {
				if (nxpl == mxpl) {
					mxpl += mxpl / 2 + 1;
					xpl = TREALLOC(xpl, mxpl, char *);
				}
				xpl[nxpl++] = q - n - 1;
			}
			p += n;
		}
		*ep = xpl;
		return nxpl;

	} else {
		return 0;
	}
}
#endif	/*defined(IMA_I860) || defined(IMA_CM5)*/


int
pvm_spawn(file, argv, flags, where, count, tids)
	char *file;
	char **argv;
	int flags;
	char *where;
	int count;
	int *tids;
{
	int sbf, rbf;	/* temp for current tx, rx msgs */
	int ictx;
	int cc;
	int i, n;
	char **ep;
	int *tidlist = 0;
	char *p;
	char buf[TEV_MASK_LENGTH + 20];
	TEV_DECLS

	if (p = getenv("PVMTASK"))
		i = pvmstrtoi(p) | flags;
	else
		i = flags;

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_SPAWN,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_SE, TEV_DATA_SCALAR,
				file ? file : "", 1, 1 );
			TEV_PACK_STRING( TEV_DID_SW, TEV_DATA_SCALAR,
				where ? where : "", 1, 1 );
			TEV_PACK_INT( TEV_DID_SF, TEV_DATA_SCALAR, &i, 1, 1 );
			TEV_PACK_INT( TEV_DID_SC, TEV_DATA_SCALAR, &count, 1, 1 );
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		if (count < 1)
			cc = PvmBadParam;

		else {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);

			pvm_pkstr(file);
			pvm_pkint(&i, 1, 1);
			pvm_pkstr(where ? where : "");
			pvm_pkint(&count, 1, 1);
			if (argv)
				for (n = 0; argv[n]; n++);
			else
				n = 0;
			pvm_pkint(&n, 1, 1);
			for (i = 0; i < n; i++)
				pvm_pkstr(argv[i]);

			pvm_pkint( &(pvmctrc.outtid), 1, 1 );
			pvm_pkint( &(pvmctrc.outctx), 1, 1 );
			pvm_pkint( &(pvmctrc.outtag), 1, 1 );
			pvm_pkint( &(pvmctrc.trctid), 1, 1 );
			pvm_pkint( &(pvmctrc.trcctx), 1, 1 );
			pvm_pkint( &(pvmctrc.trctag), 1, 1 );

			n = pvmgetenvars(&ep) + 4;
			pvm_pkint(&n, 1, 1);
			n -= 4;
			sprintf(buf, "PVMTMASK=%s", pvmctrc.tmask);
			pvm_pkstr(buf);
			sprintf(buf, "PVMTRCBUF=%d", pvmctrc.trcbuf);
			pvm_pkstr(buf);
			sprintf(buf, "PVMTRCOPT=%d", pvmctrc.trcopt);
			pvm_pkstr(buf);
			sprintf(buf, "PVMCTX=0x%x", pvmmyctx);
			pvm_pkstr(buf);
			if (n > 0) {
				for (i = 0; i < n; i++)
					pvm_pkstr(ep[i]);
				PVM_FREE(ep);
			}

			if (pvmschedtid)
				cc = msendrecv(pvmschedtid, SM_SPAWN, PvmBaseContext);
			else
				cc = msendrecv(TIDPVMD, TM_SPAWN, SYSCTX_TM);
			if (cc > 0) {
				pvm_upkint(&cc, 1, 1);
				if (cc == count) {
					tidlist = tids ? tids : TALLOC(count, int, "xxx");
					pvm_upkint(tidlist, cc, 1);
					cc = bubble(cc, tidlist);
				}
				pvm_freebuf(pvm_setrbuf(rbf));

			} else
				pvm_setrbuf(rbf);
			pvm_freebuf(pvm_setsbuf(sbf));

			if (cc > 0) {
				sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
				pvm_pkint(&cc, 1, 1);
				pvm_pkint(tidlist, cc, 1);
				ictx = pvm_setcontext(SYSCTX_TC);
				pvmmcast(pvmsbuf->m_mid, tidlist, cc, TC_SIBLINGS);
				pvm_setcontext(ictx);
				pvm_freebuf(pvm_setsbuf(sbf));
			}
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_SPAWN,TEV_EVENT_EXIT)) {
			int tevcount;
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			tevcount = ( cc > 0 ) ? cc : 0;
			TEV_PACK_INT( TEV_DID_STL, TEV_DATA_ARRAY,
				tidlist, tevcount, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (tidlist != tids && tidlist != NULL)
		PVM_FREE(tidlist);

	if (cc < 0)
		lpvmerr("pvm_spawn", cc);
	return cc;
}


int
pvm_tasks(where, ntaskp, taskp)
	int where;					/* which host or 0 for all */
	int *ntaskp;
	struct pvmtaskinfo **taskp;
{
	int cc, ec, sbf, rbf, ae;
	static struct pvmtaskinfo *tlist = 0;
	static int ntask = 0;
	int len1 = 5, len2 = 3;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_TASKS,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_TW, TEV_DATA_SCALAR, &where, 1, 1 );
			TEV_FIN;
		}
	}

	if (tlist) {
		while (ntask-- > 0)
			PVM_FREE(tlist[ntask].ti_a_out);
		PVM_FREE(tlist);
		tlist = 0;
		ntask = 0;
	}

	if (!(cc = BEATASK)) {
		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);
		pvm_pkint(&where, 1, 1);

		if (pvmschedtid)
			cc = msendrecv(pvmschedtid, SM_TASK, PvmBaseContext);
		else
			cc = msendrecv(TIDPVMD, TM_TASK, SYSCTX_TM);
		if (cc > 0) {
			if (!(cc = pvm_upkint(&ec, 1, 1))
			&& (cc = ec) >= 0) {
				tlist = TALLOC(len1, struct pvmtaskinfo, "ti");
				ae = pvm_setopt(PvmAutoErr, 0);
				ntask = 0;
				while (!pvm_upkint(&tlist[ntask].ti_tid, 1, 1)) {
					pvm_upkint(&tlist[ntask].ti_ptid, 1, 1);
					pvm_upkint(&tlist[ntask].ti_host, 1, 1);
					pvm_upkint(&tlist[ntask].ti_flag, 1, 1);
					pvmupkstralloc(&(tlist[ntask].ti_a_out));
					pvm_upkint(&tlist[ntask].ti_pid, 1, 1);
					ntask++;
					if (ntask == len1) {
						len1 += len2;
						len2 = ntask;
						tlist = TREALLOC(tlist, len1, struct pvmtaskinfo);
					}
				}
				pvm_setopt(PvmAutoErr, ae);
				cc = 0;
			}
			pvm_freebuf(pvm_setrbuf(rbf));
			if (ntaskp)
				*ntaskp = ntask;
			if (taskp)
				*taskp = tlist;
		} else
			pvm_setrbuf(rbf);
		pvm_freebuf(pvm_setsbuf(sbf));
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_TASKS,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_PACK_INT( TEV_DID_TNT, TEV_DATA_SCALAR, &ntask, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_tasks", cc);
	return cc;
}


int
pvm_tickle(narg, argp, nresp, resp)
	int narg;
	int *argp;
	int *nresp;
	int *resp;
{
	int cc;
	int sbf, rbf;
	int nres;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_TICKLE,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_TA, TEV_DATA_ARRAY, argp, narg, 1 );
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		if (narg < 1 || narg > 10)
			cc = PvmBadParam;

		else {

			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			pvm_pkint(&narg, 1, 1);
			pvm_pkint(argp, narg, 1);
			if ((cc = msendrecv(TIDPVMD, TM_TICKLE, SYSCTX_TM)) > 0) {
				pvm_upkint(&nres, 1, 1);
				if (nresp)
					*nresp = nres;
				if (resp)
					pvm_upkint(resp, nres, 1);
				pvm_freebuf(pvm_setrbuf(rbf));
				cc = 0;

			} else
				pvm_setrbuf(rbf);
			pvm_freebuf(pvm_setsbuf(sbf));
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_TICKLE,TEV_EVENT_EXIT)) {
			int tevcount;
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			tevcount = ( resp ) ? nres : 0;
			TEV_PACK_INT( TEV_DID_TR, TEV_DATA_ARRAY,
				resp, tevcount, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_tickle", cc);
	return cc;
}


int
pvm_tidtohost(tid)
	int tid;
{
	return (tid & TIDHOST);
}


int
pvm_trecv(tid, tag, tmout)
	int tid;				/* source tid to match */
	int tag;				/* message tag to match */
	struct timeval *tmout;	/* time to wait for match */
{
	struct pmsg *up;
	struct pmsg *bestup;
	int bestcc = 0;
	int cc;
	struct timeval tin, tnow;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_TRECV,TEV_EVENT_ENTRY)) {
			int ts, tu;
			TEV_PACK_INT( TEV_DID_RST, TEV_DATA_SCALAR, &tid, 1, 1 );
			TEV_PACK_INT( TEV_DID_RMC, TEV_DATA_SCALAR, &tag, 1, 1 );
			TEV_PACK_INT( TEV_DID_RCX, TEV_DATA_SCALAR,
					&pvmmyctx, 1, 1 );
			if (tmout) {
				ts = tmout->tv_sec;
				tu = tmout->tv_usec;
			}
			else
				ts = tu = -1;
			TEV_PACK_INT( TEV_DID_MTS, TEV_DATA_SCALAR, &ts, 1, 1 );
			TEV_PACK_INT( TEV_DID_MTU, TEV_DATA_SCALAR, &tu, 1, 1 );
			TEV_FIN;
		}
	}

	pvmgetclock(&tin);

	if (!(cc = BEATASK)) {
		if (pvmrbuf)
			umbuf_free(pvmrbuf);
		pvmrbuf = 0;

		for (up = pvmrxlist->m_link; 1; up = up->m_link) {
			if (up == pvmrxlist && bestcc)
				break;
			while (up == pvmrxlist) {
				up = up->m_rlink;
				if (tmout) {
					pvmgetclock(&tnow);
					TVXSUBY(&tnow, &tnow, &tin);
					if (TVXLTY(tmout, &tnow)) {
						if (bestcc)
							goto fnd;
						cc = 0;
						if (!TVISSET(tmout)) {
							if ((cc = mroute(0, 0, 0, tmout)) <= 0)
								goto done;
						} else
							goto done;
					} else {
						TVXSUBY(&tnow, tmout, &tnow);
						if ((cc = mroute(0, 0, 0, &tnow)) < 0)
							goto done;
					}

				} else {
					if ((cc = mroute(0, 0, 0, (struct timeval *)0)) < 0)
						goto done;
				}
				up = up->m_link;
			}

			if ((cc = recv_match(up->m_mid, tid, tag)) < 0)
				goto done;
			if (cc == 1) {
				bestup = up;
				break;
			}
			if (cc > bestcc) {
				bestcc = cc;
				bestup = up;
			}
		}

fnd:
		LISTDELETE(bestup, m_link, m_rlink);
		bestup->m_flag &= ~MM_UPACK;
		if (!(cc = pvm_setrbuf(bestup->m_mid)))
			cc = bestup->m_mid;
	}

done:
	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_TRECV,TEV_EVENT_EXIT)) {
			int nb, mc, src;
			TEV_PACK_INT( TEV_DID_MB, TEV_DATA_SCALAR, &cc, 1, 1 );
			if (cc > 0)
				pvm_bufinfo(cc, &nb, &mc, &src);
			else
				nb = mc = src = -1;
			TEV_PACK_INT( TEV_DID_MNB, TEV_DATA_SCALAR, &nb, 1, 1 );
			TEV_PACK_INT( TEV_DID_MC, TEV_DATA_SCALAR, &mc, 1, 1 );
			TEV_PACK_INT( TEV_DID_MCX, TEV_DATA_SCALAR,
					&pvmmyctx, 1, 1 );
			TEV_PACK_INT( TEV_DID_SRC, TEV_DATA_SCALAR, &src, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_trecv", cc);
	return cc;
}


char *
pvm_version()
{
	static char *_pvm_version_str = PVM_VER;
	return(_pvm_version_str);
}


int
pvm_reg_rm(hip)
	struct pvmhostinfo **hip;
{
	int old_sched;
	int cc;
	int sbf;
	int rbf;
	/* char buf[256]; XXX static limit, argh (Not Any More! :-) JAK */
	static struct pvmhostinfo *hin = 0;
	static int mbindex = -1;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_REG_RM,TEV_EVENT_ENTRY)) {
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);

		if (pvmschedtid)
			cc = msendrecv(pvmschedtid, SM_SCHED, PvmBaseContext);
		else
			cc = msendrecv(TIDPVMD, TM_SCHED, SYSCTX_TM);
		if (cc > 0) {
			pvm_upkint(&cc, 1, 1);
			if (cc >= 0) {
				if (hin) {
					PVM_FREE(hin->hi_name);
					PVM_FREE(hin->hi_arch);

				} else
					hin = TALLOC(1, struct pvmhostinfo, "hi");
				pvm_upkint(&hin->hi_tid, 1, 1);
				pvmupkstralloc(&(hin->hi_name));
				pvmupkstralloc(&(hin->hi_arch));
				pvm_upkint(&hin->hi_speed, 1, 1);
				if (hip)
					*hip = hin;

				if ( mbindex >= 0 )
					pvm_delinfo( PVMRMCLASS, mbindex, PvmMboxDefault );
				pvm_setsbuf(pvm_mkbuf(PvmDataDefault));
				pvm_pkint(&pvmmytid,1,1);
				mbindex = pvm_putinfo( PVMRMCLASS, pvm_getsbuf(),
					PvmMboxMultiInstance );
			}
			pvm_freebuf(pvm_setrbuf(rbf));

		} else
			pvm_setrbuf(rbf);
		pvm_freebuf(pvm_setsbuf(sbf));
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_REG_RM,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_reg_rm", cc);
	return cc;
}


int
pvm_reg_tasker()
{
	static int imit = 0;		/* i'm the tasker */
	static int mbindex = -1;	/* mbox index */

	int cc;
	int sbf;
	int rbf;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_REG_TASKER,TEV_EVENT_ENTRY)) {
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);

		cc = imit ? 0 : 1;
		pvm_pkint(&cc, 1, 1);
		cc = msendrecv(TIDPVMD, TM_TASKER, SYSCTX_TM);
		if (cc > 0) {
			pvm_upkint(&cc, 1, 1);
			if (!cc) {
				imit = !imit;
				if ( imit ) {
					pvm_setsbuf(pvm_mkbuf(PvmDataDefault));
					pvm_pkint(&pvmmytid,1,1);
					mbindex = pvm_putinfo( PVMTASKERCLASS,
						pvm_getsbuf(), PvmMboxMultiInstance );
				} else if ( mbindex >= 0 ) {
					if ( pvm_delinfo( PVMTASKERCLASS, mbindex,
							PvmMboxDefault ) >= 0 ) {
						mbindex = -1;
					}
				}
			}
			pvm_freebuf(pvm_setrbuf(rbf));

		} else
			pvm_setrbuf(rbf);
		pvm_freebuf(pvm_setsbuf(sbf));
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_REG_TASKER,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_reg_tasker", cc);
	return cc;
}


int
pvm_reg_hoster()
{
	static int imit = 0;		/* i'm the hoster */
	static int mbindex = -1;	/* mbox index */

	int cc;
	int sbf;
	int rbf;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_REG_HOSTER,TEV_EVENT_ENTRY)) {
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);

		cc = imit ? 0 : 1;
		pvm_pkint(&cc, 1, 1);
		cc = msendrecv(TIDPVMD, TM_HOSTER, SYSCTX_TM);
		if (cc > 0) {
			pvm_upkint(&cc, 1, 1);
			if (!cc) {
				imit = !imit;
				if ( imit ) {
					pvm_setsbuf(pvm_mkbuf(PvmDataDefault));
					pvm_pkint(&pvmmytid,1,1);
					mbindex = pvm_putinfo( PVMHOSTERCLASS,
						pvm_getsbuf(), PvmMboxMultiInstance );
				} else if ( mbindex >= 0 ) {
					if ( pvm_delinfo( PVMHOSTERCLASS, mbindex,
							PvmMboxDefault ) >= 0 ) {
						mbindex = -1;
					}
				}
			}
			pvm_freebuf(pvm_setrbuf(rbf));

		} else
			pvm_setrbuf(rbf);
		pvm_freebuf(pvm_setsbuf(sbf));
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_REG_HOSTER,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_reg_hoster", cc);
	return cc;
}


int
pvm_reg_tracer( tctx, ttag, octx, otag, tmask, tbuf, topt )
	int tctx;
	int ttag;
	int octx;
	int otag;
	Pvmtmask tmask;
	int tbuf;
	int topt;
{
	static int imit = 0;		/* i'm the tracer */
	static int mbindex = -1;	/* mbox index */

	int cc;
	int sbf;
	int rbf;
	int x;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_REG_TRACER,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_TRC, TEV_DATA_SCALAR, &tctx, 1, 1 );
			TEV_PACK_INT( TEV_DID_TRT, TEV_DATA_SCALAR, &ttag, 1, 1 );
			TEV_PACK_INT( TEV_DID_TRX, TEV_DATA_SCALAR, &octx, 1, 1 );
			TEV_PACK_INT( TEV_DID_TRO, TEV_DATA_SCALAR, &otag, 1, 1 );
			TEV_PACK_STRING( TEV_DID_TRM, TEV_DATA_SCALAR,
				tmask, 1, 1 );
			TEV_PACK_INT( TEV_DID_TRB, TEV_DATA_SCALAR, &tbuf, 1, 1 );
			TEV_PACK_INT( TEV_DID_TRL, TEV_DATA_SCALAR, &topt, 1, 1 );
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);

		cc = imit ? 0 : 1;
		pvm_pkint(&cc, 1, 1);
		if ( cc ) {
			pvm_pkint(&tctx, 1, 1);
			pvm_pkint(&ttag, 1, 1);
			pvm_pkint(&octx, 1, 1);
			pvm_pkint(&otag, 1, 1);
			pvm_pkstr(tmask);
			pvm_pkint(&tbuf, 1, 1);
			pvm_pkint(&topt, 1, 1);
		}
		cc = msendrecv(TIDPVMD, TM_TRACER, SYSCTX_TM);
		if (cc > 0) {
			pvm_upkint(&cc, 1, 1);
			if (!cc) {
				imit = !imit;
				if ( imit ) {
					pvm_setsbuf(pvm_mkbuf(PvmDataDefault));
					pvm_pkint(&pvmmytid,1,1);
					pvm_pkint(&tctx, 1, 1);
					pvm_pkint(&ttag, 1, 1);
					pvm_pkint(&octx, 1, 1);
					pvm_pkint(&otag, 1, 1);
					pvm_pkstr(tmask);
					pvm_pkint(&tbuf, 1, 1);
					pvm_pkint(&topt, 1, 1);
					mbindex = pvm_putinfo( PVMTRACERCLASS,
						pvm_getsbuf(), PvmMboxDefault );
				} else if ( mbindex >= 0 ) {
					if ( pvm_delinfo( PVMTRACERCLASS, mbindex,
							PvmMboxDefault ) >= 0 ) {
						mbindex = -1;
					}
				}
			}
			pvm_freebuf(pvm_setrbuf(rbf));

		} else
			pvm_setrbuf(rbf);
		pvm_freebuf(pvm_setsbuf(sbf));
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_REG_TRACER,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_reg_tracer", cc);
	return cc;
}


/*	pvm_hostsync()
*
*	Get time of day clock from remote host.
*	Returns current time on remote host,
*	difference between local clock and remote host clock.
*
*	Note the delta time is a 2s-compl./1000000-compl. signed timeval.
*	Positive values are normal, negative ones are f.e.:
*		-1 uSec  = -1,999999
*		-1 Sec   = -1,000000
*		-1.1 Sec = -2,999000
*/

int
pvm_hostsync(host, clk, delta)
	int host;				/* pvmd tid of host */
	struct timeval *clk;	/* current time on host */
	struct timeval *delta;	/* time relative to local clock */
{
	int cc;
	int sbf, rbf;
	struct timeval myta, mytb, remt;
	int i[2];

	if (!(cc = BEATASK)) {
		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);
		pvm_pkint(&host, 1, 1);

		gettimeofday(&myta, (struct timezone *) NULL);
		if ((cc = msendrecv(TIDPVMD, TM_HOSTSYNC,SYSCTX_TM)) > 0) {
			gettimeofday(&mytb, (struct timezone *) NULL);

			pvm_upkint(&cc, 1, 1);
			if (cc >= 0) {
				cc = 0;
				pvm_upkint(i, 2, 1);
				remt.tv_sec = i[0];
				remt.tv_usec = i[1];

				if (clk)
					*clk = remt;

				if (delta) {
					TVDIVN(&myta, &myta, 2);
					TVDIVN(&mytb, &mytb, 2);
					TVXADDY(&myta, &myta, &mytb);
					TVXSUBY(&myta, &myta, &remt);
					*delta = myta;
				}
			}
			pvm_freebuf(pvm_setrbuf(rbf));
		} else
			pvm_setrbuf(rbf);
		pvm_freebuf(pvm_setsbuf(sbf));
	}

	if (cc < 0)
		lpvmerr("pvm_host_sync", cc);
	return cc;
}


/*	pvm_gettmask()
*
*	Get our (or child) trace mask.
*/

int
pvm_gettmask(who, tmask)
	int who;
	Pvmtmask tmask;
{
	int i;
	char *tm = 0;

	if (who == PvmTaskChild)
		tm = pvmctrc.tmask;
	else if (who == PvmTaskSelf)
		tm = pvmtrc.tmask;

	if (!tm)
		return lpvmerr("pvm_gettmask", PvmBadParam);
	BCOPY(tm, tmask, TEV_MASK_LENGTH);
	return PvmOk;
}


/*	pvm_settmask()
*
*	Set our (or child's) trace mask.
*/

int
pvm_settmask(who, tmask)
	int who;
	Pvmtmask tmask;
{
	int i;
	char *tm = 0;

	if (who == PvmTaskChild)
		tm = pvmctrc.tmask;
	else if (who == PvmTaskSelf)
		tm = pvmtrc.tmask;

	if (!tm)
		return lpvmerr("pvm_settmask", PvmBadParam);

	BCOPY(tmask, tm, TEV_MASK_LENGTH);
	return PvmOk;
}


int
pvm_archcode(arch)
	char *arch;
{
	struct pvmhostinfo *hlist;
	int sbf, rbf, cc;
	int nhost, narch;
	int i;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_ARCHCODE,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_AN, TEV_DATA_SCALAR,
				arch ? arch : "", 1, 1 );
			TEV_FIN;
		}
	}

	if (!arch)
		cc = PvmBadParam;

	else
	{
		/* Go get pvm_config() info...  :-Q :-Q :-Q */
		/* (can't use pvm_config() directly, as stomps */
		/* hostinfo structure...  Damn. */

		if (!(cc = BEATASK)) {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			if (pvmschedtid)
				cc = msendrecv(pvmschedtid, SM_CONFIG, PvmBaseContext);
			else
				cc = msendrecv(TIDPVMD, TM_CONFIG, SYSCTX_TM);
			if (cc > 0) {
				pvm_upkint(&nhost, 1, 1);
				pvm_upkint(&narch, 1, 1);
				hlist = TALLOC(nhost, struct pvmhostinfo, "hi");
				for (i = 0; i < nhost; i++) {
					pvm_upkint(&hlist[i].hi_tid, 1, 1);
					pvmupkstralloc(&(hlist[i].hi_name));
					pvmupkstralloc(&(hlist[i].hi_arch));
					pvm_upkint(&hlist[i].hi_speed, 1, 1);
					pvm_upkint(&hlist[i].hi_dsig, 1, 1);
				}
				pvm_freebuf(pvm_setrbuf(rbf));
			}
			pvm_freebuf(pvm_setsbuf(sbf));
			pvm_setrbuf(rbf);

			cc = PvmNotFound;

			for ( i=0 ; i < nhost ; i++ ) {
				if ( !strcmp(hlist[i].hi_arch, arch) ) {
					cc = hlist[i].hi_dsig;
					break;
				}
			}

			while (nhost-- > 0) {
				PVM_FREE(hlist[nhost].hi_name);
				PVM_FREE(hlist[nhost].hi_arch);
			}
			PVM_FREE(hlist);
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_ARCHCODE,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_AC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_archcode", cc);
	
	return( cc );
}


int
pvm_newcontext()
{
	int sbf, rbf, cc;
	int mid = -1;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_NEWCONTEXT,TEV_EVENT_ENTRY)) {
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);
		cc = 0;
		pvm_pkint(&cc, 1, 1);
		if ((cc = msendrecv(TIDPVMD, TM_CONTEXT, SYSCTX_TM)) > 0) {
			pvm_upkint(&cc, 1, 1);
			pvm_freebuf(pvm_setrbuf(rbf));

		} else
			pvm_setrbuf(rbf);
		pvm_freebuf(pvm_setsbuf(sbf));
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_NEWCONTEXT,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CXN, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_newcontext", cc);
	return cc;
}


int
pvm_freecontext(cid)
	int cid;
{
	int sbf, rbf, cc;
	int mid = -1;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_FREECONTEXT,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_CXF, TEV_DATA_SCALAR, &cid, 1, 1 );
			TEV_FIN;
		}
	}

	if (!(cc = BEATASK)) {
		sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
		rbf = pvm_setrbuf(0);
		pvm_pkint(&cid, 1, 1);
		if ((cc = msendrecv(TIDPVMD, TM_CONTEXT, SYSCTX_TM)) > 0) {
			pvm_upkint(&cc, 1, 1);
			pvm_freebuf(pvm_setrbuf(rbf));

		} else
			pvm_setrbuf(rbf);
		pvm_freebuf(pvm_setsbuf(sbf));
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_FREECONTEXT,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_freecontext", cc);
	return cc;
}


int
pvm_getcontext()
{
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_GETCONTEXT,TEV_EVENT_ENTRY)) {
			TEV_FIN;
		}
	}

	/* Yep, overkill... */

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_GETCONTEXT,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CXC, TEV_DATA_SCALAR,
				&pvmmyctx, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	return pvmmyctx;
}


int
pvm_setcontext(newctx)
	int newctx;
{
	int c;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_SETCONTEXT,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_CXS, TEV_DATA_SCALAR, &newctx, 1, 1 );
			TEV_FIN;
		}
	}

	c = pvmmyctx;
	pvmmyctx = newctx;

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_SETCONTEXT,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &c, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	return c;
}

/*
*	pvm_addmhf()
*
*  add message handler function
*
*  function returns:
*	index ( >= 0 ) message handler
*			- can be used to delete the handler via pvm_delmhf()
*	PvmExists - can't insert as handler already exists
*			- search by (tag, ctx, src) including "wild-cards" (-1)
*
*/
int
pvm_addmhf(src, tag, ctx, f)
	int src, tag, ctx;			/* message source, context, tag */
#ifdef  IMA_SCO
	int (*f)(int);				/* handler function */
#else
	int (*f)();				/* handler function */
#endif
{
	int i;		/* temp local */
	int hand;	/* index into handles[] array -->> internal use only */
				/* - not for user */
	int mhid;	/* message handler index -->> into dhandles[] */
				/* -->> give to user */
	int exists = 0;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_ADDMHF,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_RST, TEV_DATA_SCALAR, &src, 1, 1 );
			TEV_PACK_INT( TEV_DID_RMC, TEV_DATA_SCALAR, &tag, 1, 1 );
			TEV_PACK_INT( TEV_DID_RCX, TEV_DATA_SCALAR, &ctx, 1, 1 );
			TEV_FIN;
		}
	}

	/*
	*  confirm that does not already exist within "handles"
	*  this includes "wild-card" options in both directions too...
	*
	*  search from most recently added message handler to system
	*  added message handlers
	*/
	for ( i=nhandles-1 ; i >= 0 && !exists ; i-- ){
		if ((handles[i].header.tag == -1
				|| handles[i].header.tag == tag || tag == -1)
		&& (handles[i].header.ctx == -1
				|| handles[i].header.ctx == ctx || ctx == -1)
		&& (handles[i].header.src == -1
				|| handles[i].header.src == src || src == -1))
		{
			exists++;
		}
	}

	/*
	*  see if there are any already on free list
	*  -  use existing if on free list
	*  -  create new if none free - two scenarios:
	*       1. may be initial message handlers
	*       2. may be additional message handlers and lists just full
	*
	*  note: ndhandles never decreases - thus if less than nhandles,
	*  must be some free slots...
	*/
	if ( exists )
			mhid = PvmExists;
	else if (ndhandles > nhandles){
		/*
		*  there exist some free slots
		*/
		mhid = fl_dhandles;		/* take from head of free list */
		nhandles++;				/* incr actual # of active headers */

		/*
		*  move next one to head of free list
		*  if tail of list - will move "tail marker" (-1) to
		*  fl_dhandles to indicte empty list
		*/
		fl_dhandles = dhandles[mhid].mhid;

		/*
		*  fill the lists now...
		*/

		dhandles[mhid].mhid = mhid;		/* set to self */

		/* dhandles[mhid].handle	no change here as should be next */
		/* contiguous on handles[] */

		hand = dhandles[mhid].handle;	/* set to index -> handles[] */
		handles[hand].mhid = mhid;		/* set to corresponding mhid */
		handles[hand].header.tag = tag;
		handles[hand].header.ctx = ctx;
		handles[hand].header.src = src;
		handles[hand].f = f;	/* sonnofabeech! */
	}
	else{
		/* no free slots available - will have to allocate more slots...
		*  two scenarios for this:
		*    1. first time adding message handlers - none ever
		*           allocated.
		*    2. all presently allocated are filled and active - but
		*           been here before.
		*
		*  note: since no free slots, must have case of:
		*           ndhandles == nhandles
		*
		*  ndhandles : is the "high-water" mark as it is never decreased
		*  nhandles  : indicates the actual number of active handles
		*/
		if (ndhandles == 0){
			/* first time here - allocate new memory... */
			dhandles = TALLOC(++ndhandles, struct dhandler, "dhandles");
			handles = TALLOC(++nhandles, struct mhandler, "mhandle");
		}
		else{
			/* been here! - reallocate more space... */
			dhandles = TREALLOC(dhandles, ++ndhandles, struct dhandler);
			handles = TREALLOC(handles, ++nhandles, struct mhandler);
		}

		mhid = ndhandles - 1;		/* set index into dhandles */

		/*
		*  fill the lists now...
		*/

		dhandles[mhid].mhid = mhid;		/* set to self */
		dhandles[mhid].handle = mhid;	/* set same since lists full */

		handles[mhid].mhid = mhid;
		handles[mhid].header.tag = tag;
		handles[mhid].header.ctx = ctx;
		handles[mhid].header.src = src;
		handles[mhid].f = f;	/* sonnofabeech! */
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_ADDMHF,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_MHI, TEV_DATA_SCALAR, &mhid, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (mhid < 0)
		lpvmerr("pvm_addmhf", mhid);
	return mhid;	/* return message handler */
					/* -->> index into dhandles[] */
} /* pvm_addmhf */


/*
*	pvm_delmhf()
*
*  delete message handler function
*
*  function returns:
*	PvmBadParam - negative mhid value
*	PvmNotFound - mhid not found in list
*			- possibly deleted before...
*			- possibly never existed (access past end of list index)
*			- return PvmNotFound but no error message as is normal
*                 operation...
*	PvmOk
*/
int
pvm_delmhf(mhid)
	int mhid;			/* message handler index */
{
	char *errstr;
	int htoid;			/* handle - moved to   - id location */
	int hfrid;			/* handle - moved from - id location */
	int rc = 0;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_DELMHF,TEV_EVENT_ENTRY)) {
			TEV_PACK_INT( TEV_DID_MHI, TEV_DATA_SCALAR, &mhid, 1, 1 );
			TEV_FIN;
		}
	}

	/*
	*  check incomming parameter at lower and upper boundary
	*	- can't have negative mhid values
	*	- too high an index - mhid entry does not exist
	*/
	if (mhid < 0) { /* too low */
		errstr = "pvm_delmhf";
		rc = PvmBadParam;
	}
	else if (mhid >= ndhandles) { /* too high */
		errstr = "(mhid >= ndhandles) pvm_delmhf";
		rc = PvmNotFound;
	}

	/*
	*  make sure is not already on free list - can only delete active
	*  mhid entries
	*
	*  confirm active by:
	*    since handles is contiguous at low order indices, thus any
	*    entry in dhandles[x].handle less-than nhandles is an active
	*    entry and may be deleted
	*/
	if ( rc >= 0 ) {
		if ( dhandles[mhid].handle < nhandles ) {
			/*
			*  this one's active - delete it
			*/

			nhandles--;		/* reduce # of active handles[] entries */
			htoid = dhandles[mhid].handle;	/* handle - moved to */
											/* -id location */
			hfrid = nhandles;		/* handle - moved from - id loc */

			/* Don't Spank List if Last Entry...  D-Oh! */
			if ( htoid != hfrid )
			{
				/*
				*  move the last "active" handle[] entry up to "deleted"
				*  location
				*/

				handles[htoid] = handles[hfrid];	/* the move */

				/* unnecessary?! handles[hfrid].mhid = htoid; */
				/* ("back-link" ptr adjust?) */

				/*
				*  adjust dhandles[] to point to
				*    1. the moved "up" entry
				*    2. the "deleted" entry
				*/

				/* 1. the moved "up" entry */
				dhandles[handles[htoid].mhid].handle = htoid;

				/* 2. the "deleted" entry */
				dhandles[mhid].handle = hfrid;
			}

			/*
			*  put the "freed" dhandle entry (mhid value) on head of
			*  the free list
			*/

			/* link this to previous free list */
			dhandles[mhid].mhid = fl_dhandles;

			fl_dhandles = mhid;		/* put this one on head of list */
		}
		else {
			/* this one is already on free list - not active entry */
			errstr = "pvm_delmhf";
			rc = PvmNotFound;
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_DELMHF,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &rc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (rc < 0)
		lpvmerr(errstr, rc);
	return( rc );

} /* pvm_delmhf */


int
pvm_putinfo(name, mid, flags)
	char *name;			/* class name */
	int mid;			/* message to store */
	int flags;			/* options */
{
	int index = -1;
	int sbf, rbf, cc;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_PUTINFO,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_CN, TEV_DATA_SCALAR,
				name ? name : "", 1, 1 );
			TEV_PACK_INT( TEV_DID_CI, TEV_DATA_SCALAR, &index, 1, 1 );
			TEV_PACK_INT( TEV_DID_CF, TEV_DATA_SCALAR, &flags, 1, 1);
			TEV_PACK_INT( TEV_DID_CD, TEV_DATA_SCALAR, &mid, 1, 1 );
			TEV_FIN;
		}
	}

	if (!name || !*name || index < -1) {
		cc = PvmBadParam;

	} else {
		if (!(cc = BEATASK)) {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			cc = TMDB_PUT;
			pvm_pkint(&cc, 1, 1);
			pvm_pkint(&pvmmytid, 1, 1);
			pvm_pkstr(name);
			pvm_pkint(&index, 1, 1);
			pvm_pkint(&flags, 1, 1);
			pvm_pkmesg(mid);
			if ((cc = msendrecv(TIDPVMD, TM_DB, SYSCTX_TM)) > 0) {
				pvm_upkint(&cc, 1, 1);
				pvm_freebuf(pvm_setrbuf(rbf));

			} else
				pvm_setrbuf(rbf);
			pvm_freebuf(pvm_setsbuf(sbf));
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_PUTINFO,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		if (cc != PvmDenied && cc != PvmExists)
			lpvmerr("pvm_putinfo", cc);
		else
			pvm_errno = cc;
	return cc;
}


int
pvm_recvinfo(name, index, flags)
	char *name;		/* class name */
	int index;		/* req class index or -1 for any */
	int flags;		/* options */
{
	int sbf, cc;
	int mid = -1;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_GETINFO,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_CN, TEV_DATA_SCALAR,
				name ? name : "", 1, 1 );
			TEV_PACK_INT( TEV_DID_CI, TEV_DATA_SCALAR, &index, 1, 1 );
			TEV_PACK_INT( TEV_DID_CF, TEV_DATA_SCALAR, &flags, 1, 1 );
			TEV_FIN;
		}
	}

	if (!name || !*name || index < 0) {
		cc = PvmBadParam;

	} else {
		if (!(cc = BEATASK)) {
			if (pvmrbuf)
				umbuf_free(pvmrbuf);
			pvmrbuf = 0;

			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			cc = TMDB_GET;
			pvm_pkint(&cc, 1, 1);
			pvm_pkint(&pvmmytid, 1, 1);
			pvm_pkstr(name);
			pvm_pkint(&index, 1, 1);
			pvm_pkint(&flags, 1, 1);
			if ((cc = msendrecv(TIDPVMD, TM_DB, SYSCTX_TM)) > 0) {
				pvm_upkint(&cc, 1, 1);
				if (cc >= 0) {
					mid = pvm_upkmesg();
					pvm_freebuf(pvm_setrbuf(mid));
				}
			}
			pvm_freebuf(pvm_setsbuf(sbf));
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_GETINFO,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_PACK_INT( TEV_DID_CR, TEV_DATA_SCALAR, &mid, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if ( cc < 0 ) {
		if ( cc != PvmNotFound )
			lpvmerr("pvm_recvinfo", cc);
		else
			pvm_errno = cc;
		return cc;
	}
	else
		return mid;
}


int
pvm_delinfo(name, index, flags)
	char *name;		/* class name */
	int index;		/* class index or -1 for all */
	int flags;		/* options */
{
	int sbf, rbf, cc;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_DELINFO,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_CN, TEV_DATA_SCALAR,
				name ? name : "", 1, 1 );
			TEV_PACK_INT( TEV_DID_CI, TEV_DATA_SCALAR, &index, 1, 1 );
			TEV_PACK_INT( TEV_DID_CF, TEV_DATA_SCALAR, &flags, 1, 1 );
			TEV_FIN;
		}
	}

	if (!name || !*name || index < 0) {
		cc = PvmBadParam;

	} else {
		if (!(cc = BEATASK)) {
			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			cc = TMDB_REMOVE;
			pvm_pkint(&cc, 1, 1);
			pvm_pkint(&pvmmytid, 1, 1);
			pvm_pkstr(name);
			pvm_pkint(&index, 1, 1);
			pvm_pkint(&flags, 1, 1);
			if ((cc = msendrecv(TIDPVMD, TM_DB, SYSCTX_TM)) > 0) {
				pvm_upkint(&cc, 1, 1);
				pvm_freebuf(pvm_setrbuf(rbf));

			} else
				pvm_setrbuf(rbf);
			pvm_freebuf(pvm_setsbuf(sbf));
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_DELINFO,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		if (cc != PvmDenied && cc != PvmNotFound)
			lpvmerr("pvm_delinfo", cc);
		else
			pvm_errno = cc;
	return cc;
}


int
pvm_getmboxinfo(pattern, nclasses, classes)
	char *pattern;					/* class name */
	int *nclasses;					/* number of classes returned */
	struct pvmmboxinfo **classes;	/* name list returned */
{
	static struct pvmmboxinfo *clist = (struct pvmmboxinfo *) NULL;
	static int nclist = 0;

	int sbf, rbf, cc;
	int i, j;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_GETMBOXINFO,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_CN, TEV_DATA_SCALAR,
				pattern ? pattern : "", 1, 1 );
			TEV_FIN;
		}
	}

	if ( !pattern )
		pattern = "";

	if ( clist ) {
		for ( i=0 ; i < nclist ; i++ ) {
			if ( clist[i].mi_name )
				PVM_FREE( clist[i].mi_name );
			if ( clist[i].mi_indices )
				PVM_FREE( clist[i].mi_indices );
			if ( clist[i].mi_owners )
				PVM_FREE( clist[i].mi_owners );
			if ( clist[i].mi_flags )
				PVM_FREE( clist[i].mi_flags );
		}
		PVM_FREE( clist );
		clist = (struct pvmmboxinfo *) NULL;
		nclist = 0;
	}

	if ( !(cc = BEATASK) )
	{
		sbf = pvm_setsbuf( pvm_mkbuf( PvmDataFoo ) );
		rbf = pvm_setrbuf( 0 );
		cc = TMDB_NAMES;
		pvm_pkint( &cc, 1, 1 );
		pvm_pkint( &pvmmytid, 1, 1 );
		pvm_pkstr( pattern );
		cc = 0;
		pvm_pkint( &cc, 1, 1 );
		pvm_pkint( &cc, 1, 1 );
		if ( (cc = msendrecv( TIDPVMD, TM_DB, SYSCTX_TM )) > 0 ) {
			pvm_upkint( &cc, 1, 1 );
			if ( cc >= 0 ) {
				pvm_upkint( &nclist, 1, 1 );
				clist = TALLOC( nclist, struct pvmmboxinfo, "classes" );
				for ( i=0 ; i < nclist ; i++ ) {
					pvmupkstralloc( &(clist[i].mi_name) );
					pvm_upkint( &(clist[i].mi_nentries), 1, 1 );
					clist[i].mi_indices = TALLOC( clist[i].mi_nentries,
							int, "class_indices" );
					clist[i].mi_owners = TALLOC( clist[i].mi_nentries,
							int, "class_owners" );
					clist[i].mi_flags = TALLOC( clist[i].mi_nentries,
							int, "class_flags" );
					for ( j=0 ; j < clist[i].mi_nentries ; j++ ) {
						pvm_upkint( &(clist[i].mi_indices[j]), 1, 1 );
						pvm_upkint( &(clist[i].mi_owners[j]), 1, 1 );
						pvm_upkint( &(clist[i].mi_flags[j]), 1, 1 );
					}
				}
				if (classes)
					*classes = clist;
				if (nclasses)
					*nclasses = nclist;
			}
			pvm_freebuf(pvm_setrbuf(rbf));
		}
		
		else
			pvm_setrbuf(rbf);

		pvm_freebuf(pvm_setsbuf(sbf));
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_GETMBOXINFO,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_getmboxinfo", cc);
	return cc;
}


int
pvm_siblings(tidsp)
	int **tidsp;
{
	static int pvmsiblings_me[1];
	int cc = PvmParentNotSet;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_SIBLINGS,TEV_EVENT_ENTRY)) {
			TEV_FIN;
		}
	}

	if (pvmnsibs == -1)  /* only call pvm_parent if we haven't gotten sibs */
		cc = pvm_parent();

	if (cc > 0 || cc == PvmParentNotSet) 
	{
		/* wait for pvmnsibs to be set by spawning program */ 
		while (pvmnsibs == -1) {
			cc = mroute(0, 0, 0, (struct timeval *)0);
			if (cc < 0)
				break;
		}
		if (pvmnsibs != -1) {
			cc = pvmnsibs;
			*tidsp = pvmsibtids;
		}

	} else 
		if (cc == PvmNoParent)  /* I am my only sibling */
		{
			cc = 1;
			pvmsiblings_me[0] = pvmmytid;
			*tidsp = pvmsiblings_me; 
		}
			
			

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_SIBLINGS,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_SIB, TEV_DATA_ARRAY,
				pvmsibtids, cc, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		lpvmerr("pvm_siblings", cc);
	return cc;
}


int
pvm_export(name)
	char *name;
{
	char *vn = "PVM_EXPORT";
	char *e;
	char *p, *q;
	int l;

	if (!name[0])
		goto done;

	if (e = getenv(vn)) {
		p = e;
		while (*p) {
			while (*p == ':')
				p++;
			q = p;
			while (*q && *q != ':')
				q++;
			l = q - p;
			if (strlen(name) == l && !strncmp(name, p, l))
				goto done;
			p = q;
		}
		p = TALLOC(strlen(vn) + strlen(e) + strlen(name) + 3, char, "str");
		strcpy(p, vn);
		strcat(p, "=");
		strcat(p, e);
		if (e[0])
			strcat(p, ":");
		strcat(p, name);
		pvmputenv(p);

	} else {
		e = TALLOC(strlen(vn) + strlen(name) + 2, char, "str");
		strcpy(e, vn);
		strcat(e, "=");
		strcat(e, name);
		pvmputenv(e);
	}

done:
/*
	e = getenv(vn);
	pvmlogprintf("pvm_export() %s=%s\n", vn, e);
*/
	return 0;
}


int
pvm_unexport(name)
	char *name;
{
	char *vn = "PVM_EXPORT";
	char *e, *enew;
	char *p, *q;
	int l;

	if (!name[0])
		goto done;

	if (e = getenv(vn)) {
		p = e;
		while (*p) {
			while (*p == ':')
				p++;
			q = p;
			while (*q && *q != ':')
				q++;
			l = q - p;
			if (strlen(name) == l && !strncmp(name, p, l)) {
				if (*q == ':')
					q++;
				else if (p > e && *(p - 1) == ':')
					p--;
				enew = TALLOC(strlen(vn) + (p - e) + strlen(q) + 2, char, "str");
				strcpy(enew, vn);
				strcat(enew, "=");
				strncat(enew, e, p - e);
				strcat(enew, q);
				pvmputenv(enew);
				goto done;
			}
			p = q;
		}
	}

done:
/*
	e = getenv(vn);
	pvmlogprintf("pvm_unexport() %s=%s\n", vn, e);
*/
	return 0;
}


/*	pvmreset()
*
*	One handy routine for cleaning up the virtual machine.
*	Used by "pvm" console, XPVM and whoever else is in a
*	tidy mood.  Not necessarily for public consumption...
*/

int
pvmreset( mytid, killtasks, class, index )
int mytid;
int killtasks;
char *class;
int index;
{
	struct pvmtaskinfo *tip;
	int ntask;

	int *noresets = (int *) NULL;
	int nnr = 0;

	int sbf, rbf;
	int found;
	int i, j;
	int cc;

	if ( !pvm_tasks( 0, &ntask, &tip ) && ntask > 0 )
	{
		pvm_getnoresets( &noresets, &nnr );

		for ( i=0 ; i < ntask && killtasks ; i++ )
		{
			for ( j=0, found=0 ; j < nnr && !found ; j++ )
				if ( noresets[j] == tip[i].ti_tid )
					found++;

			if ( !found && tip[i].ti_tid && tip[i].ti_tid != mytid )
				pvm_kill(tip[i].ti_tid);
		}
	}

	/* XXX this is gnasty... */
	/* while ((i = pvm_lookup("pvmgs", -1, &j)) >= 0) */
		/* pvm_delete("pvmgs", i); */

	/* Tell Master PVMD to clean up mboxes... */

	sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
	rbf = pvm_setrbuf(0);
	cc = TMDB_RESET;
	pvm_pkint(&cc, 1, 1);
	pvm_pkint(&pvmmytid, 1, 1);
	pvm_pkstr(class ? class : "");
	cc = 0;
	pvm_pkint(&index, 1, 1);
	pvm_pkint(&killtasks, 1, 1);
	pvm_pkint(&nnr, 1, 1);
	for ( i=0 ; i < nnr ; i++ )
		pvm_pkint(&(noresets[i]), 1, 1);
	if ((cc = msendrecv(TIDPVMD, TM_DB, SYSCTX_TM)) > 0) {
		pvm_upkint(&cc, 1, 1);
		pvm_freebuf(pvm_setrbuf(rbf));
	} else
		pvm_setrbuf(rbf);
	pvm_freebuf(pvm_setsbuf(sbf));

	return 0;
}


/***************************************************************
 **  backwards compat functions: built on new mbox interface  **
 **                                                           **
 ***************************************************************/

int
pvm_insert(name, req, data)
	char *name;		/* class name */
	int req;		/* requested class index or -1 for any */
	int data;
{
	int sbf, rbf, cc;
	int flags;
	int mid;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_INSERT,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_CN, TEV_DATA_SCALAR,
				name ? name : "", 1, 1 );
			TEV_PACK_INT( TEV_DID_CI, TEV_DATA_SCALAR, &req, 1, 1 );
			TEV_PACK_INT( TEV_DID_CD, TEV_DATA_SCALAR, &data, 1, 1 );
			TEV_FIN;
		}
	}

	if (!name || !*name || req < -1) {
		cc = PvmBadParam;

	} else {
		if (!(cc = BEATASK)) {

			flags = PvmMboxDefault
				| PvmMboxMultiInstance
				| PvmMboxPersistent;

			mid = pvm_mkbuf(PvmDataFoo);
			sbf = pvm_setsbuf(mid);
			pvm_pkint(&data, 1, 1);

			pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			rbf = pvm_setrbuf(0);
			cc = TMDB_PUT;
			pvm_pkint(&cc, 1, 1);
			pvm_pkint(&pvmmytid, 1, 1);
			pvm_pkstr(name);
			pvm_pkint(&req, 1, 1);
			pvm_pkint(&flags, 1, 1);
			pvm_pkmesg(mid);
			if ((cc = msendrecv(TIDPVMD, TM_DB, SYSCTX_TM)) > 0) {
				pvm_upkint(&cc, 1, 1);
				pvm_freebuf(pvm_setrbuf(rbf));

			} else
				pvm_setrbuf(rbf);
			pvm_freebuf(pvm_setsbuf(sbf));
			pvm_freebuf(mid);
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_INSERT,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		if (cc != PvmDupEntry)
			lpvmerr("pvm_insert", cc);
		else
			pvm_errno = cc;
	return cc;
}


int
pvm_lookup(name, req, datap)
	char *name;		/* class name */
	int req;		/* req class index or -1 for any */
	int *datap;		/* data return */
{
	int sbf, rbf, cc;
	int flags;
	int mid;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_LOOKUP,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_CN, TEV_DATA_SCALAR,
				name ? name : "", 1, 1 );
			TEV_PACK_INT( TEV_DID_CI, TEV_DATA_SCALAR, &req, 1, 1);
			TEV_FIN;
		}
	}

	if (!name || !*name || req < -1) {
		cc = PvmBadParam;

	} else {
		if (!(cc = BEATASK)) {

			flags = PvmMboxDefault;

			if ( req < 0 ) {
				flags |= PvmMboxFirstAvail;
				req = 0;
			}

			rbf = pvm_setrbuf(0);

			sbf = pvm_setsbuf(pvm_mkbuf(PvmDataFoo));
			cc = TMDB_GET;
			pvm_pkint(&cc, 1, 1);
			pvm_pkint(&pvmmytid, 1, 1);
			pvm_pkstr(name);
			pvm_pkint(&req, 1, 1);
			pvm_pkint(&flags, 1, 1);
			if ((cc = msendrecv(TIDPVMD, TM_DB, SYSCTX_TM)) > 0) {
				pvm_upkint(&cc, 1, 1);
				if (cc >= 0) {
					mid = pvm_upkmesg();
					pvm_freebuf(pvm_setrbuf(mid));
				}
			}
			pvm_freebuf(pvm_setsbuf(sbf));

			if ( cc >= 0 && datap )
				pvm_upkint(datap, 1, 1);
			
			pvm_freebuf(pvm_setrbuf(rbf));
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_LOOKUP,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		if (cc != PvmNoEntry)
			lpvmerr("pvm_lookup", cc);
		else
			pvm_errno = cc;
	return cc;
}


int
pvm_delete(name, req)
	char *name;		/* class name */
	int req;		/* class index or -1 for all */
{
	int cc;
	TEV_DECLS

	if (TEV_EXCLUSIVE) {
		if (TEV_DO_TRACE(TEV_DELETE,TEV_EVENT_ENTRY)) {
			TEV_PACK_STRING( TEV_DID_CN, TEV_DATA_SCALAR,
				name ? name : "", 1, 1 );
			TEV_PACK_INT( TEV_DID_CI, TEV_DATA_SCALAR, &req, 1, 1 );
			TEV_FIN;
		}
	}

	if (!name || !*name || req < 0) {
		cc = PvmBadParam;

	} else {
		if (!(cc = BEATASK)) {
			cc = pvm_delinfo( name, req, PvmMboxDefault );
		}
	}

	if (TEV_AMEXCL) {
		if (TEV_DO_TRACE(TEV_DELETE,TEV_EVENT_EXIT)) {
			TEV_PACK_INT( TEV_DID_CC, TEV_DATA_SCALAR, &cc, 1, 1 );
			TEV_FIN;
		}
		TEV_ENDEXCL;
	}

	if (cc < 0)
		if (cc != PvmNoEntry)
			lpvmerr("pvm_delete", cc);
		else
			pvm_errno = cc;
	return cc;
}

