/*
* Low-level BSPlib interface routines
*
* Written by Konrad Hinsen <hinsen@cnrs-orleans.fr>
* 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: */
syntax highlighted by Code2HTML, v. 0.9.1