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 CPUPolicy: ## @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, queue): # # function body # @endcode # # @param queue The sgpem::ReadyQueue 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.CPUPolicy.callback_get_policy().get_parameters() ## @brief This function implements an in-place stable sort # using directly ReadyQueue 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 DynamicSchedulable 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 # # Since queue.sort() uses a in-place version of the # quicksort algorithm, note the effect of using "<" # instead than "<=": quicksort wouldn't be stable anymore. # You have been warned. If your policy behaves strangely, # this may be the cause. # # @param self The object caller # @param queue The ReadyQueue 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 ReadyQueue 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