Commit eb34d246 authored by Georg Martin Reinke's avatar Georg Martin Reinke
Browse files

add Python type for external interfaces

parent 58eae23c
#include "PyInterface.h"
#include "ShmemInterface.h"
using namespace DPsim;
PyTypeObject DPsim::PyInterfaceType = {
PyVarObject_HEAD_INIT(NULL, 0)
"dpsim.Interface", /* tp_name */
sizeof(PyInterface), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)PyInterface::dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /* tp_flags */
"An interface to an external source/sink of data.", /* tp_doc */
};
void PyInterface::dealloc(PyInterface* self) {
if (self->intf)
delete self->intf;
Py_TYPE(self)->tp_free((PyObject*) self);
}
PyObject* pyShmemInterface(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {"queuelen", "samplelen", "polling", nullptr};
struct shmem_conf conf;
const char *wname, *rname;
conf.queuelen = 512;
conf.samplelen = 64;
conf.polling = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|iib", kwlist,
&wname, &rname, &conf.queuelen, &conf.samplelen, &conf.polling))
return nullptr;
PyInterface *pyIntf = PyObject_New(PyInterface, &PyInterfaceType);
pyIntf->intf = new ShmemInterface(wname, rname, &conf);
return (PyObject*) pyIntf;
}
#ifndef PYINTERFACE_H
#define PYINTERFACE_H
#include <Python.h>
#include "ExternalInterface.h"
namespace DPsim {
// Thin Python wrapper around ExternalInterface
struct PyInterface {
PyObject_HEAD
ExternalInterface *intf;
static void dealloc(PyInterface*);
};
extern PyTypeObject PyInterfaceType;
#ifdef __linux__
PyObject* pyShmemInterface(PyObject *self, PyObject *args);
#endif
};
#endif
#include <Python.h>
#include "PyComponent.h"
#include "PyInterface.h"
#include "PyModule.h"
#include "PySimulation.h"
......@@ -8,6 +9,7 @@ using namespace DPsim;
PyMethodDef DPsim::pyModuleMethods[] = {
{"load_cim", pyLoadCim, METH_VARARGS, "Load a network from CIM file(s)."},
{"ShmemInterface", (PyCFunction)pyShmemInterface, METH_VARARGS|METH_KEYWORDS, "Construct an Interface that communicates via POSIX shared memory."},
{0}
};
......@@ -24,6 +26,9 @@ extern "C" {
return nullptr;
if (PyType_Ready(&PySimulationType) < 0)
return nullptr;
PyInterfaceType.tp_new = PyType_GenericNew;
if (PyType_Ready(&PyInterfaceType) < 0)
return nullptr;
m = PyModule_Create(&dpsimModule);
if (!m)
......
#include "PySimulation.h"
#include "PyComponent.h"
#include "PyInterface.h"
#include "PySimulation.h"
#include <cfloat>
#include <iostream>
......@@ -7,6 +8,7 @@
using namespace DPsim;
static PyMethodDef PySimulation_methods[] = {
{"add_interface", PySimulation::addInterface, METH_VARARGS, "Registers an external interface with the simulation."},
{"lvector", PySimulation::lvector, METH_NOARGS, "Returns the left-side vector from the last step."},
{"pause", PySimulation::pause, METH_NOARGS, "Pause the already running simulation."},
{"start", PySimulation::start, METH_NOARGS, "Start the simulation, or resume if it is paused."},
......@@ -146,15 +148,39 @@ void PySimulation::dealloc(PySimulation* self) {
delete self->mut;
delete self->cond;
for (auto it : self->refs) {
Py_DECREF(it);
}
// Since this is not a C++ destructor which would automatically call the
// destructor of its members, we have to manually call the destructor of
// the component vector here to free the associated memory.
// the vectors here to free the associated memory.
self->comps.~vector<BaseComponent*>();
self->refs.~vector<PyObject*>();
Py_XDECREF(self->pyComps);
Py_TYPE(self)->tp_free((PyObject*)self);
}
PyObject* PySimulation::addInterface(PyObject* self, PyObject* args) {
PySimulation *pySim = (PySimulation*) self;
PyObject* pyObj;
PyInterface* pyIntf;
if (!PyArg_ParseTuple(args, "O", &pyObj))
return nullptr;
if (!PyObject_TypeCheck(pyObj, &PyInterfaceType)) {
PyErr_SetString(PyExc_TypeError, "Argument must be dpsim.Interface");
return nullptr;
}
pyIntf = (PyInterface*) pyObj;
pySim->sim->addExternalInterface(pyIntf->intf);
Py_INCREF(pyObj);
pySim->refs.push_back(pyObj);
Py_INCREF(Py_None);
return Py_None;
}
PyObject* PySimulation::lvector(PyObject *self, PyObject *args) {
PySimulation *pySim = (PySimulation*) self;
if (pySim->state == StateRunning) {
......
......@@ -36,6 +36,11 @@ namespace DPsim {
PyObject* pyComps; // Components as a (Python) list of PyComponents
std::vector<BaseComponent*> comps;
int numSwitch;
// List of additional objects that aren't directly used from PySimulation
// methods, but that a reference has be kept to to avoid them from being
// freed (e.g. ExternalInterfaces).
std::vector<PyObject*> refs;
// Function executed by the simulation thread
static void simThreadFunction(PySimulation* pySim);
......@@ -49,6 +54,7 @@ namespace DPsim {
static void dealloc(PySimulation*);
// Methods that are actually available from Python
static PyObject* addInterface(PyObject *self, PyObject *args);
static PyObject* lvector(PyObject *self, PyObject *args);
static PyObject* pause(PyObject *self, PyObject *args);
static PyObject* start(PyObject *self, PyObject *args);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment