/* * Low-level BSPlib interface routines * * Written by Konrad Hinsen * last revision: 2002-3-22 */ #include "Python.h" #include "assert.h" #define _BSP_MODULE #include "Scientific/bspmodule.h" /* Global variables */ static int pid, nprocs, tagsize; static int array_counter; static PyBSP_Message *message_queue; static int nmessages, nobjects, current_message, array_data_pointer; /********************************************************/ /* Low-level access, for use by other extension modules */ /********************************************************/ static void PyBSP_Sync(void) { free(message_queue); message_queue = NULL; nmessages = nobjects = 0; bsp_sync(); array_counter = 0; } static void PyBSP_SetTagSize(int *tag_nbytes) { tagsize = *tag_nbytes; bsp_set_tagsize(tag_nbytes); } static void PyBSP_Send(int pid, const void *tag, const void *payload, int payload_nbytes) { bsp_send(pid, tag, payload, payload_nbytes); } static void PyBSP_QSize(int *nmessages, int *accum_nbytes) { bsp_qsize(nmessages, accum_nbytes); } static void PyBSP_GetTag(int *status, void *tag) { bsp_get_tag(status, tag); } static void PyBSP_Move(void *payload, int reception_nbytes) { bsp_move(payload, reception_nbytes); } static int PyBSP_HPMove(void **tag_ptr, void **payload_ptr) { return bsp_hpmove(tag_ptr, payload_ptr); } /*********************************/ /* Python object level functions */ /*********************************/ /* Send string object */ static int PyBSP_SendString(PyStringObject *string, int dest_pid) { PyBSP_Tag tag; int len = PyString_GET_SIZE(string); char *data = PyString_AS_STRING(string); if (dest_pid < 0 || dest_pid >= nprocs) { PyErr_SetString(PyExc_ValueError, "pid outside allowed range"); return -1; } if (tagsize != PyBSP_TAGSIZE) { int tagsize = PyBSP_TAGSIZE; PyBSP_SetTagSize(&tagsize); } tag.type = PyBSP_StringTag; tag.source_pid = pid; PyBSP_Send(dest_pid, (void *)&tag, (void *)data, len); return 0; } /* Send array object */ static int PyBSP_SendArray(PyArrayObject *array, int dest_pid) { PyBSP_Tag tag; int *typeinfo; if (dest_pid < 0 || dest_pid >= nprocs) { PyErr_SetString(PyExc_ValueError, "pid outside allowed range"); return -1; } if (PyArray_ISCONTIGUOUS(array)) Py_INCREF(array); else { array = (PyArrayObject *)PyArray_ContiguousFromObject((PyObject *)array, PyArray_NOTYPE, 0, 0); if (array == NULL) return -1; } if (tagsize != PyBSP_TAGSIZE) { int tagsize = PyBSP_TAGSIZE; PyBSP_SetTagSize(&tagsize); } typeinfo = (int *)malloc((array->nd+1)*sizeof(int)); if (typeinfo == NULL) { PyErr_NoMemory(); Py_DECREF(array); return -1; } typeinfo[0] = array->descr->type_num; memcpy(typeinfo+1, array->dimensions, array->nd*sizeof(int)); tag.type = PyBSP_ArrayTypeTag; tag.number = array_counter; tag.source_pid = pid; PyBSP_Send(dest_pid, (void *)&tag, (void *)typeinfo, (array->nd+1)*sizeof(int)); free(typeinfo); tag.type = PyBSP_ArrayDataTag; tag.number = array_counter; tag.source_pid = pid; PyBSP_Send(dest_pid, (void *)&tag, (void *)array->data, PyArray_NBYTES(array)); array_counter++; Py_DECREF(array); return 0; } /* Collect incoming messages */ static int collect_messages(void) { int i, dummy; if (message_queue == NULL) { PyBSP_QSize(&nmessages, &dummy); message_queue = (PyBSP_Message *)malloc(nmessages*sizeof(PyBSP_Message)); if (message_queue == NULL) { PyErr_NoMemory(); return -1; } nobjects = 0; for (i = 0; i < nmessages; i++) { PyBSP_Message *msg = message_queue + i; msg->length = PyBSP_HPMove((void *)&msg->tag_ptr, &msg->payload_ptr); if (msg->tag_ptr->type == PyBSP_StringTag || msg->tag_ptr->type == PyBSP_ArrayTypeTag) nobjects++; } current_message = 0; array_data_pointer = 0; } return 0; } /* Return number of remaining objects */ static int PyBSP_NumberOfObjects(void) { collect_messages(); return nobjects; } /* Receive string or array object */ static PyObject * PyBSP_ReceiveObject(void) { PyBSP_Message *msg; PyObject *object; if (collect_messages() == -1) return NULL; if (current_message == nmessages) { Py_INCREF(Py_None); return Py_None; } while (1) { msg = message_queue + current_message; if (msg->tag_ptr->type == PyBSP_StringTag) { object = PyString_FromStringAndSize((char *)msg->payload_ptr, msg->length); current_message++; nobjects--; break; } else if (msg->tag_ptr->type == PyBSP_ArrayTypeTag) { int *typeinfo = (int *)msg->payload_ptr; int type = *typeinfo; int nd = msg->length/sizeof(int) - 1; int *dimensions = typeinfo + 1; int data_pointer; PyArrayObject *array = (PyArrayObject *)PyArray_FromDims(nd, dimensions, type); object = (PyObject *)array; if (array_data_pointer == 0) data_pointer = current_message+1; else data_pointer = array_data_pointer; for (; data_pointer < nmessages; data_pointer++) { PyBSP_Message *amsg = message_queue + data_pointer; if (amsg->tag_ptr->type == PyBSP_ArrayDataTag && amsg->tag_ptr->source_pid == msg->tag_ptr->source_pid && amsg->tag_ptr->number == msg->tag_ptr->number) { memcpy(array->data, amsg->payload_ptr, amsg->length); break; } } if (data_pointer == nmessages) { PyErr_SetString(PyExc_ValueError, "no array data found"); Py_XDECREF(object); object = NULL; } else if (data_pointer == current_message+1) current_message++; current_message++; nobjects--; break; } else if (msg->tag_ptr->type == PyBSP_ArrayDataTag) { if (array_data_pointer == 0) array_data_pointer = current_message; current_message++; } else { PyErr_SetString(PyExc_ValueError, "illegal tag value"); object = NULL; break; } } return object; } /********************/ /* Python functions */ /********************/ static PyObject * syncc(PyObject *dummy, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; if (tagsize != PyBSP_TAGSIZE) { int tagsize = PyBSP_TAGSIZE; PyBSP_SetTagSize(&tagsize); } PyBSP_Sync(); Py_INCREF(Py_None); return Py_None; } static PyObject * send(PyObject *dummy, PyObject *args) { PyObject *object; int dest_pid, ret; if (!PyArg_ParseTuple(args, "Oi", &object, &dest_pid)) return NULL; if (PyString_Check(object)) ret = PyBSP_SendString((PyStringObject *)object, dest_pid); else if (PyArray_Check(object)) ret = PyBSP_SendArray((PyArrayObject *)object, dest_pid); else { PyErr_SetString(PyExc_TypeError, "can send only strings and arrays"); ret = -1; } if (ret == 0) { Py_INCREF(Py_None); return Py_None; } else return NULL; } static PyObject * receive(PyObject *dummy, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; return PyBSP_ReceiveObject(); } static PyObject * receive_all(PyObject *dummy, PyObject *args) { PyObject *list; int i, n; if (!PyArg_ParseTuple(args, "")) return NULL; if (collect_messages() == -1) return NULL; n = nobjects; list = PyList_New(n); if (list == NULL) return NULL; for (i = 0; i < n; i++) { PyObject *object = PyBSP_ReceiveObject(); if (object == NULL) { Py_DECREF(list); return NULL; } PyList_SET_ITEM(list, i, object); } return list; } /********************************************/ /* Table of functions defined in the module */ /********************************************/ static PyMethodDef bsp_methods[] = { {"sync", syncc, 1}, {"send", send, 1}, {"receive", receive, 1}, {"receive_all", receive_all, 1}, {NULL, NULL} /* sentinel */ }; /*************************/ /* Module initialization */ /*************************/ DL_EXPORT(void) initScientific_bsplib(void) { PyObject *m, *d; static void *PyBSP_API[PyBSP_API_pointers]; m = Py_InitModule("Scientific_bsplib", bsp_methods); d = PyModule_GetDict(m); /* Initialize module variables */ pid = bsp_pid(); nprocs = bsp_nprocs(); tagsize = 0; nmessages = nobjects = 0; message_queue = NULL; array_counter = 0; /* Initialize C API pointer array and store in module */ set_PyBSP_API_pointers(); PyDict_SetItemString(d, "_C_API", PyCObject_FromVoidPtr(PyBSP_API, NULL)); /* Store pid and number of processors */ PyDict_SetItemString(d, "processorID", PyInt_FromLong((long)pid)); PyDict_SetItemString(d, "numberOfProcessors", PyInt_FromLong((long)nprocs)); /* Import the array module */ #ifdef import_array import_array(); if (PyErr_Occurred()) { PyErr_SetString(PyExc_ImportError, "Can\'t import Numeric."); return; } #endif /* Check for errors */ if (PyErr_Occurred()) PyErr_SetString(PyExc_ImportError, "Can\'t initialize module."); } /* Keep indentation style when using cc mode in (x)emacs. */ /* Local Variables: */ /* c-basic-offset: 2 */ /* c-hanging-braces-alist: ((brace-list-open) (substatement-open after) (class-open after) (class-close before) (block-close . c-snug-do-while)) */ /* End: */