Port everything to work with Python 2.6 and (hopefully) 3.0.
Phew, this was harder than I expected, mostly because I noticed I never grokked metaclasses all that well. Now it's slightly better ;-). git-svn-id: svn://svn.gna.org/svn/sgpemv2/trunk@1344 3ecf2c5c-341e-0410-92b4-d18e462d057c
This commit is contained in:
parent
59ebcace2a
commit
cd10080cca
|
@ -95,7 +95,6 @@ noinst_HEADERS += \
|
||||||
src/python_cpu_policy_manager.hh
|
src/python_cpu_policy_manager.hh
|
||||||
|
|
||||||
share_PYTHON = \
|
share_PYTHON = \
|
||||||
src/Abstract.py \
|
|
||||||
src/CPUPolicy.py \
|
src/CPUPolicy.py \
|
||||||
src/ScriptAdapter.py
|
src/ScriptAdapter.py
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ AM_GNU_GETTEXT_VERSION([0.17])
|
||||||
|
|
||||||
dnl PYTHON_VERSION is declared precious by AC_PYTHON_DEVEL,
|
dnl PYTHON_VERSION is declared precious by AC_PYTHON_DEVEL,
|
||||||
dnl so don't use it here
|
dnl so don't use it here
|
||||||
PY_VERSION=2.3
|
PY_VERSION=2.6
|
||||||
GTKMM_VERSION=2.8.0
|
GTKMM_VERSION=2.8.0
|
||||||
SGPEMV2_VERSION=1.0
|
SGPEMV2_VERSION=1.0
|
||||||
|
|
||||||
|
|
|
@ -268,7 +268,7 @@ EOD`
|
||||||
|
|
||||||
AC_MSG_RESULT([$pythonexists])
|
AC_MSG_RESULT([$pythonexists])
|
||||||
|
|
||||||
if test ! "x$pythonexists" = "xyes"; then
|
if test ! "x$pythonexists" = "xyes"; then
|
||||||
AC_MSG_FAILURE([
|
AC_MSG_FAILURE([
|
||||||
Could not link test program to Python. Maybe the main Python library has been
|
Could not link test program to Python. Maybe the main Python library has been
|
||||||
installed in some non-standard library path. If so, pass it to configure,
|
installed in some non-standard library path. If so, pass it to configure,
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
## @brief Defines a class to create abstract methods
|
|
||||||
#
|
|
||||||
# @author Ivo Timmermans
|
|
||||||
# @date 2004/01/23
|
|
||||||
# @version 1.1
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# @code
|
|
||||||
# import Abstract;
|
|
||||||
# class Foo:
|
|
||||||
# __metaclass__ = Abstract.Metaclass
|
|
||||||
# foo = Abstract.AbstractMethod('foo')
|
|
||||||
# @endcode
|
|
||||||
class AbstractMethod (object):
|
|
||||||
## @brief Constructor
|
|
||||||
#
|
|
||||||
# @param func name of the function (used when raising an
|
|
||||||
# exception). Its type is str.
|
|
||||||
def __init__(self, func):
|
|
||||||
self._function = func
|
|
||||||
|
|
||||||
## @brief Get callable object
|
|
||||||
#
|
|
||||||
# @return An instance of AbstractMethodHelper.
|
|
||||||
# This trickery is needed to get the name of the class for which
|
|
||||||
# an abstract method was requested, otherwise it would be
|
|
||||||
# sufficient to include a __call__ method in the AbstractMethod
|
|
||||||
# class itself.
|
|
||||||
def __get__(self, obj, type):
|
|
||||||
return self.AbstractMethodHelper(self._function, type)
|
|
||||||
|
|
||||||
## @brief Abstract method helper class
|
|
||||||
#
|
|
||||||
# An AbstractMethodHelper instance is a callable object that
|
|
||||||
# represents an abstract method.
|
|
||||||
class AbstractMethodHelper (object):
|
|
||||||
def __init__(self, func, cls):
|
|
||||||
self._function = func
|
|
||||||
self._class = cls
|
|
||||||
|
|
||||||
## @brief Call abstract method
|
|
||||||
#
|
|
||||||
# Raises a TypeError, because abstract methods can not be
|
|
||||||
# called.
|
|
||||||
def __call__(self, *args, **kwargs):
|
|
||||||
raise TypeError('Abstract method `' + self._class.__name__ \
|
|
||||||
+ '.' + self._function + '\' called')
|
|
||||||
|
|
||||||
## @brief Configure a new class to be abstract
|
|
||||||
#
|
|
||||||
# @author Ivo Timmermans
|
|
||||||
# @date 2004/01/23
|
|
||||||
# @version 1.1
|
|
||||||
class Metaclass (type):
|
|
||||||
## Configure a new class
|
|
||||||
#
|
|
||||||
# @param cls Class object
|
|
||||||
# @param name Name of the class
|
|
||||||
# @param bases All base classes for cls
|
|
||||||
def __init__(cls, name, bases, *args, **kwargs):
|
|
||||||
super(Metaclass, cls).__init__(cls, name, bases, *args, **kwargs)
|
|
||||||
|
|
||||||
# Detach cls.new() from class Metaclass, and make it a method
|
|
||||||
# of cls.
|
|
||||||
cls.__new__ = staticmethod(cls.new)
|
|
||||||
|
|
||||||
# Find all abstract methods, and assign the resulting list to
|
|
||||||
# cls.__abstractmethods__, so we can read that variable when a
|
|
||||||
# request for allocation (__new__) is done.
|
|
||||||
abstractmethods = []
|
|
||||||
ancestors = list(cls.__mro__)
|
|
||||||
ancestors.reverse() # Start with __builtin__.object
|
|
||||||
for ancestor in ancestors:
|
|
||||||
for clsname, clst in ancestor.__dict__.items():
|
|
||||||
if isinstance(clst, AbstractMethod):
|
|
||||||
abstractmethods.append(clsname)
|
|
||||||
else:
|
|
||||||
if clsname in abstractmethods:
|
|
||||||
abstractmethods.remove(clsname)
|
|
||||||
|
|
||||||
abstractmethods.sort()
|
|
||||||
setattr(cls, '__abstractmethods__', abstractmethods)
|
|
||||||
|
|
||||||
## @brief Allocator for class cls
|
|
||||||
#
|
|
||||||
# @param self Class object for which an instance should be
|
|
||||||
# created.
|
|
||||||
# @param cls Same as self.
|
|
||||||
def new(self, cls):
|
|
||||||
if len(cls.__abstractmethods__):
|
|
||||||
raise NotImplementedError('Can\'t instantiate class `' + \
|
|
||||||
cls.__name__ + '\';\n' + \
|
|
||||||
'Abstract methods: ' + \
|
|
||||||
", ".join(cls.__abstractmethods__))
|
|
||||||
|
|
||||||
return object.__new__(self)
|
|
|
@ -1,17 +1,11 @@
|
||||||
from Abstract import *
|
from abc import *
|
||||||
import sgpem
|
import sgpem
|
||||||
|
|
||||||
## @brief This is the abstract class a user-defined policy
|
## @brief The abstract base class needed for compatibility between
|
||||||
# should inherit from
|
# Python 2.6 and Python 3.x.
|
||||||
#
|
#
|
||||||
# This class also exposes the method sort(), which can be
|
# @see CPUPolicy
|
||||||
# used to easily sort the queue of ready process with a
|
class CPUPolicyBase(object):
|
||||||
# user-defined given compare function.
|
|
||||||
class CPUPolicy:
|
|
||||||
## @var Avoid instantiation of an abstract class.
|
|
||||||
# @see Abstract.Metaclass
|
|
||||||
__metaclass__ = Metaclass
|
|
||||||
|
|
||||||
## @brief Configure policy to initial values
|
## @brief Configure policy to initial values
|
||||||
#
|
#
|
||||||
# This is called just before a simulation starts, and is responsible
|
# This is called just before a simulation starts, and is responsible
|
||||||
|
@ -26,7 +20,9 @@ class CPUPolicy:
|
||||||
# @endcode
|
# @endcode
|
||||||
#
|
#
|
||||||
# @see sgpem::Policy::get_parameters()
|
# @see sgpem::Policy::get_parameters()
|
||||||
configure = AbstractMethod('configure')
|
@abstractmethod
|
||||||
|
def configure(self):
|
||||||
|
pass
|
||||||
|
|
||||||
## @brief Sort ready processes queue
|
## @brief Sort ready processes queue
|
||||||
#
|
#
|
||||||
|
@ -46,7 +42,9 @@ class CPUPolicy:
|
||||||
# swap(positionA, positionB) and size().
|
# swap(positionA, positionB) and size().
|
||||||
#
|
#
|
||||||
# @see Policy::Policy::sort()
|
# @see Policy::Policy::sort()
|
||||||
sort_queue = AbstractMethod('sort_queue')
|
@abstractmethod
|
||||||
|
def sort_queue(self, queue):
|
||||||
|
pass
|
||||||
|
|
||||||
## @brief Returns whether the policy wants to be preemptive,
|
## @brief Returns whether the policy wants to be preemptive,
|
||||||
# other than by normal time slice termination
|
# other than by normal time slice termination
|
||||||
|
@ -70,7 +68,9 @@ class CPUPolicy:
|
||||||
# slice (or a process blocking/termination, of course) before
|
# slice (or a process blocking/termination, of course) before
|
||||||
# selecting a new running process, even if it has greater priority
|
# selecting a new running process, even if it has greater priority
|
||||||
# than the current one
|
# than the current one
|
||||||
is_preemptive = AbstractMethod('is_preemptive')
|
@abstractmethod
|
||||||
|
def is_preemptive(self):
|
||||||
|
pass
|
||||||
|
|
||||||
## @brief Returns how long is a time-slice for this policy
|
## @brief Returns how long is a time-slice for this policy
|
||||||
#
|
#
|
||||||
|
@ -90,7 +90,9 @@ class CPUPolicy:
|
||||||
#
|
#
|
||||||
# @return -1 If the policy doesn't want to use time slices
|
# @return -1 If the policy doesn't want to use time slices
|
||||||
# @return 0+ To specify a time slice duration for this policy
|
# @return 0+ To specify a time slice duration for this policy
|
||||||
get_time_slice = AbstractMethod('get_time_slice')
|
@abstractmethod
|
||||||
|
def get_time_slice(self):
|
||||||
|
pass
|
||||||
|
|
||||||
## @brief Returns the PolicyParameters instance you can use in
|
## @brief Returns the PolicyParameters instance you can use in
|
||||||
# Policy::Policy::configure()
|
# Policy::Policy::configure()
|
||||||
|
@ -178,3 +180,18 @@ class CPUPolicy:
|
||||||
# puts pivot in place
|
# puts pivot in place
|
||||||
queue.swap(i,b)
|
queue.swap(i,b)
|
||||||
return i
|
return i
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## @brief This is the abstract class a user-defined policy
|
||||||
|
# should inherit from
|
||||||
|
#
|
||||||
|
# This class also exposes the method sort(), which can be
|
||||||
|
# used to easily sort the queue of ready process with a
|
||||||
|
# user-defined given compare function.
|
||||||
|
#
|
||||||
|
# @see CPUPolicyBase
|
||||||
|
CPUPolicy = ABCMeta('CPUPolicy', (CPUPolicyBase, ), {})
|
||||||
|
|
||||||
|
|
||||||
|
print (dir (CPUPolicy))
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
from CPUPolicy import CPUPolicy
|
from CPUPolicy import CPUPolicy
|
||||||
|
|
||||||
class rr(CPUPolicy) :
|
class rr(CPUPolicy):
|
||||||
"""Round Robin scheduling policy
|
"""Round Robin scheduling policy
|
||||||
|
|
||||||
This policy executes a thread for a given amount
|
This policy executes a thread for a given amount
|
||||||
|
|
|
@ -34,13 +34,39 @@ using namespace std;
|
||||||
Glib::StaticRecMutex PythonCPUPolicy::_mtx = GLIBMM_STATIC_REC_MUTEX_INIT;
|
Glib::StaticRecMutex PythonCPUPolicy::_mtx = GLIBMM_STATIC_REC_MUTEX_INIT;
|
||||||
|
|
||||||
|
|
||||||
|
// Convenience porting function for converting from Python 3.0
|
||||||
|
// UCS-(2|4) strings to glib::ustring
|
||||||
|
namespace sgpem
|
||||||
|
{
|
||||||
|
static Glib::ustring
|
||||||
|
PyString_AsString (PyObject* obj)
|
||||||
|
{
|
||||||
|
using ::PyString_AsString;
|
||||||
|
|
||||||
|
Glib::ustring ret;
|
||||||
|
|
||||||
|
PyObject *str = PyObject_Str (obj);
|
||||||
|
if (PyUnicode_Check (str))
|
||||||
|
{
|
||||||
|
PyObject *ustr = PyUnicode_AsUTF8String (str);
|
||||||
|
ret = PyBytes_AsString (ustr);
|
||||||
|
Py_DECREF (ustr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = PyString_AS_STRING (str);
|
||||||
|
|
||||||
|
Py_DECREF (str);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WARNING : this class needs extensive and above all
|
// WARNING : this class needs extensive and above all
|
||||||
// *strong* exception checking / handling!
|
// *strong* exception checking / handling!
|
||||||
|
|
||||||
PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyException)
|
PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyException)
|
||||||
: _upolicy_dict(NULL), _adapter(NULL), _name(name), _description()
|
: _upolicy_dict(NULL), _adapter(NULL), _name(name), _description()
|
||||||
{
|
{
|
||||||
PyObject* pLoadmeStr = PyString_FromString(name);
|
PyObject* pLoadmeStr = PyUnicode_FromString (name);
|
||||||
PyObject* pUserCPUPolicyModule = PyImport_Import(pLoadmeStr);
|
PyObject* pUserCPUPolicyModule = PyImport_Import(pLoadmeStr);
|
||||||
Py_DECREF(pLoadmeStr);
|
Py_DECREF(pLoadmeStr);
|
||||||
|
|
||||||
|
@ -52,7 +78,7 @@ PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyExceptio
|
||||||
assert(_upolicy_dict);
|
assert(_upolicy_dict);
|
||||||
|
|
||||||
// Loads ScriptAdapter module and get its dictionary
|
// Loads ScriptAdapter module and get its dictionary
|
||||||
pLoadmeStr = PyString_FromString("ScriptAdapter");
|
pLoadmeStr = PyUnicode_FromString("ScriptAdapter");
|
||||||
PyObject* pScriptAdapterModule = PyImport_Import(pLoadmeStr);
|
PyObject* pScriptAdapterModule = PyImport_Import(pLoadmeStr);
|
||||||
Py_DECREF(pLoadmeStr);
|
Py_DECREF(pLoadmeStr);
|
||||||
assert(pScriptAdapterModule);
|
assert(pScriptAdapterModule);
|
||||||
|
@ -68,7 +94,7 @@ PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyExceptio
|
||||||
// Retrieve a description for the policy using the __doc__ attribute
|
// Retrieve a description for the policy using the __doc__ attribute
|
||||||
PyObject* pDescriptionString = PyObject_GetAttrString(pCPUPolicyClass, "__doc__");
|
PyObject* pDescriptionString = PyObject_GetAttrString(pCPUPolicyClass, "__doc__");
|
||||||
if(pDescriptionString != Py_None)
|
if(pDescriptionString != Py_None)
|
||||||
_description = PyString_AsString(pDescriptionString);
|
_description = sgpem::PyString_AsString(pDescriptionString);
|
||||||
Py_DECREF(pDescriptionString);
|
Py_DECREF(pDescriptionString);
|
||||||
|
|
||||||
// Creates a new object of type ScriptAdapter :
|
// Creates a new object of type ScriptAdapter :
|
||||||
|
@ -77,7 +103,7 @@ PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyExceptio
|
||||||
PyObject* pAdapterCtorParam = PyTuple_New(1);
|
PyObject* pAdapterCtorParam = PyTuple_New(1);
|
||||||
Py_INCREF(pCPUPolicyClass); // PyTuple_SetItem steals a reference
|
Py_INCREF(pCPUPolicyClass); // PyTuple_SetItem steals a reference
|
||||||
PyTuple_SetItem(pAdapterCtorParam, 0, pCPUPolicyClass);
|
PyTuple_SetItem(pAdapterCtorParam, 0, pCPUPolicyClass);
|
||||||
_adapter = PyInstance_New(pAdapterClass, pAdapterCtorParam, NULL);
|
_adapter = PyObject_CallObject((PyObject*) pAdapterClass, pAdapterCtorParam);
|
||||||
Py_DECREF(pAdapterCtorParam);
|
Py_DECREF(pAdapterCtorParam);
|
||||||
|
|
||||||
Py_DECREF(pScriptAdapterModule);
|
Py_DECREF(pScriptAdapterModule);
|
||||||
|
@ -214,7 +240,7 @@ PythonCPUPolicy::get_time_slice() const throw(UserInterruptException, MalformedP
|
||||||
// Parse return value stored in global Python object
|
// Parse return value stored in global Python object
|
||||||
retval = PyObject_CallMethod(_adapter, const_cast<char*>("get_return_value"), NULL);
|
retval = PyObject_CallMethod(_adapter, const_cast<char*>("get_return_value"), NULL);
|
||||||
assert(retval);
|
assert(retval);
|
||||||
long tmp = PyInt_AsLong(retval);
|
long tmp = PyLong_AsLong(retval);
|
||||||
Py_DECREF(retval);
|
Py_DECREF(retval);
|
||||||
|
|
||||||
set_callback_policy(NULL);
|
set_callback_policy(NULL);
|
||||||
|
@ -236,7 +262,7 @@ PythonCPUPolicy::wait_unlock() const throw(UserInterruptException, MalformedPoli
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Py_UNBLOCK_THREADS;
|
Py_UNBLOCK_THREADS;
|
||||||
Glib::usleep(wait_for); // hack'a'ton! magggggiccc nummmbeeerrrrrs!!
|
Glib::usleep(wait_for); // hack'a'ton! magggggiccc nummmbeeerrrrrs!!
|
||||||
Py_BLOCK_THREADS;
|
Py_BLOCK_THREADS;
|
||||||
|
|
||||||
PyObject* retval = PyObject_CallMethod(_adapter, const_cast<char*>("mutex_test_lock"), NULL);
|
PyObject* retval = PyObject_CallMethod(_adapter, const_cast<char*>("mutex_test_lock"), NULL);
|
||||||
|
@ -269,12 +295,8 @@ PythonCPUPolicy::wait_unlock() const throw(UserInterruptException, MalformedPoli
|
||||||
{
|
{
|
||||||
if(pException != Py_None)
|
if(pException != Py_None)
|
||||||
{
|
{
|
||||||
PyObject* pExceptStr = PyObject_Str(pException);
|
|
||||||
|
|
||||||
string msg = _("unhandled exception in user policy: ");
|
string msg = _("unhandled exception in user policy: ");
|
||||||
msg += PyString_AsString(pExceptStr);
|
msg += sgpem::PyString_AsString(pException);
|
||||||
|
|
||||||
Py_DECREF(pExceptStr);
|
|
||||||
Py_DECREF(pException);
|
Py_DECREF(pException);
|
||||||
|
|
||||||
throw MalformedPolicyException(msg);
|
throw MalformedPolicyException(msg);
|
||||||
|
@ -292,10 +314,10 @@ PythonCPUPolicy::wait_unlock() const throw(UserInterruptException, MalformedPoli
|
||||||
syncronized variable...
|
syncronized variable...
|
||||||
...if he has, break
|
...if he has, break
|
||||||
...else:
|
...else:
|
||||||
if the global lock is set:
|
if the global lock is set:
|
||||||
stay in this loop
|
stay in this loop
|
||||||
else:
|
else:
|
||||||
all's went okay, can exit loop
|
all's went okay, can exit loop
|
||||||
} */
|
} */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -316,11 +338,8 @@ PythonCPUPolicy::get_exception_information()
|
||||||
|
|
||||||
if (pValue != NULL)
|
if (pValue != NULL)
|
||||||
{
|
{
|
||||||
PyObject* pValueStr = PyObject_Str(pValue);
|
msg = sgpem::PyString_AsString(pValue) + "\n";
|
||||||
|
PyErr_PrintEx (false);
|
||||||
msg = PyString_AsString(pValueStr);
|
|
||||||
|
|
||||||
Py_DECREF(pValueStr);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
msg = string(_("no available information for this error"));
|
msg = string(_("no available information for this error"));
|
||||||
|
|
|
@ -70,8 +70,8 @@ PythonCPUPolicyManager::PythonCPUPolicyManager()
|
||||||
// environment variables.
|
// environment variables.
|
||||||
|
|
||||||
GlobalPreferences& prefs = GlobalPreferences::get_instance();
|
GlobalPreferences& prefs = GlobalPreferences::get_instance();
|
||||||
Glib::ustring importdirs = "import sys\n"
|
|
||||||
"sys.path[:0] = [ ";
|
Glib::ustring importdirs = "import sys; sys.path[:0] = [ ";
|
||||||
for_each(prefs.get_policy_dirs().begin(),
|
for_each(prefs.get_policy_dirs().begin(),
|
||||||
prefs.get_policy_dirs().end(),
|
prefs.get_policy_dirs().end(),
|
||||||
pol_dirs_concat(importdirs));
|
pol_dirs_concat(importdirs));
|
||||||
|
|
Loading…
Reference in New Issue