// src/backend/pyloader/python_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_policy.hh" #include #include #include using namespace sgpem; using namespace std; #define WAIT_FOR (250000) // WARNING : this class needs extensive and above all // *strong* exception checking / handling! PythonPolicy::PythonPolicy(const char* name) : _upolicy_dict(NULL), _adapter(NULL), _name(name) { PyObject* pLoadmeStr = PyString_FromString(name); PyObject* pUserPolicyModule = PyImport_Import(pLoadmeStr); Py_DECREF(pLoadmeStr); if( !pUserPolicyModule ) { PyErr_Print(); // Error in import // FIXME : don't exit abruptly, but fall back gracefully exit(-1); } // Dictionary with defined ``symbols'' for .pyc file _upolicy_dict = PyModule_GetDict(pUserPolicyModule); 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 pUserPolicyDict PyObject* pPolicyClass = PyDict_GetItemString(_upolicy_dict, name); assert(pPolicyClass); // 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(pPolicyClass); // PyTuple_SetItem steals a reference PyTuple_SetItem(pAdapterCtorParam, 0, pPolicyClass); _adapter = PyInstance_New(pAdapterClass, pAdapterCtorParam, NULL); Py_DECREF(pAdapterCtorParam); assert(_adapter); Py_DECREF(pScriptAdapterModule); // And now, who's your daddy, huh? } PythonPolicy::~PythonPolicy() { 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 PythonPolicy::configure() throw(UserInterruptException) { PyObject* retval = PyObject_CallMethod(_adapter, "async_configure", NULL); Py_DECREF(retval); wait_unlock(); } void PythonPolicy::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 PythonPolicy::get_description() const { return _name; } Glib::ustring PythonPolicy::get_name() const { return _name; } bool PythonPolicy::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 PythonPolicy::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::max() : static_cast(tmp); } void PythonPolicy::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!! cout << "got here..." << endl; Py_BLOCK_THREADS; cout << "wow I also got here!" << endl; 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 } */ }