Porting to MPP systems is more difficult because most of them do not offer a standard Unix environment on the nodes. We discuss some of these limitations below.
Processes running on the nodes of an Intel iPSC/860 have no Unix process id's and they cannot receive Unix signals. There is a similar problem for the Thinking Machine's CM-5 .
If a node process forks, the behavior of the new process is machine dependent. In any event it would not be allowed to become a new PVM task. In general, processes on the nodes are not allowed to enroll unless they were spawned by PVM.
By default, pvm_spawn() starts tasks on the (compute) nodes. To spawn multiple copies of the same executable, the programmer should call pvm_spawn() once and specify the number of copies.
On some machines (e.g., iPSC/860), only one process is allowed on each node, so the total number of PVM tasks on these machines cannot exceed the number of nodes available.
Several functions serve as the multiprocessor ``interface" for PVM. They are called by pvmd to spawn new tasks and to communicate with them. The implementation of these functions is system dependent; the source code is kept in the src/PVM_ARCH/pvmdmimd.c (message passing) or src/PVM_ARCH/pvmdshmem.c (shared memory). We give a brief description of each of these functions below. Note that pvmdmimd.c can be found in the subdirectory PVM_ARCH because MPP platforms are very different from one another, even those from the same vendor.
void mpp_init(int argc, char **argv); Initialization. Called once when PVM is started. Arguments argc and argv are passed from pvmd main(). int mpp_load(int flags, char *name, char *argv, int count, int *tids, int ptid); Create partition if necessary. Load executable onto nodes; create new entries in task table, encode node number and process type into task IDs. flags: exec options; name: executable to be loaded; argv: command line argument for executable; count: number of tasks to be created; tids: array to store new task IDs; ptid: parent task ID. void mpp_output(struct task *tp, struct pkt *pp); Send all pending packets to nodes via native send. Node number and process type are extracted from task ID. tp: destination task; pp: packet. int mpp_mcast(struct pkt pp, int *tids, int ntask); Global send. pp: packet; tids: list of destination task IDs; ntask: how many. int mpp_probe(); Probe for pending packets from nodes (non-blocking). Returns 1 if packets are found, otherwise 0. void mpp_input(); Receive pending packets (from nodes) via native receive. void mpp_free(int tid) Remove node/process-type from active list. tid: task ID.
In addition to these functions, the message exchange routine in libpvm, mroute(), must also be implemented in the most efficient native message-passing primitives. The following macros are defined in src/pvmmimd.h:
ASYNCRECV(buf,len) Non-blocking receive. Returns immediately with a message handle. buf: (char *), buffer to place the data; len: (int), size of buffer in bytes. ASYNCSEND(tag,buf,len,dest,ptype) Non-blocking send. Returns immediately with a message handle. tag: (int), message tag; buf: (char *), location of data; len: (int), size of data in bytes; dest: (long), address of destination node; ptype: instance number of destination task. ASYNCWAIT(mid) Blocks until operation associated with mid has completed. mid: message handle (its type is system-dependent). ASYNCDONE(mid) Returns 1 if operation associated with mid has completed, and 0 otherwise. mid: message handle (its type is system-dependent). MSGSIZE(mid) Returns size of message most recently arrived. mid: message handle (its type is system-dependent). MSGSENDER(mid) Returns node number of the sender of most recently received message. mid: message handle (its type is system-dependent). PVMCRECV(tag,buf,len) Blocks until message has been received into buffer. tag: (int), expected message tag; buf: (char *), buffer to place the data; len: (int), size of buffer in bytes; PVMCSEND(tag,buf,len,dest,ptype) Blocks until send operation is complete and buffer can be reused. Non-blocking send. Returns immediately with a message handle. tag: (int), message tag; buf: (char *), location of data; len: (int), size of data in bytes; dest: (long), address of destination node; ptype: instance number of destination task.
These functions are used by mroute() on MPP systems. The source code for mroute for multiprocessors is in src/lpvmmimd.c or src/lpvmshmem.c depending on the class.
For shared-memory implementations, the following macros are defined in
PAGEINITLOCK(lp) Initialize the lock pointed to by lp. PAGELOCK(lp) Locks the lock pointed to by lp. PAGEUNLOCK(lp) Unlocks the lock pointed to by lp.In addition, the file pvmshmem.c contains routines used by both pvmd and libpvm.