diff --git a/src/backend/pyloader/Policy.py b/src/backend/pyloader/Policy.py index f9f7a7e..05e5baa 100644 --- a/src/backend/pyloader/Policy.py +++ b/src/backend/pyloader/Policy.py @@ -3,28 +3,123 @@ from Abstract import * ## @brief This is the abstract class a user-defined policy # should inherit from # -# This class also exposes the method sort, which can be +# This class also exposes the method sort(), which can be # used to easily sort the queue of ready process with a -# given compare function +# user-defined given compare function. class Policy: - ## @var Avoid instantiation of an abstract class + ## @var Avoid instantiation of an abstract class. + # @see Abstract.Metaclass __metaclass__ = Metaclass - - configure = AbstractMethod('configure') - sort_queue = AbstractMethod('sort_queue') - is_preemptive = AbstractMethod('is_preemptive') - get_time_slice = AbstractMethod('get_time_slice') - - ## @brief this function implements a quicksort in place - # using the SchedulableQueue methods + + ## @brief Configure policy to initial values # - # The compare parameter should be a user defined function - # name returning either True or False, defined like: + # 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. + # + # @warning How do the user access get_parameters()? + # + # Should be implemented with signature: # @code - # def compare(SchedulableA,SchedulableB): - # return SchedulableA.someProperty() < SchedulableB.someProperty() + # 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.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 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) + # 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 diff --git a/src/backend/pyloader/ScriptAdapter.py b/src/backend/pyloader/ScriptAdapter.py index 2d2e727..9dd590a 100644 --- a/src/backend/pyloader/ScriptAdapter.py +++ b/src/backend/pyloader/ScriptAdapter.py @@ -1,9 +1,10 @@ import mutex, thread import sgpem +## Var Global syncronization object _g_mutex = mutex.mutex() -## @val Synchronized return value you can read from C++ +## @var Synchronized return value you can read from C++ # when a threaded function returns _ret_val = None @@ -15,18 +16,32 @@ _ret_val = None # the policy member functions on a different thread, so # to ensure asyncronous control. # -# Instantiated in the C++ code, it should be instantiated like: +# 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 - + + + ## @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): _g_mutex.lock(ScriptAdapter._wrap_configure, self ) @@ -37,7 +52,15 @@ class ScriptAdapter : # call configure method self._policy.configure() _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 _g_mutex.lock(ScriptAdapter._wrap_sort_queue, self) @@ -52,6 +75,10 @@ class ScriptAdapter : self._policy.sort_queue(event, queue) _g_mutex.unlock() + + ## @brief Asynchronously call Policy.is_preemptive() + # + # @param self The caller object def async_is_preemptive(self): _g_mutex.lock(ScriptAdapter._wrap_is_preemptive, self) @@ -61,7 +88,11 @@ class ScriptAdapter : def _wrap_is_preemptive_callback(self): _ret_val = self._policy.is_preemptive() _g_mutex.unlock() + + ## @brief Asynchronously call Policy.get_time_slice() + # + # @param self The caller object def async_get_time_slice(self): _g_mutex.lock(ScriptAdapter._wrap_get_time_slice, self) diff --git a/src/backend/pyloader/python_policy_manager.hh b/src/backend/pyloader/python_policy_manager.hh index 26b72d4..7090481 100644 --- a/src/backend/pyloader/python_policy_manager.hh +++ b/src/backend/pyloader/python_policy_manager.hh @@ -32,14 +32,39 @@ 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: + 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(); - PyObject* get_py_dict(); - + + /** \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(); private: @@ -47,7 +72,10 @@ namespace sgpem PythonPolicyManager(const PythonPolicyManager&); PythonPolicyManager& operator=(const PythonPolicyManager&); + /** Singleton support. */ static PythonPolicyManager* _instance; + + /** The selected and active PyhonPolicy object. */ std::auto_ptr _python_policy; bool _initialized; diff --git a/src/builtin-policies/fcfs.py b/src/builtin-policies/fcfs.py index 36fc24a..a39f7d1 100644 --- a/src/builtin-policies/fcfs.py +++ b/src/builtin-policies/fcfs.py @@ -16,18 +16,18 @@ class fcfs(Policy) : def sort_queue(self, event, queue): print 'Entering sort_queue' print queue.size() + print queue.get_item_at(0) print dir(queue.get_item_at(0)) for i in range(0, queue.size()): ss = queue.get_item_at(i) print ss.get_schedulable().get_name() - cmpf = lambda a, b: \ - a.get_schedulable().get_arrival_time() < \ - b.get_schedulable().get_arrival_time() - try: - self.sort(queue,cmpf) - except: - print "Unexpected error:", sys.exc_info()[0] - raise - for i in range(0, queue.size()): - ss = queue.get_item_at(i) - print ss.get_schedulable().get_name() + # Uncomment this to try the qsort algorithm with FCFS + #cmpf = lambda a, b: \ + # a.get_schedulable().get_arrival_time() < \ + # b.get_schedulable().get_arrival_time() + #try: + # self.sort(queue,cmpf) + #except: + # print "Unexpected error:", sys.exc_info()[0] + # raise +