class StackletLanguageRunner(AbstractLanguageRunner): sthread = None def __init__(self, language_process): AbstractLanguageRunner.__init__(self, language_process) self.sthread = StackletThread() global_execution_state.origin = self # there can only be one valid handle at a time (main or foreign thread) self.handle = self.sthread.new(self.__class__.new_stacklet_callback) def resumable(self): return self._has_valid_handle() def _resume_thread(self): self._switch_to_handle() def _yield_thread(self): self._switch_to_handle() def _switch_to_handle(self): if not self._has_valid_handle(): print 'handle not valid: %s' % self.handle return self.handle = self.sthread.switch(self.handle) if self.handle is self.sthread.get_null_handle(): log('language_process thread has finished (handle is null)') if self.sthread.is_empty_handle(self.handle): log('language_process thread has finished (handle is empty)') def _has_valid_handle(self): # TODO: make less verbose when this proved to work if not bool(self.handle): print 'handle evaluates to False: %s' % self.handle return False if self.sthread.is_empty_handle(self.handle): print 'handle is empty: %s' % self.handle return False if self.handle is self.sthread.get_null_handle(): print 'handle is null handle: %s' % self.handle return False return True @staticmethod def new_stacklet_callback(h, arg): log('new_stacklet_callback: %s' % h) self = global_execution_state.origin self.handle = h global_execution_state.clear() # stacklets start immediate, so yield back before executing any code, # code is only executed when the resume primitive is used, # eval primitive only creates a new language process self.return_to_smalltalk() self.language_process().safe_run() global_execution_state.origin = self return self.handle # return to Smalltalk when done
class ProcessState: stacklet = None current = None def init(self, config): self.stacklet = StackletThread(config) self.current = Greenlet( self.stacklet.get_null_handle(), True)