sgpemv2/plugins/pyloader/src/python_cpu_policy.cc

237 lines
6.5 KiB
C++
Raw Normal View History

// src/python_cpu_policy.cc - Copyright 2005, 2006, University
// of Padova, dept. of Pure and Applied
// Mathematics
//
// This file is part of SGPEMv2.
//
// This 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.
//
// SGPEMv2 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 SGPEMv2; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "python_cpu_policy.hh"
#include <limits>
#include <unistd.h>
#include <iostream>
using namespace sgpem;
using namespace std;
#define WAIT_FOR (250000)
// WARNING : this class needs extensive and above all
// *strong* exception checking / handling!
PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyException)
: _upolicy_dict(NULL), _adapter(NULL), _name(name)
{
//PyRun_SimpleString("import StringIO\nimport sys\nsys.stderr = cStringIO.StringIO()\n");
//PyObject* pBuiltinsMod = PyImport_ImportModule("__builtin__");
//PyObject* pBuiltinsDict = PyModule_GetDict(pBuiltinsMod);
PyObject* pLoadmeStr = PyString_FromString(name);
PyObject* pUserCPUPolicyModule = PyImport_Import(pLoadmeStr);
Py_DECREF(pLoadmeStr);
if( !pUserCPUPolicyModule )
{
PyErr_Print(); // Error in import
// PyObject* msg = PyRun_String("import sys\nsys.stderr.getvalue()", Py_eval_input, pBuiltinsDict, NULL);
// if(msg == NULL)
// PyErr_Print();
// char* str = PyString_AsString(msg);
// throw MalformedPolicyException(PyString_AS_STRING(msg));
throw MalformedPolicyException("");
}
// Dictionary with defined ``symbols'' for .pyc file
_upolicy_dict = PyModule_GetDict(pUserCPUPolicyModule);
assert(_upolicy_dict);
// Loads ScriptAdapter module and get its dictionary
pLoadmeStr = PyString_FromString("ScriptAdapter");
PyObject* pScriptAdapterModule = PyImport_Import(pLoadmeStr);
Py_DECREF(pLoadmeStr);
assert(pScriptAdapterModule);
PyObject* pAdapterDict = PyModule_GetDict(pScriptAdapterModule);
assert(pAdapterDict);
// Now takes the user-defined policy class from pUserCPUPolicyDict
PyObject* pCPUPolicyClass = PyDict_GetItemString(_upolicy_dict, name);
assert(pCPUPolicyClass); // FIXME needs stricter checking and exception throwing
// Creates a new object of type ScriptAdapter :
// takes init function from ScriptAdapter class
PyObject* pAdapterClass = PyDict_GetItemString(pAdapterDict, "ScriptAdapter");
PyObject* pAdapterCtorParam = PyTuple_New(1);
Py_INCREF(pCPUPolicyClass); // PyTuple_SetItem steals a reference
PyTuple_SetItem(pAdapterCtorParam, 0, pCPUPolicyClass);
_adapter = PyInstance_New(pAdapterClass, pAdapterCtorParam, NULL);
Py_DECREF(pAdapterCtorParam);
Py_DECREF(pScriptAdapterModule);
if(_adapter == NULL)
{
PyErr_Print();
throw MalformedPolicyException(_("unable to instantiate ScriptAdapter, "
"check that all methods are implemented"));
}
// And now, who's your daddy, huh?
}
PythonCPUPolicy::~PythonCPUPolicy()
{
if(_adapter) Py_DECREF(_adapter);
// We keep this alive until dtor time, because
// the user may have defined some static global-space
// variables and they make use of them.
if(_upolicy_dict) Py_DECREF(_upolicy_dict);
}
void
PythonCPUPolicy::configure() throw(UserInterruptException)
{
PyObject* retval = PyObject_CallMethod(_adapter, "async_configure", NULL);
Py_DECREF(retval);
wait_unlock();
}
void
PythonCPUPolicy::sort_queue() const throw(UserInterruptException)
{
PyObject* retval = PyObject_CallMethod(_adapter, "async_sort_queue", NULL);
// Do minimal debugging
if(!retval) PyErr_Print();
else Py_DECREF(retval);
wait_unlock();
}
Glib::ustring
PythonCPUPolicy::get_description() const
{
return _name;
}
Glib::ustring
PythonCPUPolicy::get_name() const
{
return _name;
}
bool
PythonCPUPolicy::is_pre_emptive() const throw(UserInterruptException)
{
PyObject* retval = PyObject_CallMethod(_adapter, "async_is_preemptive", NULL);
Py_DECREF(retval);
wait_unlock();
// Parse return value stored in global Python object
retval = PyObject_CallMethod(_adapter, "get_return_value", NULL);
assert(retval);
bool ret = PyObject_IsTrue(retval);
Py_DECREF(retval);
return ret;
}
int
PythonCPUPolicy::get_time_slice() const throw(UserInterruptException)
{
PyObject* retval = PyObject_CallMethod(_adapter, "async_get_time_slice", NULL);
// Do minimal debugging
if(!retval) PyErr_Print();
else Py_DECREF(retval);
wait_unlock();
// Parse return value stored in global Python object
retval = PyObject_CallMethod(_adapter, "get_return_value", NULL);
assert(retval);
long tmp = PyInt_AsLong(retval);
Py_DECREF(retval);
return tmp < 0 ? numeric_limits<int>::max() : static_cast<int>(tmp);
}
void
PythonCPUPolicy::wait_unlock() const throw(UserInterruptException)
{
PyThreadState* _save;
int i = 0; // We give the sort_queue() three seconds max time, then...
// we shot it stone dead! Bang.
bool still_locked;
do
{
Py_UNBLOCK_THREADS;
usleep(WAIT_FOR); // hack'a'ton! magggggiccc nummmbeeerrrrrs!!
Py_BLOCK_THREADS;
PyObject* retval = PyObject_CallMethod(_adapter, "mutex_test_lock", NULL);
assert(retval);
still_locked = PyObject_IsTrue(retval);
Py_DECREF(retval);
if(i++ > 12) /* waits for WAIT_FOR * 12 microseconds == 3 secs */
{
PyThreadState_Clear(_save);
// As the API documentation says, the caller of PyEval_RestoreThread
// should NOT possess the interpreter lock
Py_UNBLOCK_THREADS;
PyEval_RestoreThread(_save);
throw UserInterruptException("User-defined policy is "
"taking too long to terminate.");
}
}
while(still_locked);
// What we should really do here:
/* do {
enable python threads
wait for some time...
disable python threads
...check if user asked for interruption, reading a
syncronized variable...
...if he has, break
...else:
if the global lock is set:
stay in this loop
else:
all's went okay, can exit loop
} */
}