diff options
author | Ori Bernstein <ori@eigenstate.org> | 2021-06-14 00:00:37 +0000 |
---|---|---|
committer | Ori Bernstein <ori@eigenstate.org> | 2021-06-14 00:00:37 +0000 |
commit | a73a964e51247ed169d322c725a3a18859f109a3 (patch) | |
tree | 3f752d117274d444bda44e85609aeac1acf313f3 /sys/src/cmd/python/Demo/threads/Coroutine.py | |
parent | e64efe273fcb921a61bf27d33b230c4e64fcd425 (diff) |
python, hg: tow outside the environment.
they've served us well, and can ride off into the sunset.
Diffstat (limited to 'sys/src/cmd/python/Demo/threads/Coroutine.py')
-rw-r--r-- | sys/src/cmd/python/Demo/threads/Coroutine.py | 159 |
1 files changed, 0 insertions, 159 deletions
diff --git a/sys/src/cmd/python/Demo/threads/Coroutine.py b/sys/src/cmd/python/Demo/threads/Coroutine.py deleted file mode 100644 index 4cc65f7bf..000000000 --- a/sys/src/cmd/python/Demo/threads/Coroutine.py +++ /dev/null @@ -1,159 +0,0 @@ -# Coroutine implementation using Python threads. -# -# Combines ideas from Guido's Generator module, and from the coroutine -# features of Icon and Simula 67. -# -# To run a collection of functions as coroutines, you need to create -# a Coroutine object to control them: -# co = Coroutine() -# and then 'create' a subsidiary object for each function in the -# collection: -# cof1 = co.create(f1 [, arg1, arg2, ...]) # [] means optional, -# cof2 = co.create(f2 [, arg1, arg2, ...]) #... not list -# cof3 = co.create(f3 [, arg1, arg2, ...]) -# etc. The functions need not be distinct; 'create'ing the same -# function multiple times gives you independent instances of the -# function. -# -# To start the coroutines running, use co.tran on one of the create'd -# functions; e.g., co.tran(cof2). The routine that first executes -# co.tran is called the "main coroutine". It's special in several -# respects: it existed before you created the Coroutine object; if any of -# the create'd coroutines exits (does a return, or suffers an unhandled -# exception), EarlyExit error is raised in the main coroutine; and the -# co.detach() method transfers control directly to the main coroutine -# (you can't use co.tran() for this because the main coroutine doesn't -# have a name ...). -# -# Coroutine objects support these methods: -# -# handle = .create(func [, arg1, arg2, ...]) -# Creates a coroutine for an invocation of func(arg1, arg2, ...), -# and returns a handle ("name") for the coroutine so created. The -# handle can be used as the target in a subsequent .tran(). -# -# .tran(target, data=None) -# Transfer control to the create'd coroutine "target", optionally -# passing it an arbitrary piece of data. To the coroutine A that does -# the .tran, .tran acts like an ordinary function call: another -# coroutine B can .tran back to it later, and if it does A's .tran -# returns the 'data' argument passed to B's tran. E.g., -# -# in coroutine coA in coroutine coC in coroutine coB -# x = co.tran(coC) co.tran(coB) co.tran(coA,12) -# print x # 12 -# -# The data-passing feature is taken from Icon, and greatly cuts -# the need to use global variables for inter-coroutine communication. -# -# .back( data=None ) -# The same as .tran(invoker, data=None), where 'invoker' is the -# coroutine that most recently .tran'ed control to the coroutine -# doing the .back. This is akin to Icon's "&source". -# -# .detach( data=None ) -# The same as .tran(main, data=None), where 'main' is the -# (unnameable!) coroutine that started it all. 'main' has all the -# rights of any other coroutine: upon receiving control, it can -# .tran to an arbitrary coroutine of its choosing, go .back to -# the .detach'er, or .kill the whole thing. -# -# .kill() -# Destroy all the coroutines, and return control to the main -# coroutine. None of the create'ed coroutines can be resumed after a -# .kill(). An EarlyExit exception does a .kill() automatically. It's -# a good idea to .kill() coroutines you're done with, since the -# current implementation consumes a thread for each coroutine that -# may be resumed. - -import thread -import sync - -class _CoEvent: - def __init__(self, func): - self.f = func - self.e = sync.event() - - def __repr__(self): - if self.f is None: - return 'main coroutine' - else: - return 'coroutine for func ' + self.f.func_name - - def __hash__(self): - return id(self) - - def __cmp__(x,y): - return cmp(id(x), id(y)) - - def resume(self): - self.e.post() - - def wait(self): - self.e.wait() - self.e.clear() - -Killed = 'Coroutine.Killed' -EarlyExit = 'Coroutine.EarlyExit' - -class Coroutine: - def __init__(self): - self.active = self.main = _CoEvent(None) - self.invokedby = {self.main: None} - self.killed = 0 - self.value = None - self.terminated_by = None - - def create(self, func, *args): - me = _CoEvent(func) - self.invokedby[me] = None - thread.start_new_thread(self._start, (me,) + args) - return me - - def _start(self, me, *args): - me.wait() - if not self.killed: - try: - try: - apply(me.f, args) - except Killed: - pass - finally: - if not self.killed: - self.terminated_by = me - self.kill() - - def kill(self): - if self.killed: - raise TypeError, 'kill() called on dead coroutines' - self.killed = 1 - for coroutine in self.invokedby.keys(): - coroutine.resume() - - def back(self, data=None): - return self.tran( self.invokedby[self.active], data ) - - def detach(self, data=None): - return self.tran( self.main, data ) - - def tran(self, target, data=None): - if not self.invokedby.has_key(target): - raise TypeError, '.tran target %r is not an active coroutine' % (target,) - if self.killed: - raise TypeError, '.tran target %r is killed' % (target,) - self.value = data - me = self.active - self.invokedby[target] = me - self.active = target - target.resume() - - me.wait() - if self.killed: - if self.main is not me: - raise Killed - if self.terminated_by is not None: - raise EarlyExit, '%r terminated early' % (self.terminated_by,) - - return self.value - -# end of module |