#include #include #include #include /* FILE: pypvm_core_module.c -- A python interface to PVM. For more * information on PVM, see http://www.epm.ornl.gov/pvm/. * AUTHORS: W. Michael Petullo, wp0002@drake.edu * Gregory D. Baker, greg.baker@ifost.org.au * DATE: 13 FEB 1998 - 24 MAY 2000 * * Copyright (c) 1999 W. Michael Petullo * Copyright (c) 2000 Gregory D. Baker * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Useful definitions for this module */ static PyObject * pypvm_module; static PyObject * pypvm_dictionary; static PyObject *PvmBadParamException, *PvmMismatchException, *PvmOverflowException, *PvmNoDataException , *PvmNoHostException, *PvmNoFileException, *PvmNoMemException , *PvmBadMsgException, *PvmSysErrException, *PvmNoBufException , *PvmNoSuchBufException, *PvmNullGroupException, *PvmDupGroupException, *PvmNoGroupException, *PvmNotInGroupException , *PvmNoInstException , *PvmHostFailException, *PvmNoParentException , *PvmNotImplException , *PvmDSysErrException, *PvmBadVersionException, *PvmOutOfResException, *PvmDupHostException, *PvmCantStartException, *PvmAlreadyException , *PvmNoTaskException, *PvmNoEntryException, *PvmDupEntryException; static PyObject *PvmBadParamNumber, *PvmMismatchNumber, *PvmOverflowNumber, *PvmNoDataNumber , *PvmNoHostNumber, *PvmNoFileNumber, *PvmNoMemNumber , *PvmBadMsgNumber, *PvmSysErrNumber, *PvmNoBufNumber , *PvmNoSuchBufNumber, *PvmNullGroupNumber, *PvmDupGroupNumber, *PvmNoGroupNumber, *PvmNotInGroupNumber , *PvmNoInstNumber , *PvmHostFailNumber, *PvmNoParentNumber , *PvmNotImplNumber , *PvmDSysErrNumber, *PvmBadVersionNumber, *PvmOutOfResNumber, *PvmDupHostNumber, *PvmCantStartNumber, *PvmAlreadyNumber , *PvmNoTaskNumber, *PvmNoEntryNumber, *PvmDupEntryNumber; /* There are lots of functions that may want to return nothing, or throw an exception if their corresponding PVM call returned < 0. We define a macro `return_none' to handle this. Its argument is the return result from the PVM call. (Which will probably be a variable name. */ #define return_none(x) \ if (was_error(x)) return NULL; \ Py_INCREF(Py_None); \ return Py_None; /* PVM often returns negative numbers to mean some kind of error. Python can throw exceptions in these cases, so that's what we do. (We use set object with the exception as the string, and the data as the PVM return value. Maybe it should be the other way around. Anyway, it's kind of cute. */ static int was_error(int info) { if (info > 0) return 0; switch (info) { case PvmOk: return 0; #define error_case(x) case x : \ PyErr_SetObject(x ## Exception,x ## Number); \ return 1; error_case(PvmBadParam); error_case(PvmMismatch); error_case(PvmOverflow); error_case(PvmNoData); error_case(PvmNoHost); error_case(PvmNoFile); error_case(PvmNoMem); error_case(PvmBadMsg); error_case(PvmSysErr); error_case(PvmNoBuf); error_case(PvmNoSuchBuf); error_case(PvmNullGroup); error_case(PvmDupGroup); error_case(PvmNoGroup); error_case(PvmNotInGroup); error_case(PvmNoInst); error_case(PvmHostFail); error_case(PvmNoParent); error_case(PvmNotImpl); error_case(PvmDSysErr); error_case(PvmBadVersion); error_case(PvmOutOfRes); error_case(PvmDupHost); error_case(PvmCantStart); error_case(PvmAlready); error_case(PvmNoTask); error_case(PvmNoEntry); error_case(PvmDupEntry); } } static char pypvm_hostinfo__doc[] = "Returns a list (one tuple for each host in the virtual machine) - each tuple\n is (task id of pvm daemon,hostname,architecture,speed). \n\n This is a subset of the information that can be retrieved with pypvm.config()\n "; static PyObject * pypvm_hostinfo (PyObject *self, PyObject *args, PyObject* keywords) { struct pvmhostinfo *hinfo; int i; PyObject *list; int nhost; int narch; int info; PyObject *pvmd_tid, *hostname, *architecture, *speed; PyObject *tuple; info = pvm_config(&nhost,&narch,&hinfo); if (was_error(info)) return NULL; list = PyList_New(nhost); for (i = 0; i < nhost; i++) { pvmd_tid = PyInt_FromLong(hinfo[i].hi_tid); hostname = PyString_FromString(hinfo[i].hi_name); architecture = PyString_FromString(hinfo[i].hi_arch); speed = PyInt_FromLong(hinfo[i].hi_speed); tuple = PyTuple_New(4); PyTuple_SetItem(tuple,0,pvmd_tid); PyTuple_SetItem(tuple,1,hostname); PyTuple_SetItem(tuple,2,architecture); PyTuple_SetItem(tuple,3,speed); PyList_SetItem(list,i,tuple); } return list; } static char pypvm_narch__doc[]= "pypvm.narch() returns a count of the number of different data formats\nbeing used (narch = number of architectures). This is a subset of\nthe information returned by pypvm.config()\n"; static PyObject * pypvm_narch(PyObject * self, PyObject * args, PyObject * keywords) { struct pvmhostinfo *hinfo; int i; PyObject *list; int nhost; int narch; int info; PyObject *pvmd_tid, *hostname, *architecture, *speed; PyObject *tuple; info = pvm_config(&nhost,&narch,&hinfo); if (was_error(info)) return NULL; return Py_BuildValue("i",nhost); } static char pypvm_config__doc[] = "pypvm.config() returns a three element tuple\n - the number of hosts in the PVM cluster\n - the number of architectures in the cluster\n - a list of dictionaries giving information about each machine in\n the cluster.\n\n Each dictionary has keys \n - dtid\n - hostname\n - arch\n - speed\n\nNote that the speed field may have no particularly relationship\n with reality, as it just reporting the number stored in the\n startup hostsfile for the master pvmd. Read the pvmd3 man\n pages for more information.\n\n The information provided by pypvm.config is also available through\n pypvm.hostinfo and pypvm.narch."; static PyObject * pypvm_config (PyObject *self, PyObject *args, PyObject * keywords) { int info; int nhosts, narchs, i; struct pvmhostinfo *hinfo; PyObject *py_info, *items, *fctval; info =pvm_config(&nhosts, &narchs, &hinfo); if (was_error(info)) { return NULL; } py_info = PyList_New(nhosts); for (i = 0; i < nhosts; i++) { /* build info dictionaries */ items = PyDict_New(); PyDict_SetItemString(items, "dtid",PyInt_FromLong(hinfo[i].hi_tid)); PyDict_SetItemString(items, "hostname",PyString_FromString(hinfo[i].hi_name)); PyDict_SetItemString(items, "arch",PyString_FromString(hinfo[i].hi_arch)); PyDict_SetItemString(items, "speed",PyInt_FromLong(hinfo[i].hi_speed)); PyList_SetItem(py_info, i, items); } fctval = PyTuple_New(3); PyTuple_SetItem(fctval, 0, PyInt_FromLong(nhosts)); PyTuple_SetItem(fctval, 1, PyInt_FromLong(narchs)); PyTuple_SetItem(fctval, 2, py_info); free(hinfo); return (fctval); } static char pypvm_tasks__doc[] = "Returns a list (one tuple for each task) of all tasks running in the \nvirtual machine. Each tuple is (task id, parent task id, task id of\nthe pvm daemon on the tasks' machine,flags it was called with,\n the name of the task, and the process id of the task).\n\n If called with a tid as an argument, it will just return that tasks\n info; if called with the tid of a pvm daemon, it will return all\n the tasks on that host.\n"; static PyObject * pypvm_tasks (PyObject* self,PyObject* args, PyObject * keywords) { struct pvmtaskinfo * taskinfo; int where=0; /* If they don't provide it, they probably meant everything */ int ntasks; int info; int i; PyObject * list, *tuple; static char *kwlist[] = { "tid" , NULL }; if (!PyArg_ParseTupleAndKeywords(args,keywords,"|i", kwlist,&where)) return NULL; info = pvm_tasks(where,&ntasks,&taskinfo); if (was_error(info)) return NULL; list = PyList_New(ntasks); for (i=0;i 1) { /* not a list of strings or string is more than one character */ PyErr_SetString(PyExc_TypeError, "argument 1: expected list of chars"); PyMem_Free(chars); return (NULL); } } info = pvm_pkbyte(chars, list_len, stride); PyMem_Free(chars); return_none(info); } static PyObject * pypvm_pkdouble(PyObject* self, PyObject* args, PyObject *keywords) { int stride=1, list_len, i; double *doubles; PyObject *double_list, *item; int info; char * kwlist[] = {"list","stride",NULL }; if (!PyArg_ParseTupleAndKeywords(args, keywords, "O|i", kwlist, &double_list, &stride)) /* ASSERT: incorrect arguments */ return (NULL); if ((list_len = PyList_Size(double_list)) < 0) { /* ASSERT: second argument was not a list */ PyErr_SetString(PyExc_TypeError,"argument 1: expected list of doubles"); return (NULL); } if ((doubles = (double *) PyMem_Malloc(list_len * sizeof(double))) == NULL) return (NULL); for (i = 0; i < list_len; i++) { /* extract doubles from list */ item = PyList_GetItem(double_list, i); if (PyFloat_Check(item)) doubles[i] = PyFloat_AsDouble(item); else if (PyInt_Check(item)) doubles[i] = (double) PyInt_AS_LONG(item); else { PyErr_SetString(PyExc_TypeError, "argument 2: expected list of doubles"); PyMem_Free(doubles); return NULL; } } info = pvm_pkdouble(doubles, list_len, stride); PyMem_Free(doubles); return_none(info); } static PyObject * pypvm_pkfloat(PyObject* self, PyObject* args, PyObject *keywords) { int stride=1, list_len, i; float *floats; PyObject *float_list, *item; int info; char * kwlist[] = {"list","stride",NULL }; if (!PyArg_ParseTupleAndKeywords(args, keywords, "O|i", kwlist, &float_list, &stride)) /* ASSERT: incorrect arguments */ return (NULL); if ((list_len = PyList_Size(float_list)) < 0) { /* ASSERT: second argument was not a list */ PyErr_SetString(PyExc_TypeError,"argument 1: expected list of doubles"); return (NULL); } if ((floats = (float *) PyMem_Malloc(list_len * sizeof(float))) == NULL) return (NULL); for (i = 0; i < list_len; i++) { /* extract floats from list */ item = PyList_GetItem(float_list, i); if (PyFloat_Check(item)) floats[i] = (float) PyFloat_AsDouble(item); else if (PyInt_Check(item)) floats[i] = (float) PyInt_AS_LONG(item); else { PyErr_SetString(PyExc_TypeError,"argument 2: expected list of doubles"); PyMem_Free(floats); return NULL; } } info = pvm_pkfloat(floats, list_len, stride); PyMem_Free(floats); return_none(info); } static PyObject * pypvm_pkint(PyObject *self, PyObject *args, PyObject *keywords) { int stride=1, list_len, *ints, i; int info; char * kwlist[] = {"list", "stride", NULL }; PyObject *int_list, *item; if (!PyArg_ParseTupleAndKeywords(args, keywords, "O|i", kwlist, &int_list, &stride)) /* ASSERT: incorrect arguments */ return (NULL); if ((list_len = PyList_Size(int_list)) < 0) { /* ASSERT: second argument was not a list */ PyErr_SetString(PyExc_TypeError,"argument 1: expected list of ints"); return (NULL); } if ((ints = (int *) PyMem_Malloc(list_len * sizeof(int))) == NULL) return (NULL); for (i = 0; i < list_len; i++) { /* extract integers from list */ item = PyList_GetItem(int_list, i); if (!PyInt_Check(item)) { PyErr_SetString(PyExc_TypeError,"argument 1: expected list of ints"); PyMem_Free(ints); return NULL; } ints[i] = (int) PyInt_AsLong(item); } info = pvm_pkint(ints, list_len, stride); PyMem_Free(ints); return_none(info); } static PyObject* pypvm_pklong(PyObject * self, PyObject *args, PyObject *keywords) { int stride=1, list_len, i; int info; long *longs; PyObject *long_list, *item; char * kwlist[] = {"list","stride", NULL }; if (!PyArg_ParseTupleAndKeywords(args, keywords, "O|i", kwlist, &long_list, &stride)) /* ASSERT: incorrect arguments */ return (NULL); if ((list_len = PyList_Size(long_list)) < 0) { /* ASSERT: second argument was not a list */ PyErr_SetString(PyExc_TypeError,"argument 1: expected list of longs"); return (NULL); } if ((longs = (long *) PyMem_Malloc(list_len * sizeof(long))) == NULL) return (NULL); for (i = 0; i < list_len; i++) { /* extract longs from list */ item = PyList_GetItem(long_list, i); if (!PyInt_Check(item)) { PyErr_SetString(PyExc_TypeError,"argument 1: expected list of longs"); PyMem_Free(longs); return NULL; } longs[i] = PyInt_AsLong(item); } info = pvm_pklong(longs, list_len, stride); PyMem_Free(longs); return_none(info); } static PyObject* pypvm_pkshort(PyObject *self, PyObject *args, PyObject *keywords) { int info; short *shorts; int stride, list_len, i; PyObject *short_list, *item; char * kwlist[] = {"list","stride", NULL }; if (!PyArg_ParseTupleAndKeywords(args, keywords, "O|i", kwlist, &short_list, &stride)) /* ASSERT: incorrect arguments */ return (NULL); if ((list_len = PyList_Size(short_list)) < 0) { /* ASSERT: second argument was not a list */ PyErr_SetString(PyExc_TypeError,"argument 1: expected list of shorts"); return (NULL); } if ((shorts = (short *) PyMem_Malloc(list_len * sizeof(short))) == NULL) return (NULL); for (i = 0; i < list_len; i++) { /* extract shorts from list */ item = PyList_GetItem(short_list, i); if (!PyInt_Check(item)) { PyErr_SetString(PyExc_TypeError,"argument 1: expected list of shorts"); PyMem_Free(shorts); return NULL; } shorts[i] = PyInt_AsLong(item); } info = pvm_pkshort(shorts, list_len, stride); PyMem_Free(shorts); return_none(info); } static char pypvm_pkstr__doc[] = "pypvm.pkstr(str) packs the string [str]"; static PyObject * pypvm_pkstr(PyObject * self, PyObject * args, PyObject * keywords) { char *str; int info; char * kwlist[] = { "str" , NULL }; if (!PyArg_ParseTupleAndKeywords(args, keywords, "s", kwlist, &str)) /* ASSERT: incorrect arguments */ return (NULL); info = pvm_pkstr(str); return_none(info); } static char pypvm_probe__doc[]="\npypvm.probe(tid,msgtag) checks to see if a message with label msgtag has \narrived from tid. If a matching message has arrived pypvm.probe \nreturns a buffer identifier. This bufid can be used in a pypvm.bufinfo \ncall to determine information about the message such as its source\n and length. \n"; static PyObject *pypvm_probe(PyObject *self, PyObject *args, PyObject * keywords) { PyObject * resultobj; int bufid; int tid=-1; int msgtag=-1; static char *kwlist[] = { "tid", "msgtag" , NULL }; self = self; if(!PyArg_ParseTupleAndKeywords(args,keywords,"|ii:pvm_nrecv", kwlist,&tid,&msgtag)) { return NULL; } bufid = pvm_probe(tid,msgtag); if (was_error(bufid)) return NULL; resultobj = Py_BuildValue("i",bufid); return resultobj; } static char pypvm_pstat__doc[]="\npypvm.pstat(tid) returns the status of the process identified by [tid].\nAlso note that pypvm.notify() can be used to notify the caller that a task \nhas failed. \n"; static PyObject *pypvm_pstat(PyObject *self, PyObject *args, PyObject * keywords) { PyObject * resultobj; int status; int tid; static char *kwlist[] = { "tid" , NULL }; if(!PyArg_ParseTupleAndKeywords(args,keywords,"i:pvm_pstat", kwlist,&tid)) return NULL; status = pvm_pstat(tid); resultobj = Py_BuildValue("i",status); return resultobj; } static char pypvm_recv__doc[]="pypvm.recv(tid,msgtag) blocks the process until a message with label \n[msgtag] has arrived from [tid]. pypvm.recv() then places the message \nin a new active receive buffer, which also clears the current receive buffer.\n[tid] and [msgtag] can be -1, meaning \"match anything\", which is the default\nif either is not mentioned.\n"; static PyObject *pypvm_recv(PyObject *self, PyObject *args, PyObject *kwds) { PyObject * resultobj; int bufid; int tid=-1; int msgtag=-1; static char *kwlist[] = {"tid","msgtag",NULL}; if(!PyArg_ParseTupleAndKeywords(args,kwds,"|ii:pvm_recv", kwlist, &tid,&msgtag)) return NULL; bufid = pvm_recv(tid,msgtag); if (was_error(bufid)) return NULL; resultobj = Py_BuildValue("i",bufid); return resultobj; } static char pypvm_reg_tasker__doc[]="Registers the calling task as a PVM task starter. This function is for \nfolks who are writing stuff like debugger servers and so on. \n"; static PyObject *pypvm_reg_tasker(PyObject *self, PyObject *args, PyObject * keywords) { PyObject * resultobj; int cc; cc = pvm_reg_tasker(); return_none(cc); } static char pypvm_send__doc[]="\npypvm.send(tid,msgtag) sends a message stored in the active send buffer\nto the PVM process identified by [tid]. [msgtag] is used to label the \ncontent of the message.\n"; static PyObject *pypvm_send(PyObject *self, PyObject *args, PyObject * keywords) { PyObject * resultobj; int info; int tid; int msgtag; static char *kwlist[] = { "tid" , "msgtag" , NULL }; if(!PyArg_ParseTupleAndKeywords(args,keywords,"ii:pvm_send", kwlist,&tid,&msgtag)) return NULL; info= pvm_send(tid,msgtag); return_none(info); } static char pypvm_sendsig__doc[]="pypvm.sendsig(tid,signum) sends the signal number [signum] to the PVM\nprocess identified by [tid]. \n"; static PyObject *pypvm_sendsig(PyObject *self, PyObject *args, PyObject * keywords) { PyObject * resultobj; int info; int tid; int signum; static char *kwlist[] = { "tid" , "signum" , NULL }; if(!PyArg_ParseTupleAndKeywords(args,keywords,"ii:pvm_sendsig", kwlist,&tid,&signum)) return NULL; info = pvm_sendsig(tid,signum); return_none(info); } #ifdef PVM33COMPAT static char pypvm_setmwid__doc[]="pypvm.setmwid(bufid,waitid) assigns a new wait ID to a message buffer."; static PyObject *pypvm_setmwid(PyObject *self, PyObject *args, PyObject * keywords) { PyObject * resultobj; int info; int bufid; int waitid; static char *kwlist[] = { "bufid", "waitid" , NULL }; if(!PyArg_ParseTupleAndKeywords(args,keywords,"ii:pvm_setmwid", kwlist,&bufid,&waitid)) return NULL; info = pvm_setmwid(bufid,waitid); return_none(info); } #endif static char pypvm_setopt__doc[]="\npypvm.setopt(what,value) is a general purpose function used\nto set miscellaneous options in the PVM library. The previous\nvalue is returned.\n\n[what] is an integer defining what to set. One of:\n pypvm.opt['Route'] 1 Message routing policy\n pypvm.opt['DebugMask'] 2 Libpvm debug mask\n pypvm.opt['AutoErr'] 3 Auto error reporting\n pypvm.opt['OutputTid'] 4 Stdout destination for children\n pypvm.opt['OutputCode'] 5 Output message tag\n pypvm.opt['TraceTid'] 6 Trace data destination for children\n pypvm.opt['TraceCode'] 7 Trace message tag\n pypvm.opt['FragSize'] 8 Message fragment size\n pypvm.opt['ResvTids'] 9 Allow messages to reserved tags and TIDs\n pypvm.opt['SelfOutputTid'] 10 Stdout destination\n pypvm.opt['SelfOutputCode'] 11 Output message tag\n pypvm.opt['SelfTraceTid'] 12 Trace data destination\n pypvm.opt['SelfTraceCode'] 13 Trace message tag\n pypvm.opt['ShowTids'] 14 pvm_catchout prints task ids with output\n pypvm.opt['PollType'] 15 Message wait policy (shared memory)\n pypvm.opt['PollTime'] 16 Message spinwait duration\n\n[val] Integer specifying new setting of option. Usually this is just any\nold number, but there are some predefined values for pypvm.opt['Route']:\n pypvm.opt['DontRoute'] 1 Don't request or grant connections\n pypvm.opt['AllowDirect'] 2 (Default) Don't request but allow\n pypvm.opt['RouteDirect'] 3 Request and allow connections\n"; /* ' " */ static PyObject *pypvm_setopt(PyObject *self, PyObject *args, PyObject *keywords) { int what, val, oldval; char * kwlist[] = {"what", "val", NULL }; if (!PyArg_ParseTupleAndKeywords(args, keywords, "ii", kwlist, &what, &val)) return NULL; oldval = pvm_setopt(what, val); if (was_error(oldval)) { return NULL; } return (PyLong_FromLong(oldval)); } static char pypvm_setrbuf__doc[]="pypvm.setrbuf(bufid) switches the active receive buffer to bufid and returns \nthe previous buffer id."; static PyObject *pypvm_setrbuf(PyObject *self, PyObject *args, PyObject * keywords) { PyObject * resultobj; int oldbufid; int bufid; static char *kwlist[] = { "bufid" , NULL }; if(!PyArg_ParseTupleAndKeywords(args,keywords,"i:pvm_setrbuf", kwlist,&bufid)) return NULL; oldbufid = pvm_setrbuf(bufid); if (was_error(oldbufid)) return NULL; resultobj = Py_BuildValue("i",oldbufid); return resultobj; } static char pypvm_setsbuf__doc[]="pypvm.setsbuf(bufid) switches the active send buffer to bufid and returns \nthe previous buffer id."; static PyObject *pypvm_setsbuf(PyObject *self, PyObject *args, PyObject * keywords) { PyObject * resultobj; int oldbufid; int bufid; static char *kwlist[] = { "bufid", NULL }; if(!PyArg_ParseTupleAndKeywords(args,keywords,"i:pvm_setrbuf", kwlist,&bufid)) return NULL; oldbufid = pvm_setsbuf(bufid); if (was_error(oldbufid)) return NULL; resultobj = Py_BuildValue("i",oldbufid); return resultobj; } static char pypvm_spawn__doc[]="pypvm.spawn(task,argv,flag, where, ntasks) starts [ntask] copies of the \nexecutable named [task]. The tids are returned in a list.\n"; static PyObject *pypvm_spawn(PyObject *self, PyObject *args, PyObject * keywords) { PyObject * resultobj; int numt; char *task; PyObject *argvObject; char **argv; int flag; char * where; int ntasks; int * tids; int size,index; static char *kwlist[] = { "task" , "argv", "flag", "where", "ntasks" , NULL }; if (!PyArg_ParseTupleAndKeywords(args,keywords,"sOisi", kwlist,&task,&argvObject,&flag,&where,&ntasks)) { /* Hmm... I'd much rather have flags=default as default */ return NULL; } size = PyList_Size(argvObject); argv = calloc(size+1,sizeof(char *)); for (index=0;index