- Merged branch 0.3-r556--SPLIT_PYLOADER_CONFIG back into trunk

git-svn-id: svn://svn.gna.org/svn/sgpemv2/trunk@561 3ecf2c5c-341e-0410-92b4-d18e462d057c
This commit is contained in:
tchernobog 2006-04-06 19:01:13 +00:00
parent c6d4f5fd27
commit 51f0d7fbe7
36 changed files with 849 additions and 48 deletions

View file

@ -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)

View file

@ -1,178 +0,0 @@
from Abstract import *
import sgpem
## @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.
class Policy:
## @var Avoid instantiation of an abstract class.
# @see Abstract.Metaclass
__metaclass__ = Metaclass
## @brief Configure policy to initial values
#
# This is called just before a simulation starts, and is responsible
# to define the parameters the policy wants to expose to the user.
# For example, it may make the return value of is_preemptive configurable,
# or register an integer value for a the time slice duration.
#
# Should be implemented with signature:
# @code
# def configure(self):
# # function body
# @endcode
#
# @see sgpem::Policy::get_parameters()
configure = AbstractMethod('configure')
## @brief Sort ready processes queue
#
# This method is called by the scheduler at each
# step of the simulation to sort the ready
# processes queue.
#
# Should be implemented with signature:
# @code
# def sort_queue(self, event, queue):
# # function body
# @endcode
#
# @param event Enumeration value of type Scheduler::Event,
# needed by some policies to know the reason of
# the call
# @param queue The sgpem::SchedulableQueue to be sorted.
# Only some methods of it are implemented,
# notably get_item_at(position),
# swap(positionA, positionB) and size().
#
# @see Policy::Policy::sort()
sort_queue = AbstractMethod('sort_queue')
## @brief Returns whether the policy wants to be preemptive,
# other than by normal time slice termination
#
# See the return value for a complete explanation. Please
# note how the word ``priority'' here has a general meaning:
# it indicates every process than can bubble up the sorted
# ready queue and come before another. So it's up to
# Policy.sort_queue() to give it a precise meaning.
#
# Should be implemented with signature:
# @code
# def is_preemptive(self):
# # function body
# @endcode
#
# @return True If the policy declares it wants the running
# process to be released if a process at higher priority
# is put at the beginning of the ready processes queue
# @return False If the policy always waits the end of the time
# slice (or a process blocking/termination, of course) before
# selecting a new running process, even if it has greater priority
# than the current one
is_preemptive = AbstractMethod('is_preemptive')
## @brief Returns how long is a time-slice for this policy
#
# A time sliced policy should return a positive integer value,
# a policy which doesn't use slices should instead return -1.
# You're encouraged to use a user-configurable parameter via
# Policy.configure() if the policy is time-sliced, to ensure
# greater flexibility.
#
# Should be implemented with signature:
# @code
# def get_time_slice(self):
# # function body
# @endcode
#
# FIXME: what happens for ``return 0''? The same as ``return 1''?
#
# @return -1 If the policy doesn't want to use time slices
# @return 0+ To specify a time slice duration for this policy
get_time_slice = AbstractMethod('get_time_slice')
## @brief Returns the PolicyParameters instance you can use in
# Policy::Policy::configure()
#
# @return A sgpem::PolicyParameters instance
def get_parameters(self):
return sgpem.Scheduler.get_instance().get_policy().get_parameters()
## @brief This function implements an in-place stable sort
# using directly SchedulableQueue methods
#
# The compare parameter should be a user defined binary
# function returning either True or False, defined in one
# of the following ways:
# @code
# # As a lambda anonymous function (preferred)
# # (x and y are two SchedulableStatus objects)
# cmpf = lambda x,y: x.someProperty() < y.someProperty()
#
# # As a normal *global* function
# def compare(a,b):
# return a.someProperty < b.someProperty()
# cmpf = compare
# @endcode
#
# The call is then simply:
# @code
# def sort_queue() :
# # ...
# self.sort(queue, cmpf)
# @endcode
#
# @param self The object caller
# @param queue The SchedulableQueue to be sorted in place
# @param cmpf The binary function to use to compare elements
# @returns None
def sort(self, queue, cmpf):
self.__recursive_qsort(queue, 0, queue.size()-1, cmpf)
## @brief Recursive (private) call to perform quicksort on a
# queue
#
# @param queue The queue to sort
# @param a The initial element position of the slice
# @param b The final element position of the slice
# @param cmpf The user-defined compare function to employ
# @returns None
def __recursive_qsort(self, queue, a, b, cmpf):
if(b>a):
pivot = self.__partition(queue, a, b, cmpf)
self.__recursive_qsort(queue, a, pivot-1, cmpf)
self.__recursive_qsort(queue, pivot+1, b, cmpf)
## @brief Recursive (private) call to partition a slice of the queue
#
# This private function (the name mangling should work)
# naively sorts a partition of queue in place using just
# its methods.
#
# Feel the love.
#
# @param queue The SchedulableQueue to sort
# @param a The partition starting element position in the queue
# @param b The partition ending element position in the queue
# @param cmpf The binary function to use for comparing two elements
# @return The new pivot index
def __partition(self, queue, a, b, cmpf):
# takes pivot element:
right = queue.get_item_at(b)
i = a
for j in range(a,b): # goes from a to b-1
if cmpf(queue.get_item_at(j), right):
# the C++ code should do nothing if i == j:
queue.swap(i,j)
i = i+1
# puts pivot in place
queue.swap(i,b)
return i

View file

@ -1,109 +0,0 @@
import mutex, thread
import sgpem
## @brief This is an adapter class which acts as a proxy
# for user-implemented policies
#
# At runtime, this class will be initialized with the
# user-implemented policy, and then it will proxy the calls
# the policy member functions on a different thread, so
# to ensure asyncronous control.
#
# Instantiated in the C++ code, it is created like:
# @code
# adapter = ScriptAdapter(UserPolicyClass)
# @endcode
#
# The user shouldn't care about this class at all.
class ScriptAdapter :
## @var The policy this ScriptAdapter will use for calls
_policy = None
## @var The event to pass to Policy.sort_queue() after the asynchronous call
_event = None
## @var Synchronized return value you can read from C++
# when a threaded function returns
_ret_val = None
## Var Testable syncronization object
_g_mutex = mutex.mutex()
## @brief Constructor of ScriptAdapter
#
# @param self The caller object
# @param policy A user-implemented class inheriting from Policy.Policy
def __init__(self, policy):
self._policy = policy()
print 'ScriptAdapter for policy ', policy, ' loaded'
## @brief Asynchronously call Policy.configure()
#
# @param self The caller object
def async_configure(self):
self._g_mutex.lock(ScriptAdapter._wrap_configure, self )
def _wrap_configure(self):
thread.start_new_thread(ScriptAdapter._wrap_configure_callback, (self,))
def _wrap_configure_callback(self):
# call configure method
self._policy.configure()
self._g_mutex.unlock()
## @brief Asynchronously call Policy.sort_queue()
#
# The queue is asked directly to the C++ sgpem::Scheduler
# singleton, via SWIG
#
# @param self The caller object
# @param event The event to pass to sort_queue
def async_sort_queue(self, event):
self._event = event
self._g_mutex.lock(ScriptAdapter._wrap_sort_queue, self)
def _wrap_sort_queue(self):
thread.start_new_thread(ScriptAdapter._wrap_sort_queue_callback,
(self,self._event))
def _wrap_sort_queue_callback(self, event):
# here we retrieve and pass the ready queue
queue = sgpem.Scheduler.get_instance().get_ready_queue()
self._policy.sort_queue(event, queue)
self._g_mutex.unlock()
## @brief Asynchronously call Policy.is_preemptive()
#
# @param self The caller object
def async_is_preemptive(self):
self._g_mutex.lock(ScriptAdapter._wrap_is_preemptive, self)
def _wrap_is_preemptive(self):
thread.start_new_thread(ScriptAdapter._wrap_is_preemptive_callback, (self,))
def _wrap_is_preemptive_callback(self):
self._ret_val = self._policy.is_preemptive()
self._g_mutex.unlock()
## @brief Asynchronously call Policy.get_time_slice()
#
# @param self The caller object
def async_get_time_slice(self):
self._g_mutex.lock(ScriptAdapter._wrap_get_time_slice, self)
def _wrap_get_time_slice(self):
thread.start_new_thread(ScriptAdapter._wrap_get_time_slice_callback, (self,))
def _wrap_get_time_slice_callback(self):
self._ret_val = self._policy.get_time_slice()
self._g_mutex.unlock()
## @brief Return the global shared variable with the methods' last return value
def get_return_value(self):
return self._ret_val
def mutex_test_lock(self):
return self._g_mutex.test()

View file

@ -1,55 +0,0 @@
// src/backend/pyloader/hook.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
// The idea of this file is to provide a static function to execute
// when the plugin (this library) is loaded. Thus the name "hook".
// For the moment, instead of a function hook to be called by the
// libbackend.so module, we have a static PythonPolicyManager object.
// This is a risk.
#warning FIXME : this code is quite a bad idea. Replace me with \
a hookable structure, and execute a pointer to function stored \
therein. See "info libtool": "dlopened modules"
#include "python_policy_manager.hh"
#ifdef __cplusplus
extern "C" {
#endif
#define SG_CONSTRUCTOR __attribute__ ((constructor))
#define SG_DESTRUCTOR __attribute__ ((destructor))
#define _libpyloader_LTX__global_pm (_global_pm);
PolicyManager* _global_pm = NULL;
void SG_DLLEXPORT SG_CONSTRUCTOR hook_ctor(void)
{
_global_pm = PythonPolicyManager::get_instance();
}
void SG_DLLEXPORT SG_DESTRUCTOR hook_dtor(void)
{
delete _global_pm;
}
#ifdef __cplusplus
}
#endif

View file

@ -1,205 +0,0 @@
// 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 <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!
PythonPolicy::PythonPolicy(const char* name)
: _adapter(NULL), _adapter_dict(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
PyObject* pUserPolicyDict = PyModule_GetDict(pUserPolicyModule);
assert(pUserPolicyDict);
// Loads ScriptAdapter module and get its dictionary
pLoadmeStr = PyString_FromString("ScriptAdapter");
PyObject* pScriptAdapterModule = PyImport_Import(pLoadmeStr);
Py_DECREF(pLoadmeStr);
assert(pScriptAdapterModule);
_adapter_dict = PyModule_GetDict(pScriptAdapterModule);
assert(_adapter_dict);
// We want to keep a reference to it
Py_INCREF(_adapter_dict);
// Now takes the user-defined policy class from pUserPolicyDict
PyObject* pPolicyClass = PyDict_GetItemString(pUserPolicyDict, 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(_adapter_dict, "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(pUserPolicyModule);
Py_DECREF(pScriptAdapterModule);
// And now, who's your daddy, huh?
}
PythonPolicy::~PythonPolicy()
{
if(_adapter) Py_DECREF(_adapter);
if(_adapter_dict) Py_DECREF(_adapter_dict);
}
void
PythonPolicy::configure() throw(UserInterruptException)
{
PyObject* retval = PyObject_CallMethod(_adapter, "async_configure", NULL);
Py_DECREF(retval);
wait_unlock();
}
void
PythonPolicy::sort_queue(Scheduler::event event) const throw(UserInterruptException)
{
PyObject* pEvent = PyInt_FromLong(event);
PyObject* pMethodName = PyString_FromString("async_sort_queue");
PyObject* retval = PyObject_CallMethodObjArgs(_adapter, pMethodName, pEvent, NULL);
// Do minimal debugging
if(!retval) PyErr_Print();
else Py_DECREF(retval);
Py_DECREF(pMethodName);
Py_DECREF(pEvent);
wait_unlock();
}
Glib::ustring
PythonPolicy::get_description() 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);
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
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!!
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);
PyEval_RestoreThread(_save);
//Py_UNBLOCK_THREADS;
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
} */
}

View file

@ -1,92 +0,0 @@
// src/backend/pyloader/python_policy.hh - 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
#ifndef PYTHON_POLICY_HH
#define PYTHON_POLICY_HH 1
#include "config.h"
#include <Python.h>
#include <glibmm/ustring.h>
#include <iostream>
#include "../policy.hh"
#include "../user_interrupt_exception.hh"
namespace sgpem
{
class PythonPolicy;
class PythonPolicyManager;
class UserInterruptException;
/** \brief A specialization of abstract class Policy
This class represents a policy written in Python. Its methods interact with Python interpreter.
See the documentation of class Policy for more detailed informations.
*/
class SG_DLLEXPORT PythonPolicy : public Policy
{
public:
PythonPolicy(const char* name);
virtual ~PythonPolicy();
/**
Calls the method \c async_configure
*/
void configure() throw(UserInterruptException);
/**
Calls the method \c async_sort_queue
*/
void sort_queue(Scheduler::event) const throw(UserInterruptException);
/**
\returns A textual description of this policy.
*/
Glib::ustring get_description() const;
/**
\returns \c TRUE if the policy is preemptive.
\returns \c FALSE if the policy is not preemptive.
*/
bool is_pre_emptive() const throw(UserInterruptException);
/**
\returns The integer value of its time-slice.
*/
int get_time_slice() const throw(UserInterruptException);
private:
PythonPolicy(const PythonPolicy&);
PythonPolicy& operator=(const PythonPolicy&);
void wait_unlock() const throw(UserInterruptException);
PyObject* _adapter;
PyObject* _adapter_dict;
Glib::ustring _name;
};
}
#endif

View file

@ -1,115 +0,0 @@
// src/backend/pyloader/python_policy_manager.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_manager.hh"
#include "../global_settings.hh"
#include <Python.h>
#include <glibmm/ustring.h>
#include <glibmm/timer.h>
#include <algorithm>
#include <cassert>
#include <functional>
#include <iostream>
#include <string>
#include <unistd.h>
using namespace sgpem;
// Concatenate a string with all the policies directories
struct pol_dirs_concat : public std::unary_function<void, const Glib::ustring&>
{
public:
pol_dirs_concat(Glib::ustring& cat) : _cat(cat) {}
void operator()(const Glib::ustring& add)
{
// Please note that this string will end finishing with
// and additional ","!
_cat += "'" + add + "', ";
}
private:
Glib::ustring& _cat;
};
//static object
PythonPolicyManager* PythonPolicyManager::_instance = NULL;
PythonPolicyManager::PythonPolicyManager()
: _initialized(false)
{
PyEval_InitThreads();
}
PythonPolicyManager* const
PythonPolicyManager::get_instance()
{
if(!_instance)
_instance = new PythonPolicyManager();
return _instance;
}
Policy&
PythonPolicyManager::get_policy()
{
// FIXME : assumes that _python_policy is always != NULL!
return *_python_policy;
}
void
PythonPolicyManager::init()
{
if(_initialized)
// No-op
return;
Py_Initialize();
_initialized = true;
// The following lines are ugly, but necessary if we use
// non-standard installation directories. Theoretically,
// it should be up to the user to set correct
// environment variables.
// FIXME: find better way to achieve this.
Glib::ustring importdirs = "import sys\n"
"sys.path[:0] = [ ";
for_each(GlobalSettings::instance().policies_dir_begin(),
GlobalSettings::instance().policies_dir_end(),
pol_dirs_concat(importdirs));
importdirs += " '" MODDIR "' ]\n";
PyRun_SimpleString(importdirs.c_str());
// Okay, here we go.
// Black magic at work.
// FIXME : Hardcoded policy name
char* policy_name = "fcfs";
//char* policy_name = "sjf";
_python_policy = std::auto_ptr<PythonPolicy>(new PythonPolicy(policy_name));
}

View file

@ -1,88 +0,0 @@
// src/backend/pyloader/python_policy_manager.hh - 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
#ifndef PYTHON_POLICY_MANAGER_HH
#define PYTHON_POLICY_MANAGER_HH 1
#include "config.h"
#include <Python.h>
#include "../policy_manager.hh"
#include "python_policy.hh"
namespace sgpem
{
//class PolicyManager;
class PythonPolicyManager;
/** \brief Manages Python user-implemented policies
*
* This singleton manages the creation and destruction
* of a Python policy.
*/
class SG_DLLEXPORT PythonPolicyManager : public PolicyManager
{
public:
/** \brief Returns a reference to the active policy.
*
* For the moment, it will sufficit to keep and return
* just one Policy for PolicyManager.
* In the next milestones it will be possible to manage
* more than one, and to retrieve the correct Policy by
* passing a unique ID.
*/
Policy& get_policy();
/** \brief Initialize the Python interpreter.
*
* If the interpreter has already been initialized, it terminates it, cleanups old policies,
* and restarts it.
*/
void init();
/** \brief Returns the singleton instance of
* PythonPolicyManager.
*
* Please note that the first time you'll request
* it, it will be still uninitialized.
* @see init()
*/
static PythonPolicyManager* const get_instance();
protected:
/** The selected and active PyhonPolicy object. */
PythonPolicyManager();
std::auto_ptr<PythonPolicy> _python_policy;
private:
PythonPolicyManager(const PythonPolicyManager&);
PythonPolicyManager& operator=(const PythonPolicyManager&);
/** Singleton support. */
static PythonPolicyManager* _instance;
bool _initialized;
};
}
#endif

View file

@ -1,195 +0,0 @@
%module sgpem
%{
#include "policy.hh"
#include "policy_parameters.hh"
#include "schedulable.hh"
#include "schedulable_list.hh"
#include "schedulable_status.hh"
#include "scheduler.hh"
%}
/* NOTE : passing Unicode strings to C++ methods calling them
* from Python results in a SIGSEGV. You've been warned!
* (Investigate if this can be fixed, else please report it in
* the sgpem user manual)
*/
/** Due to the relatively new support for namespaces in SWIG,
* make sure to include the full visibility signature when
* returning / passing parameters from / to functions with
* objects different to the one you're declaring.
*/
namespace std {
class exception {
public:
virtual const char* what() const throw();
private:
exception();
};
class runtime_error : public std::exception {
public:
virtual const char* what() const throw();
private:
runtime_error();
};
}
namespace sgpem {
class Policy {
public:
virtual ~Policy() = 0;
sgpem::PolicyParameters& get_parameters();
};
// --------------------------------------------
class PolicyParametersException : public std::runtime_error {
public:
PolicyParametersException(char* msg);
%rename (__str__) what;
virtual const char* what();
}; //~ class PolicyParametersException
// --------------------------------------------
class PolicyParameters
{
public:
//methods to CREATE PARAMETERS
// (rewrapped correctly for SWIG usage)
%ignore register_int(const Glib::ustring&, const int&,
const int&, const bool&, const int&);
%ignore register_float(const Glib::ustring&, const float&,
const float&, const bool&, const float&);
%ignore register_string(const Glib::ustring&, const bool&,
const char*);
%extend {
void register_int(const char* name,
const int& lower_bound,
const int& upper_bound,
const bool& required,
const int& default_value = 0)
{
self->register_int(name, lower_bound, upper_bound,
required, default_value);
}
void register_float(const char* name,
const float& lower_bound,
const float& upper_bound,
const bool& required,
const float& default_value = 0.0f)
{
self->register_float(name, lower_bound, upper_bound,
required, default_value);
}
void register_string(const char* name,
const bool& required,
const char* default_value = "")
{
self->register_string(name, required, default_value);
}
}
//methods to SET the VALUE of PARAMETERS
// (rewrapped correctly for SWIG usage)
%ignore set_int(const Glib::ustring&, const int&);
%ignore set_float(const Glib::ustring&, const float&);
%ignore set_string(const Glib::ustring&, const Glib::ustring&);
%extend {
bool set_int(const char* name, const int& value)
{ return self->set_int(name, value); }
bool set_float(const char* name, const float& value)
{ return self->set_float(name, value); }
bool set_string(const char* name, const char* value)
{ return self->set_string(name, value); }
}
//methods to GET the VALUE of PARAMETERS
// (rewrapped correctly for SWIG usage)
%ignore get_int(const Glib::ustring&) const;
%ignore get_float(const Glib::ustring&) const;
%ignore get_string(const Glib::ustring&) const;
%extend {
int get_int(const char* name) const
{ return self->get_int(name); }
float get_float(const char* name) const
{ return self->get_float(name); }
const char* get_string(const char* name) const
{ return self->get_string(name).c_str(); }
}
}; //~ class PolicyParameters
// --------------------------------------------
class Schedulable
{
public:
virtual ~Schedulable() = 0;
virtual unsigned int get_arrival_time() const;
int get_priority() const;
unsigned int get_total_cpu_time() const;
%ignore Schedulable::get_name() const;
%extend {
const char* get_name() const
{ return self->get_name().c_str(); }
}
}; //~ class Schedulable
// --------------------------------------------
class SchedulableList
{
public:
unsigned int size() const;
const sgpem::SchedulableStatus* get_item_at(const unsigned int&) const;
void swap(unsigned int positionA, unsigned int positionB) throw();
private:
// Avoid instantiation and copy
SchedulableList();
SchedulableList(const SchedulableList&);
SchedulableList& operator=(const SchedulableList&);
~SchedulableList();
}; //~ class Schedulable
// ---------------------------------------------
class SchedulableStatus
{
public:
enum state
{
state_running = 1<<0,
state_ready = 1<<1,
state_blocked = 1<<2,
state_future = 1<<3,
state_terminated = 1<<4
};
SchedulableStatus(const SchedulableStatus& obj);
int get_cpu_time_left() const;
int get_last_scheduled() const;
state get_state() const;
const sgpem::Schedulable* get_schedulable() const;
};
// ---------------------------------------------
class Scheduler {
public:
sgpem::Policy& get_policy();
static sgpem::Scheduler& get_instance();
sgpem::SchedulableList* get_ready_queue();
private:
Scheduler();
~Scheduler();
};
} //~ namespace sgpem

View file

@ -1,42 +0,0 @@
# src/builtin-policies/fcfs.py - 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
from Policy import Policy
import sys
class fcfs(Policy) :
def __init__(self):
pass;
def configure(self):
print 'No options to configure for fcfs'
def is_preemptive(self):
return False
def get_time_slice(self):
return -2
def sort_queue(self, event, queue):
cmpf = lambda a, b: \
a.get_schedulable().get_arrival_time() < \
b.get_schedulable().get_arrival_time()
self.sort(queue,cmpf)

View file

@ -1,42 +0,0 @@
# src/builtin-policies/sjf.py - 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
from Policy import Policy
import sys
class sjf(Policy) :
def __init__(self):
pass;
def configure(self):
print 'No options to configure for fcfs'
def is_preemptive(self):
return False
def get_time_slice(self):
return -1
def sort_queue(self, event, queue):
cmpf = lambda a, b: \
a.get_cpu_time_left() < \
b.get_cpu_time_left()
self.sort(queue,cmpf)

View file

@ -1,20 +0,0 @@
from Policy import Policy
import sys
class python_loader_configure(Policy) :
def __init__(self):
pass;
def configure(self):
print "[II] Entering willingly an endless loop."
while True:
pass
def is_preemptive(self):
return False
def get_time_slice(self):
return -1
def sort_queue(self, event, queue):
pass

View file

@ -1,21 +0,0 @@
from Policy import Policy
import sys
class python_loader_get_time_slice(Policy) :
def __init__(self):
pass
def configure(self):
pass
def is_preemptive(self):
return False
def get_time_slice(self):
print "[II] Entering willingly an endless loop."
while True:
pass
return -1
def sort_queue(self, event, queue):
pass

View file

@ -1,21 +0,0 @@
from Policy import Policy
import sys
class python_loader_is_preemptive(Policy) :
def __init__(self):
pass
def configure(self):
pass
def is_preemptive(self):
print "[II] Entering willingly an endless loop."
while True:
pass
return False
def get_time_slice(self):
return -1
def sort_queue(self, event, queue):
pass

View file

@ -1,20 +0,0 @@
from Policy import Policy
import sys
class python_loader_sort_queue(Policy) :
def __init__(self):
pass
def configure(self):
pass
def is_preemptive(self):
return False
def get_time_slice(self):
return -1
def sort_queue(self, event, queue):
print "[II] Entering willingly an endless loop."
while True:
pass

View file

@ -1,113 +0,0 @@
// src/testsuite/test-python_loader.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
/* This executable tests for workingness of the PythonPolicyManager
* class and its closely related cousins. More documentation to be written
* here, thanks very much. */
#include "backend/pyloader/python_policy_manager.hh"
#include "backend/pyloader/python_policy.hh"
#include "backend/global_settings.hh"
#include "backend/schedulable_list.hh"
#include "backend/scheduler.hh"
#include "backend/user_interrupt_exception.hh"
#include "templates/smartp.hh"
#include <Python.h>
#include <glibmm/module.h>
#include <cassert>
#include <iostream>
#include <string>
// FIXME: Eeeeh? Why does this work without explicit namespace resolving?
// Is there some using declaration in included HEADERS?? Aaaaagh!
class TestPythonPolicyManager : public PythonPolicyManager {
public:
void test_init(const char* policy_name) {
init();
_python_policy = std::auto_ptr<PythonPolicy>(new PythonPolicy(policy_name));
}
};
int
main(int argc, char** argv) {
using namespace sgpem;
using namespace std;
if(argc != 2) {
std::cout << "[EE] Usage:\n\t" << argv[0] <<
" path/to/uninstalled/policies" << std::endl;
exit(-1);
}
else
// Add argv[1] as the directory to search for uninstalled policies
sgpem::GlobalSettings::instance().add_policies_dir(argv[1]);
// Self-register itself to Scheduler, however we don't care about it
TestPythonPolicyManager polman;
try
{
polman.test_init("python_loader_configure");
polman.get_policy().configure();
}
catch(UserInterruptException e)
{
cout << "configure: Caught UserInterruptException" << endl;
}
try
{
polman.test_init("python_loader_is_preemptive");
polman.get_policy().is_pre_emptive();
}
catch(UserInterruptException e)
{
cout << "is_preemptive: Caught UserInterruptException" << endl;
}
try
{
polman.test_init("python_loader_get_time_slice");
polman.get_policy().get_time_slice();
}
catch(UserInterruptException e)
{
cout << "get_time_slice: Caught UserInterruptException" << endl;
}
try
{
SchedulableList sl;
polman.test_init("python_loader_sort_queue");
polman.get_policy().sort_queue(Scheduler::event_schedulable_arrival);
}
catch(UserInterruptException e)
{
cout << "sort_queue: Caught UserInterruptException" << endl;
}
exit(0);
}